diff -Nur linux.org/Documentation/networking/wanpipe.txt linux-2.6.17/Documentation/networking/wanpipe.txt --- linux.org/Documentation/networking/wanpipe.txt 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/Documentation/networking/wanpipe.txt 2006-08-30 10:07:14.000000000 +0000 @@ -0,0 +1,13 @@ +------------------------------------------------------------------------------ +Linux WAN Router Utilities Package +------------------------------------------------------------------------------ +Version beta5-2.3.4 +Jul 20 2006 +Author: Nenad Corbic +Copyright (c) 1995-2006 Sangoma Technologies Inc. +------------------------------------------------------------------------------ + +For latest docs please visit Sangoma Wiki +Sangoma Wiki: http://wiki.sangoma.com +------------------------------------------------------------------------------ + diff -Nur linux.org/Documentation/networking/wan-router.txt linux-2.6.17/Documentation/networking/wan-router.txt --- linux.org/Documentation/networking/wan-router.txt 2006-06-18 01:49:35.000000000 +0000 +++ linux-2.6.17/Documentation/networking/wan-router.txt 2006-08-30 10:07:14.000000000 +0000 @@ -1,622 +1,13 @@ ------------------------------------------------------------------------------ Linux WAN Router Utilities Package ------------------------------------------------------------------------------ -Version 2.2.1 -Mar 28, 2001 +Version beta5-2.3.4 +Jul 20 2006 Author: Nenad Corbic -Copyright (c) 1995-2001 Sangoma Technologies Inc. +Copyright (c) 1995-2006 Sangoma Technologies Inc. ------------------------------------------------------------------------------ -INTRODUCTION - -Wide Area Networks (WANs) are used to interconnect Local Area Networks (LANs) -and/or stand-alone hosts over vast distances with data transfer rates -significantly higher than those achievable with commonly used dial-up -connections. - -Usually an external device called `WAN router' sitting on your local network -or connected to your machine's serial port provides physical connection to -WAN. Although router's job may be as simple as taking your local network -traffic, converting it to WAN format and piping it through the WAN link, these -devices are notoriously expensive, with prices as much as 2 - 5 times higher -then the price of a typical PC box. - -Alternatively, considering robustness and multitasking capabilities of Linux, -an internal router can be built (most routers use some sort of stripped down -Unix-like operating system anyway). With a number of relatively inexpensive WAN -interface cards available on the market, a perfectly usable router can be -built for less than half a price of an external router. Yet a Linux box -acting as a router can still be used for other purposes, such as fire-walling, -running FTP, WWW or DNS server, etc. - -This kernel module introduces the notion of a WAN Link Driver (WLD) to Linux -operating system and provides generic hardware-independent services for such -drivers. Why can existing Linux network device interface not be used for -this purpose? Well, it can. However, there are a few key differences between -a typical network interface (e.g. Ethernet) and a WAN link. - -Many WAN protocols, such as X.25 and frame relay, allow for multiple logical -connections (known as `virtual circuits' in X.25 terminology) over a single -physical link. Each such virtual circuit may (and almost always does) lead -to a different geographical location and, therefore, different network. As a -result, it is the virtual circuit, not the physical link, that represents a -route and, therefore, a network interface in Linux terms. - -To further complicate things, virtual circuits are usually volatile in nature -(excluding so called `permanent' virtual circuits or PVCs). With almost no -time required to set up and tear down a virtual circuit, it is highly desirable -to implement on-demand connections in order to minimize network charges. So -unlike a typical network driver, the WAN driver must be able to handle multiple -network interfaces and cope as multiple virtual circuits come into existence -and go away dynamically. - -Last, but not least, WAN configuration is much more complex than that of say -Ethernet and may well amount to several dozens of parameters. Some of them -are "link-wide" while others are virtual circuit-specific. The same holds -true for WAN statistics which is by far more extensive and extremely useful -when troubleshooting WAN connections. Extending the ifconfig utility to suit -these needs may be possible, but does not seem quite reasonable. Therefore, a -WAN configuration utility and corresponding application programmer's interface -is needed for this purpose. - -Most of these problems are taken care of by this module. Its goal is to -provide a user with more-or-less standard look and feel for all WAN devices and -assist a WAN device driver writer by providing common services, such as: - - o User-level interface via /proc file system - o Centralized configuration - o Device management (setup, shutdown, etc.) - o Network interface management (dynamic creation/destruction) - o Protocol encapsulation/decapsulation - -To ba able to use the Linux WAN Router you will also need a WAN Tools package -available from - - ftp.sangoma.com/pub/linux/current_wanpipe/wanpipe-X.Y.Z.tgz - -where vX.Y.Z represent the wanpipe version number. - -For technical questions and/or comments please e-mail to ncorbic@sangoma.com. -For general inquiries please contact Sangoma Technologies Inc. by - - Hotline: 1-800-388-2475 (USA and Canada, toll free) - Phone: (905) 474-1990 ext: 106 - Fax: (905) 474-9223 - E-mail: dm@sangoma.com (David Mandelstam) - WWW: http://www.sangoma.com - - -INSTALLATION - -Please read the WanpipeForLinux.pdf manual on how to -install the WANPIPE tools and drivers properly. - - -After installing wanpipe package: /usr/local/wanrouter/doc. -On the ftp.sangoma.com : /linux/current_wanpipe/doc - - -COPYRIGHT AND LICENSING INFORMATION - -This program is free software; you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free Software -Foundation; either version 2, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along with -this program; if not, write to the Free Software Foundation, Inc., 675 Mass -Ave, Cambridge, MA 02139, USA. - - - -ACKNOWLEDGEMENTS - -This product is based on the WANPIPE(tm) Multiprotocol WAN Router developed -by Sangoma Technologies Inc. for Linux 2.0.x and 2.2.x. Success of the WANPIPE -together with the next major release of Linux kernel in summer 1996 commanded -adequate changes to the WANPIPE code to take full advantage of new Linux -features. - -Instead of continuing developing proprietary interface tied to Sangoma WAN -cards, we decided to separate all hardware-independent code into a separate -module and defined two levels of interfaces - one for user-level applications -and another for kernel-level WAN drivers. WANPIPE is now implemented as a -WAN driver compliant with the WAN Link Driver interface. Also a general -purpose WAN configuration utility and a set of shell scripts was developed to -support WAN router at the user level. - -Many useful ideas concerning hardware-independent interface implementation -were given by Mike McLagan and his implementation -of the Frame Relay router and drivers for Sangoma cards (dlci/sdla). - -With the new implementation of the APIs being incorporated into the WANPIPE, -a special thank goes to Alan Cox in providing insight into BSD sockets. - -Special thanks to all the WANPIPE users who performed field-testing, reported -bugs and made valuable comments and suggestions that help us to improve this -product. - - - -NEW IN THIS RELEASE - - o Updated the WANCFG utility - Calls the pppconfig to configure the PPPD - for async connections. - - o Added the PPPCONFIG utility - Used to configure the PPPD dameon for the - WANPIPE Async PPP and standard serial port. - The wancfg calls the pppconfig to configure - the pppd. - - o Fixed the PCI autodetect feature. - The SLOT 0 was used as an autodetect option - however, some high end PC's slot numbers start - from 0. - - o This release has been tested with the new backupd - daemon release. - - -PRODUCT COMPONENTS AND RELATED FILES - -/etc: (or user defined) - wanpipe1.conf default router configuration file - -/lib/modules/X.Y.Z/misc: - wanrouter.o router kernel loadable module - af_wanpipe.o wanpipe api socket module - -/lib/modules/X.Y.Z/net: - sdladrv.o Sangoma SDLA support module - wanpipe.o Sangoma WANPIPE(tm) driver module - -/proc/net/wanrouter - Config reads current router configuration - Status reads current router status - {name} reads WAN driver statistics - -/usr/sbin: - wanrouter wanrouter start-up script - wanconfig wanrouter configuration utility - sdladump WANPIPE adapter memory dump utility - fpipemon Monitor for Frame Relay - cpipemon Monitor for Cisco HDLC - ppipemon Monitor for PPP - xpipemon Monitor for X25 - wpkbdmon WANPIPE keyboard led monitor/debugger - -/usr/local/wanrouter: - README this file - COPYING GNU General Public License - Setup installation script - Filelist distribution definition file - wanrouter.rc meta-configuration file - (used by the Setup and wanrouter script) - -/usr/local/wanrouter/doc: - wanpipeForLinux.pdf WAN Router User's Manual - -/usr/local/wanrouter/patches: - wanrouter-v2213.gz patch for Linux kernels 2.2.11 up to 2.2.13. - wanrouter-v2214.gz patch for Linux kernel 2.2.14. - wanrouter-v2215.gz patch for Linux kernels 2.2.15 to 2.2.17. - wanrouter-v2218.gz patch for Linux kernels 2.2.18 and up. - wanrouter-v240.gz patch for Linux kernel 2.4.0. - wanrouter-v242.gz patch for Linux kernel 2.4.2 and up. - wanrouter-v2034.gz patch for Linux kernel 2.0.34 - wanrouter-v2036.gz patch for Linux kernel 2.0.36 and up. - -/usr/local/wanrouter/patches/kdrivers: - Sources of the latest WANPIPE device drivers. - These are used to UPGRADE the linux kernel to the newest - version if the kernel source has already been pathced with - WANPIPE drivers. - -/usr/local/wanrouter/samples: - interface sample interface configuration file - wanpipe1.cpri CHDLC primary port - wanpipe2.csec CHDLC secondary port - wanpipe1.fr Frame Relay protocol - wanpipe1.ppp PPP protocol ) - wanpipe1.asy CHDLC ASYNC protocol - wanpipe1.x25 X25 protocol - wanpipe1.stty Sync TTY driver (Used by Kernel PPPD daemon) - wanpipe1.atty Async TTY driver (Used by Kernel PPPD daemon) - wanrouter.rc sample meta-configuration file - -/usr/local/wanrouter/util: - * wan-tools utilities source code - -/usr/local/wanrouter/api/x25: - * x25 api sample programs. -/usr/local/wanrouter/api/chdlc: - * chdlc api sample programs. -/usr/local/wanrouter/api/fr: - * fr api sample programs. -/usr/local/wanrouter/config/wancfg: - wancfg WANPIPE GUI configuration program. - Creates wanpipe#.conf files. -/usr/local/wanrouter/config/cfgft1: - cfgft1 GUI CSU/DSU configuration program. - -/usr/include/linux: - wanrouter.h router API definitions - wanpipe.h WANPIPE API definitions - sdladrv.h SDLA support module API definitions - sdlasfm.h SDLA firmware module definitions - if_wanpipe.h WANPIPE Socket definitions - if_wanpipe_common.h WANPIPE Socket/Driver common definitions. - sdlapci.h WANPIPE PCI definitions - - -/usr/src/linux/net/wanrouter: - * wanrouter source code - -/var/log: - wanrouter wanrouter start-up log (created by the Setup script) - -/var/lock: (or /var/lock/subsys for RedHat) - wanrouter wanrouter lock file (created by the Setup script) - -/usr/local/wanrouter/firmware: - fr514.sfm Frame relay firmware for Sangoma S508/S514 card - cdual514.sfm Dual Port Cisco HDLC firmware for Sangoma S508/S514 card - ppp514.sfm PPP Firmware for Sangoma S508 and S514 cards - x25_508.sfm X25 Firmware for Sangoma S508 card. - - -REVISION HISTORY - -1.0.0 December 31, 1996 Initial version - -1.0.1 January 30, 1997 Status and statistics can be read via /proc - filesystem entries. - -1.0.2 April 30, 1997 Added UDP management via monitors. - -1.0.3 June 3, 1997 UDP management for multiple boards using Frame - Relay and PPP - Enabled continuous transmission of Configure - Request Packet for PPP (for 508 only) - Connection Timeout for PPP changed from 900 to 0 - Flow Control Problem fixed for Frame Relay - -1.0.4 July 10, 1997 S508/FT1 monitoring capability in fpipemon and - ppipemon utilities. - Configurable TTL for UDP packets. - Multicast and Broadcast IP source addresses are - silently discarded. - -1.0.5 July 28, 1997 Configurable T391,T392,N391,N392,N393 for Frame - Relay in router.conf. - Configurable Memory Address through router.conf - for Frame Relay, PPP and X.25. (commenting this - out enables auto-detection). - Fixed freeing up received buffers using kfree() - for Frame Relay and X.25. - Protect sdla_peek() by calling save_flags(), - cli() and restore_flags(). - Changed number of Trace elements from 32 to 20 - Added DLCI specific data monitoring in FPIPEMON. -2.0.0 Nov 07, 1997 Implemented protection of RACE conditions by - critical flags for FRAME RELAY and PPP. - DLCI List interrupt mode implemented. - IPX support in FRAME RELAY and PPP. - IPX Server Support (MARS) - More driver specific stats included in FPIPEMON - and PIPEMON. - -2.0.1 Nov 28, 1997 Bug Fixes for version 2.0.0. - Protection of "enable_irq()" while - "disable_irq()" has been enabled from any other - routine (for Frame Relay, PPP and X25). - Added additional Stats for Fpipemon and Ppipemon - Improved Load Sharing for multiple boards - -2.0.2 Dec 09, 1997 Support for PAP and CHAP for ppp has been - implemented. - -2.0.3 Aug 15, 1998 New release supporting Cisco HDLC, CIR for Frame - relay, Dynamic IP assignment for PPP and Inverse - Arp support for Frame-relay. Man Pages are - included for better support and a new utility - for configuring FT1 cards. - -2.0.4 Dec 09, 1998 Dual Port support for Cisco HDLC. - Support for HDLC (LAPB) API. - Supports BiSync Streaming code for S502E - and S503 cards. - Support for Streaming HDLC API. - Provides a BSD socket interface for - creating applications using BiSync - streaming. - -2.0.5 Aug 04, 1999 CHDLC initializatin bug fix. - PPP interrupt driven driver: - Fix to the PPP line hangup problem. - New PPP firmware - Added comments to the startup SYSTEM ERROR messages - Xpipemon debugging application for the X25 protocol - New USER_MANUAL.txt - Fixed the odd boundary 4byte writes to the board. - BiSync Streaming code has been taken out. - Available as a patch. - Streaming HDLC API has been taken out. - Available as a patch. - -2.0.6 Aug 17, 1999 Increased debugging in statup scripts - Fixed insallation bugs from 2.0.5 - Kernel patch works for both 2.2.10 and 2.2.11 kernels. - There is no functional difference between the two packages - -2.0.7 Aug 26, 1999 o Merged X25API code into WANPIPE. - o Fixed a memory leak for X25API - o Updated the X25API code for 2.2.X kernels. - o Improved NEM handling. - -2.1.0 Oct 25, 1999 o New code for S514 PCI Card - o New CHDLC and Frame Relay drivers - o PPP and X25 are not supported in this release - -2.1.1 Nov 30, 1999 o PPP support for S514 PCI Cards - -2.1.3 Apr 06, 2000 o Socket based x25api - o Socket based chdlc api - o Socket based fr api - o Dual Port Receive only CHDLC support. - o Asynchronous CHDLC support (Secondary Port) - o cfgft1 GUI csu/dsu configurator - o wancfg GUI configuration file - configurator. - o Architectual directory changes. - -beta-2.1.4 Jul 2000 o Dynamic interface configuration: - Network interfaces reflect the state - of protocol layer. If the protocol becomes - disconnected, driver will bring down - the interface. Once the protocol reconnects - the interface will be brought up. - - Note: This option is turned off by default. - - o Dynamic wanrouter setup using 'wanconfig': - wanconfig utility can be used to - shutdown,restart,start or reconfigure - a virtual circuit dynamically. - - Frame Relay: Each DLCI can be: - created,stopped,restarted and reconfigured - dynamically using wanconfig. - - ex: wanconfig card wanpipe1 dev wp1_fr16 up - - o Wanrouter startup via command line arguments: - wanconfig also supports wanrouter startup via command line - arguments. Thus, there is no need to create a wanpipe#.conf - configuration file. - - o Socket based x25api update/bug fixes. - Added support for LCN numbers greater than 255. - Option to pass up modem messages. - Provided a PCI IRQ check, so a single S514 - card is guaranteed to have a non-sharing interrupt. - - o Fixes to the wancfg utility. - o New FT1 debugging support via *pipemon utilities. - o Frame Relay ARP support Enabled. - -beta3-2.1.4 Jul 2000 o X25 M_BIT Problem fix. - o Added the Multi-Port PPP - Updated utilites for the Multi-Port PPP. - -2.1.4 Aut 2000 - o In X25API: - Maximum packet an application can send - to the driver has been extended to 4096 bytes. - - Fixed the x25 startup bug. Enable - communications only after all interfaces - come up. HIGH SVC/PVC is used to calculate - the number of channels. - Enable protocol only after all interfaces - are enabled. - - o Added an extra state to the FT1 config, kernel module. - o Updated the pipemon debuggers. - - o Blocked the Multi-Port PPP from running on kernels - 2.2.16 or greater, due to syncppp kernel module - change. - -beta1-2.1.5 Nov 15 2000 - o Fixed the MulitPort PPP Support for kernels 2.2.16 and above. - 2.2.X kernels only - - o Secured the driver UDP debugging calls - - All illegal netowrk debugging calls are reported to - the log. - - Defined a set of allowed commands, all other denied. - - o Cpipemon - - Added set FT1 commands to the cpipemon. Thus CSU/DSU - configuraiton can be performed using cpipemon. - All systems that cannot run cfgft1 GUI utility should - use cpipemon to configure the on board CSU/DSU. - - - o Keyboard Led Monitor/Debugger - - A new utilty /usr/sbin/wpkbdmon uses keyboard leds - to convey operatinal statistic information of the - Sangoma WANPIPE cards. - NUM_LOCK = Line State (On=connected, Off=disconnected) - CAPS_LOCK = Tx data (On=transmitting, Off=no tx data) - SCROLL_LOCK = Rx data (On=receiving, Off=no rx data - - o Hardware probe on module load and dynamic device allocation - - During WANPIPE module load, all Sangoma cards are probed - and found information is printed in the /var/log/messages. - - If no cards are found, the module load fails. - - Appropriate number of devices are dynamically loaded - based on the number of Sangoma cards found. - - Note: The kernel configuraiton option - CONFIG_WANPIPE_CARDS has been taken out. - - o Fixed the Frame Relay and Chdlc network interfaces so they are - compatible with libpcap libraries. Meaning, tcpdump, snort, - ethereal, and all other packet sniffers and debuggers work on - all WANPIPE netowrk interfaces. - - Set the network interface encoding type to ARPHRD_PPP. - This tell the sniffers that data obtained from the - network interface is in pure IP format. - Fix for 2.2.X kernels only. - - o True interface encoding option for Frame Relay and CHDLC - - The above fix sets the network interface encoding - type to ARPHRD_PPP, however some customers use - the encoding interface type to determine the - protocol running. Therefore, the TURE ENCODING - option will set the interface type back to the - original value. - - NOTE: If this option is used with Frame Relay and CHDLC - libpcap library support will be broken. - i.e. tcpdump will not work. - Fix for 2.2.x Kernels only. - - o Ethernet Bridgind over Frame Relay - - The Frame Relay bridging has been developed by - Kristian Hoffmann and Mark Wells. - - The Linux kernel bridge is used to send ethernet - data over the frame relay links. - For 2.2.X Kernels only. - - o Added extensive 2.0.X support. Most new features of - 2.1.5 for protocols Frame Relay, PPP and CHDLC are - supported under 2.0.X kernels. - -beta1-2.2.0 Dec 30 2000 - o Updated drivers for 2.4.X kernels. - o Updated drivers for SMP support. - o X25API is now able to share PCI interrupts. - o Took out a general polling routine that was used - only by X25API. - o Added appropriate locks to the dynamic reconfiguration - code. - o Fixed a bug in the keyboard debug monitor. - -beta2-2.2.0 Jan 8 2001 - o Patches for 2.4.0 kernel - o Patches for 2.2.18 kernel - o Minor updates to PPP and CHLDC drivers. - Note: No functional difference. - -beta3-2.2.9 Jan 10 2001 - o I missed the 2.2.18 kernel patches in beta2-2.2.0 - release. They are included in this release. - -Stable Release -2.2.0 Feb 01 2001 - o Bug fix in wancfg GUI configurator. - The edit function didn't work properly. - - -bata1-2.2.1 Feb 09 2001 - o WANPIPE TTY Driver emulation. - Two modes of operation Sync and Async. - Sync: Using the PPPD daemon, kernel SyncPPP layer - and the Wanpipe sync TTY driver: a PPP protocol - connection can be established via Sangoma adapter, over - a T1 leased line. - - The 2.4.0 kernel PPP layer supports MULTILINK - protocol, that can be used to bundle any number of Sangoma - adapters (T1 lines) into one, under a single IP address. - Thus, efficiently obtaining multiple T1 throughput. - - NOTE: The remote side must also implement MULTILINK PPP - protocol. - - Async:Using the PPPD daemon, kernel AsyncPPP layer - and the WANPIPE async TTY driver: a PPP protocol - connection can be established via Sangoma adapter and - a modem, over a telephone line. - - Thus, the WANPIPE async TTY driver simulates a serial - TTY driver that would normally be used to interface the - MODEM to the linux kernel. - - o WANPIPE PPP Backup Utility - This utility will monitor the state of the PPP T1 line. - In case of failure, a dial up connection will be established - via pppd daemon, ether via a serial tty driver (serial port), - or a WANPIPE async TTY driver (in case serial port is unavailable). - - Furthermore, while in dial up mode, the primary PPP T1 link - will be monitored for signs of life. - - If the PPP T1 link comes back to life, the dial up connection - will be shutdown and T1 line re-established. - - - o New Setup installation script. - Option to UPGRADE device drivers if the kernel source has - already been patched with WANPIPE. - - Option to COMPILE WANPIPE modules against the currently - running kernel, thus no need for manual kernel and module - re-compilatin. - - o Updates and Bug Fixes to wancfg utility. - -bata2-2.2.1 Feb 20 2001 - - o Bug fixes to the CHDLC device drivers. - The driver had compilation problems under kernels - 2.2.14 or lower. - - o Bug fixes to the Setup installation script. - The device drivers compilation options didn't work - properly. - - o Update to the wpbackupd daemon. - Optimized the cross-over times, between the primary - link and the backup dialup. - -beta3-2.2.1 Mar 02 2001 - o Patches for 2.4.2 kernel. - - o Bug fixes to util/ make files. - o Bug fixes to the Setup installation script. - - o Took out the backupd support and made it into - as separate package. - -beta4-2.2.1 Mar 12 2001 - - o Fix to the Frame Relay Device driver. - IPSAC sends a packet of zero length - header to the frame relay driver. The - driver tries to push its own 2 byte header - into the packet, which causes the driver to - crash. - - o Fix the WANPIPE re-configuration code. - Bug was found by trying to run the cfgft1 while the - interface was already running. - - o Updates to cfgft1. - Writes a wanpipe#.cfgft1 configuration file - once the CSU/DSU is configured. This file can - holds the current CSU/DSU configuration. - - - ->>>>>> END OF README <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< - +For latest docs please visit Sangoma Wiki +Sangoma Wiki: http://wiki.sangoma.com +------------------------------------------------------------------------------ diff -Nur linux.org/drivers/net/wan/aft_a104.c linux-2.6.17/drivers/net/wan/aft_a104.c --- linux.org/drivers/net/wan/aft_a104.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/drivers/net/wan/aft_a104.c 2006-08-30 10:07:16.000000000 +0000 @@ -0,0 +1,1488 @@ +/***************************************************************************** +* aft_a104.c +* +* WANPIPE(tm) AFT A104 Hardware Support +* +* Authors: Nenad Corbic +* +* Copyright: (c) 2003-2005 Sangoma Technologies Inc. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version +* 2 of the License, or (at your option) any later version. +* ============================================================================ +* Sep 25, 2005 Nenad Corbic Initial Version +*****************************************************************************/ + +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) +# include +# include +# include +# include /* Socket Driver common area */ +# include +//# include +# include +# include +#else +# include +# include +# include +# include +# include +# include /* Socket Driver common area */ +# include +# include +//# include +# include +# include +# include +#endif + +/*============================================== + * PRIVATE FUNCITONS + * + */ +#if defined(CONFIG_WANPIPE_HWEC) +static int a104_hwec_reset(void *pcard, int reset); +static int a104_hwec_enable(void *pcard, int enable, int channel); +#endif + +int __a104_write_fe (void *pcard, ...); + +static int aft_map_fifo_baddr_and_size(sdla_t *card, unsigned char fifo_size, unsigned char *addr); + +static char fifo_size_vector[] = {1, 2, 4, 8, 16, 32}; +static char fifo_code_vector[] = {0, 1, 3, 7,0xF,0x1F}; + +static int request_fifo_baddr_and_size(sdla_t *card, private_area_t *chan) +{ + unsigned char req_fifo_size,fifo_size; + int i; + + /* Calculate the optimal fifo size based + * on the number of time slots requested */ + + if (IS_T1_CARD(card)){ + + if (chan->num_of_time_slots == NUM_OF_T1_CHANNELS){ + req_fifo_size=32; + }else if (chan->num_of_time_slots == 1){ + req_fifo_size=1; + }else if (chan->num_of_time_slots == 2 || chan->num_of_time_slots == 3){ + req_fifo_size=2; + }else if (chan->num_of_time_slots >= 4 && chan->num_of_time_slots<= 7){ + req_fifo_size=4; + }else if (chan->num_of_time_slots >= 8 && chan->num_of_time_slots<= 15){ + req_fifo_size=8; + }else if (chan->num_of_time_slots >= 16 && chan->num_of_time_slots<= 23){ + req_fifo_size=16; + }else{ + DEBUG_EVENT("%s:%s: Invalid number of timeslots %d\n", + card->devname,chan->if_name,chan->num_of_time_slots); + return -EINVAL; + } + }else{ + if (chan->num_of_time_slots == (NUM_OF_E1_CHANNELS-1)){ + req_fifo_size=32; + }else if (chan->num_of_time_slots == 1){ + req_fifo_size=1; + }else if (chan->num_of_time_slots == 2 || chan->num_of_time_slots == 3){ + req_fifo_size=2; + }else if (chan->num_of_time_slots >= 4 && chan->num_of_time_slots <= 7){ + req_fifo_size=4; + }else if (chan->num_of_time_slots >= 8 && chan->num_of_time_slots <= 15){ + req_fifo_size=8; + }else if (chan->num_of_time_slots >= 16 && chan->num_of_time_slots <= 31){ + req_fifo_size=16; + }else{ + DEBUG_EVENT("%s:%s: Invalid number of timeslots %d\n", + card->devname,chan->if_name,chan->num_of_time_slots); + return -EINVAL; + } + } + + DEBUG_TEST("%s:%s: Optimal Fifo Size =%d Timeslots=%d \n", + card->devname,chan->if_name,req_fifo_size,chan->num_of_time_slots); + + fifo_size=aft_map_fifo_baddr_and_size(card,req_fifo_size,&chan->fifo_base_addr); + if (fifo_size == 0 || chan->fifo_base_addr == 31){ + DEBUG_EVENT("%s:%s: Error: Failed to obtain fifo size %d or addr %d \n", + card->devname,chan->if_name,fifo_size,chan->fifo_base_addr); + return -EINVAL; + } + + DEBUG_TEST("%s:%s: Optimal Fifo Size =%d Timeslots=%d New Fifo Size=%d \n", + card->devname,chan->if_name,req_fifo_size,chan->num_of_time_slots,fifo_size); + + + for (i=0;ififo_size_code=fifo_code_vector[i]; + break; + } + } + + if (fifo_size != req_fifo_size){ + DEBUG_EVENT("%s:%s: Warning: Failed to obtain the req fifo %d got %d\n", + card->devname,chan->if_name,req_fifo_size,fifo_size); + } + + DEBUG_TEST("%s: %s:Fifo Size=%d Timeslots=%d Fifo Code=%d Addr=%d\n", + card->devname,chan->if_name,fifo_size, + chan->num_of_time_slots,chan->fifo_size_code, + chan->fifo_base_addr); + + chan->fifo_size = fifo_size; + + return 0; +} + + +static int aft_map_fifo_baddr_and_size(sdla_t *card, unsigned char fifo_size, unsigned char *addr) +{ + u32 reg=0; + int i; + + for (i=0;idevname,reg,card->u.aft.fifo_addr_map); + + for (i=0;i<32;i+=fifo_size){ + if (card->u.aft.fifo_addr_map & (reg<u.aft.fifo_addr_map |= reg<devname,card->u.aft.fifo_addr_map,i); + + return fifo_size; + } + + if (fifo_size == 1){ + return 0; + } + + fifo_size = fifo_size >> 1; + + return aft_map_fifo_baddr_and_size(card,fifo_size,addr); +} + + +static int aft_free_fifo_baddr_and_size (sdla_t *card, private_area_t *chan) +{ + u32 reg=0; + int i; + + for (i=0;ififo_size;i++){ + wan_set_bit(i,®); + } + + DEBUG_TEST("%s: Unmapping 0x%X from 0x%lX\n", + card->devname,reg<fifo_base_addr, card->u.aft.fifo_addr_map); + + card->u.aft.fifo_addr_map &= ~(reg<fifo_base_addr); + + DEBUG_TEST("%s: New Map is 0x%lX\n", + card->devname, card->u.aft.fifo_addr_map); + + + chan->fifo_size=0; + chan->fifo_base_addr=0; + + return 0; +} + + +static char aft_request_logical_channel_num (sdla_t *card, private_area_t *chan) +{ + signed char logic_ch=-1; + int err; + int if_cnt=wan_atomic_read(&card->wandev.if_cnt); + int if_offset=2; + long i; + + if (IS_E1_CARD(card)){ + if_offset=3; + } + + DEBUG_TEST("-- Request_Xilinx_logic_channel_num:--\n"); + + DEBUG_TEST("%s:%d Global Num Timeslots=%d Global Logic ch Map 0x%lX \n", + __FUNCTION__,__LINE__, + card->u.aft.num_of_time_slots, + card->u.aft.logic_ch_map); + + + /* Check that the time slot is not being used. If it is + * stop the interface setup. Notice, though we proceed + * to check for all timeslots before we start binding + * the channels in. This way, we don't have to go back + * and clean the time_slot_map */ + for (i=0;iu.aft.num_of_time_slots;i++){ + if (wan_test_bit(i,&chan->time_slot_map)){ + + if (chan->first_time_slot == -1){ + DEBUG_EVENT("%s: First TSlot :%ld\n", + card->devname,i); + chan->first_time_slot=i; + } + + chan->last_time_slot=i; + + DEBUG_CFG("%s: Configuring %s for timeslot %ld\n", + card->devname, chan->if_name, + IS_E1_CARD(card)?i:i+1); + + if (wan_test_bit(i,&card->u.xilinx.time_slot_map)){ + DEBUG_EVENT("%s: Channel/Time Slot resource conflict!\n", + card->devname); + DEBUG_EVENT("%s: %s: Channel/Time Slot %ld, aready in use!\n", + card->devname,chan->if_name,(i+1)); + + return -EEXIST; + } + } + } + + err=request_fifo_baddr_and_size(card,chan); + if (err){ + return -1; + } + + for (i=0;iu.aft.num_of_time_slots;i++){ + + if (card->u.aft.security_id == 0){ + /* Unchannelized card must config + * its hdlc logic ch on FIRST logic + * ch number */ + if (chan->channelized_cfg){ + if (card->u.aft.cfg.tdmv_dchan){ + /* In this case we KNOW that there is + * only a single hdlc channel */ + if (i==0 && !chan->hdlc_eng){ + continue; + } + } + }else{ + if (i==0 || i==1){ + if (!chan->hdlc_eng && + if_cnt < (card->u.aft.num_of_time_slots-if_offset)){ + continue; + } + } + } + } + + if (!wan_test_and_set_bit(i,&card->u.aft.logic_ch_map)){ + logic_ch=i; + break; + } + } + + if (logic_ch == -1){ + return logic_ch; + } + + for (i=0;iu.aft.num_of_time_slots;i++){ + if (!wan_test_bit(i,&card->u.aft.logic_ch_map)){ + break; + } + } + + if (card->u.aft.dev_to_ch_map[(unsigned char)logic_ch]){ + DEBUG_EVENT("%s: Error, request logical ch=%d map busy\n", + card->devname,logic_ch); + return -1; + } + + card->u.aft.dev_to_ch_map[(unsigned char)logic_ch]=(void*)chan; + + if (logic_ch >= card->u.aft.top_logic_ch){ + card->u.aft.top_logic_ch=logic_ch; + aft_dma_max_logic_ch(card); + } + + + DEBUG_TEST("Binding logic ch %d Ptr=%p\n",logic_ch,chan); + return logic_ch; +} + + + +static int aft_test_hdlc(sdla_t *card) +{ + int i; + int err; + u32 reg; + + for (i=0;i<10;i++){ + card->hw_iface.bus_read_4(card->hw,AFT_CHIP_CFG_REG, ®); + + if (!wan_test_bit(AFT_CHIPCFG_HDLC_CTRL_RDY_BIT,®) || + !wan_test_bit(AFT_CHIPCFG_RAM_READY_BIT,®)){ + /* The HDLC Core is not ready! we have + * an error. */ + err = -EINVAL; + WP_DELAY(200); + }else{ + err=0; + break; + } + } + + return err; +} + + +/*============================================== + * PUBLIC FUNCITONS + * + */ + +int a104_test_sync(sdla_t *card, int tx_only) +{ + volatile int i,err=1; + u32 reg; + + card->hw_iface.bus_read_4(card->hw,AFT_PORT_REG(card,AFT_LINE_CFG_REG), ®); + + if (wan_test_bit(AFT_LCFG_FE_IFACE_RESET_BIT,®)){ + DEBUG_EVENT("%s: Warning: PMC Reset Enabled %d! \n", + card->devname, card->wandev.comm_port+1); + } + + + for (i=0;i<500;i++){ + + card->hw_iface.bus_read_4(card->hw,AFT_PORT_REG(card,AFT_LINE_CFG_REG), ®); + if (tx_only){ + if (wan_test_bit(AFT_LCFG_TX_FE_SYNC_STAT_BIT,®)){ + err=-1; + WP_DELAY(200); + }else{ + err=0; + break; + } + }else{ + if (wan_test_bit(AFT_LCFG_TX_FE_SYNC_STAT_BIT,®) || + wan_test_bit(AFT_LCFG_RX_FE_SYNC_STAT_BIT,®)){ + err=-1; + WP_DELAY(200); + }else{ + err=0; + break; + } + } + } + + DEBUG_TEST("%s: DELAY INDEX = %i\n", + card->devname,i); + + return err; +} + +int a104_led_ctrl(sdla_t *card, int color, int led_pos, int on) +{ + u32 reg; + + if (card->adptr_subtype == AFT_SUBTYPE_SHARK){ + + /* INSERT LED CODE */ + switch (color){ + + case WAN_AFT_RED: + if (on){ + wan_clear_bit(0,&card->u.aft.led_ctrl); + }else{ + wan_set_bit(0,&card->u.aft.led_ctrl); + } + break; + + case WAN_AFT_GREEN: + if (on){ + wan_clear_bit(1,&card->u.aft.led_ctrl); + }else{ + wan_set_bit(1,&card->u.aft.led_ctrl); + } + break; + } + + a104_write_cpld(card,card->wandev.comm_port + 0x08,card->u.aft.led_ctrl); + }else{ + card->hw_iface.bus_read_4(card->hw, + AFT_PORT_REG(card,AFT_LINE_CFG_REG),®); + aft_set_led(color, led_pos, on, ®); + card->hw_iface.bus_write_4(card->hw, + AFT_PORT_REG(card,AFT_LINE_CFG_REG),reg); + } + + return 0; +} + + +int a104_global_chip_config(sdla_t *card) +{ + u32 reg; + int err=0; + /*============ GLOBAL CHIP CONFIGURATION ===============*/ + + /* Enable the chip/hdlc reset condition */ + reg=0; + wan_set_bit(AFT_CHIPCFG_SFR_EX_BIT,®); + wan_set_bit(AFT_CHIPCFG_SFR_IN_BIT,®); + + DEBUG_CFG("--- AFT Chip Reset. -- \n"); + + card->hw_iface.bus_write_4(card->hw,AFT_CHIP_CFG_REG,reg); + + WP_DELAY(10); + + /* Disable the chip/hdlc reset condition */ + wan_clear_bit(AFT_CHIPCFG_SFR_EX_BIT,®); + wan_clear_bit(AFT_CHIPCFG_SFR_IN_BIT,®); + + wan_clear_bit(AFT_CHIPCFG_FE_INTR_CFG_BIT,®); + + if (IS_T1_CARD(card)){ + wan_clear_bit(AFT_CHIPCFG_TE1_CFG_BIT,®); + }else if (IS_E1_CARD(card)){ + wan_set_bit(AFT_CHIPCFG_TE1_CFG_BIT,®); + + }else{ + DEBUG_EVENT("%s: Error: Xilinx doesn't support non T1/E1 interface!\n", + card->devname); + return -EINVAL; + } + + /* Enable FRONT END Interrupt */ + wan_set_bit(AFT_CHIPCFG_FE_INTR_CFG_BIT,®); + + DEBUG_CFG("--- Chip enable/config. -- \n"); + + if (card->adptr_subtype == AFT_SUBTYPE_SHARK){ + + /* FIXME: Do not hardcode port numbers */ + if (card->u.aft.cfg.ec_clk_src < 0 || + card->u.aft.cfg.ec_clk_src > 7) { + DEBUG_EVENT("%s: ERROR: Invalid SHARK Octasic Clock Source %d\n", + card->devname,card->u.aft.cfg.ec_clk_src); + return -EINVAL; + } + + DEBUG_EVENT("%s: Global EC Clock Port = %d\n", + card->devname, + card->u.aft.cfg.ec_clk_src+1); + aft_chipcfg_set_oct_clk_src(®,card->u.aft.cfg.ec_clk_src); + } + + card->hw_iface.bus_write_4(card->hw,AFT_CHIP_CFG_REG,reg); + + if (card->adptr_type == A108_ADPTR_8TE1) { + wan_smp_flag_t smp_flags,flags; + card->hw_iface.hw_lock(card->hw,&smp_flags); + wan_spin_lock_irq(&card->wandev.lock,&flags); + a104_write_cpld(card,0x00,0x06); + wan_spin_unlock_irq(&card->wandev.lock,&flags); + card->hw_iface.hw_unlock(card->hw,&smp_flags); + }else if (card->adptr_subtype == AFT_SUBTYPE_SHARK){ + wan_smp_flag_t smp_flags,flags; + card->hw_iface.hw_lock(card->hw,&smp_flags); + wan_spin_lock_irq(&card->wandev.lock,&flags); + if (IS_T1_CARD(card)){ + a104_write_cpld(card,0x00,0x00); + }else if (IS_E1_CARD(card)){ + a104_write_cpld(card,0x00,0x02); + } + wan_spin_unlock_irq(&card->wandev.lock,&flags); + card->hw_iface.hw_unlock(card->hw,&smp_flags); + } + + + + err=aft_test_hdlc(card); + + if (err != 0){ + DEBUG_EVENT("%s: Error: HDLC Core Not Ready (0x%X)!\n", + card->devname,reg); + return -EINVAL; + } else{ + DEBUG_CFG("%s: HDLC Core Ready\n", + card->devname); + } + DEBUG_EVENT("%s: Global Front End Configuraton!\n",card->devname); + err = -EINVAL; + if (card->wandev.fe_iface.global_config){ + err=card->wandev.fe_iface.global_config(&card->fe); + } + if (err){ + return err; + } + return 0; +} + +int a104_global_chip_unconfig(sdla_t *card) +{ + u32 reg=0; + + /* Global T1/E1 unconfig */ + if (card->wandev.fe_iface.global_unconfig){ + card->wandev.fe_iface.global_unconfig(&card->fe); + } + + /* Set Octasic/TE1 clocking to reset (A104) + ** Set Octasic/Framer to reset (A108) */ + a104_write_cpld(card,0x00,0x00); + + /* Disable the chip/hdlc reset condition */ + wan_set_bit(AFT_CHIPCFG_SFR_EX_BIT,®); + wan_set_bit(AFT_CHIPCFG_SFR_IN_BIT,®); + wan_clear_bit(AFT_CHIPCFG_FE_INTR_CFG_BIT,®); + + card->hw_iface.bus_write_4(card->hw,AFT_CHIP_CFG_REG,reg); + + return 0; +} + +static int a108_set_clock_ref(sdla_t *card, u32 *reg, u32 master_port) +{ + u32 master_cfg; + + if (IS_T1_CARD(card)) { + master_cfg=0x09; + } else { + master_cfg=0x08; + } + + if (WAN_TE1_CLK(&card->fe) == WAN_MASTER_CLK) { + wan_set_bit(AFT_LCFG_A108_FE_CLOCK_MODE_BIT,reg); + + if (WAN_FE_LINENO(&card->fe) >= 4) { + a108m_write_cpld(card, + WAN_FE_LINENO(&card->fe)-4, + master_cfg); + } + /* July 5, 2006 + ** Modification for Master mode (next line execute for all channels) */ + aft_lcfg_a108_fe_clk_source(reg,master_cfg); + + } else { + wan_clear_bit(AFT_LCFG_A108_FE_CLOCK_MODE_BIT,reg); + + if (WAN_FE_LINENO(&card->fe) >= 4) { + a108m_write_cpld(card, + WAN_FE_LINENO(&card->fe)-4, + master_port); + } else { + aft_lcfg_a108_fe_clk_source(reg,master_port); + } + } + + return 0; +} + + +int a104_chip_config(sdla_t *card) +{ + u32 reg=0, ctrl_ram_reg=0; + int i,err=0; + + wan_smp_flag_t smp_flags, flags; + + card->hw_iface.bus_read_4(card->hw,AFT_PORT_REG(card,AFT_LINE_CFG_REG), ®); + if (!wan_test_bit(AFT_LCFG_FE_IFACE_RESET_BIT,®)){ + DEBUG_EVENT("%s: Error: Physical Port %i is busy! \n", + card->devname, card->wandev.comm_port+1); + return -EBUSY; + } + + /* On A108 Cards the T1/E1 will be configured per PORT + * not per CARD */ + if (card->adptr_type == A108_ADPTR_8TE1) { + + if (IS_T1_CARD(card)) { + wan_clear_bit(AFT_LCFG_A108_FE_TE1_MODE_BIT,®); + } else { + wan_set_bit(AFT_LCFG_A108_FE_TE1_MODE_BIT,®); + } + + card->hw_iface.hw_lock(card->hw,&smp_flags); + wan_spin_lock_irq(&card->wandev.lock,&flags); + + a108_set_clock_ref(card,®,WAN_FE_LINENO(&card->fe)); + + wan_spin_unlock_irq(&card->wandev.lock,&flags); + card->hw_iface.hw_unlock(card->hw,&smp_flags); + + card->hw_iface.bus_write_4(card->hw,AFT_PORT_REG(card,AFT_LINE_CFG_REG), reg); + } + + card->hw_iface.hw_lock(card->hw,&smp_flags); + + aft_fe_intr_ctrl(card, 0); + + err = -EINVAL; + if (card->wandev.fe_iface.config){ + err=card->wandev.fe_iface.config(&card->fe); + } + + a104_led_ctrl(card, WAN_AFT_RED, 0,WAN_AFT_ON); + a104_led_ctrl(card, WAN_AFT_GREEN, 0, WAN_AFT_OFF); + + aft_fe_intr_ctrl(card, 1); + + card->hw_iface.hw_unlock(card->hw,&smp_flags); + + if (err){ + DEBUG_EVENT("%s: Failed %s configuration!\n", + card->devname, + (IS_T1_CARD(card))?"T1":"E1"); + return -EINVAL; + } + + DEBUG_EVENT("%s: Front end successful\n", + card->devname); + + if (card->adptr_type == A104_ADPTR_4TE1 || + card->adptr_type == A108_ADPTR_8TE1) { + + if (WAN_TE1_CLK(&card->fe) == WAN_MASTER_CLK && + WAN_TE1_REFCLK(&card->fe) > 0){ + + int mclk_ver=AFT_TDMV_FRM_CLK_SYNC_VER; + int max_port=4; + + if (card->adptr_subtype == AFT_SUBTYPE_SHARK){ + mclk_ver=AFT_TDMV_SHARK_FRM_CLK_SYNC_VER; + } + + if (card->adptr_type == A108_ADPTR_8TE1) { + mclk_ver=AFT_TDMV_SHARK_A108_FRM_CLK_SYNC_VER; + max_port=8; + } + + if (card->u.aft.firm_ver < mclk_ver){ + DEBUG_EVENT("%s: Error: AFT FE Clock Sync Depends on Firmware Ver: %X (Cur=%X)\n", + card->devname,mclk_ver,card->u.aft.firm_ver); + DEBUG_EVENT("%s: Please upgrade your AFT Firmware to Ver=%X or greater!\n", + card->devname,mclk_ver); + return -EINVAL; + } + + if (WAN_TE1_REFCLK(&card->fe) == card->wandev.comm_port+1){ + DEBUG_EVENT("%s: Error: Invalid FE Clock Source Line=%i (same as configured line=%i)\n", + card->devname,WAN_TE1_REFCLK(&card->fe), + card->wandev.comm_port+1); + return -EINVAL; + } + + if (WAN_TE1_REFCLK(&card->fe) > max_port){ + DEBUG_EVENT("%s: Error: Invalid FE Clock Source Line=%i\n", + card->devname,WAN_TE1_REFCLK(&card->fe)); + return -EINVAL; + + } + + card->hw_iface.bus_read_4(card->hw, + AFT_PORT_REG(card,AFT_LINE_CFG_REG),®); + + if (card->adptr_type == A108_ADPTR_8TE1) { + + card->hw_iface.hw_lock(card->hw,&smp_flags); + wan_spin_lock_irq(&card->wandev.lock,&flags); + + /* For A108 the refclock indicates NORMAL mode. + * For backward compatilbity we make the user + * indicate a MASTER mode */ + + WAN_TE1_CLK(&card->fe) = WAN_NORMAL_CLK; + a108_set_clock_ref(card,®,WAN_TE1_REFCLK(&card->fe)-1); + + wan_spin_unlock_irq(&card->wandev.lock,&flags); + card->hw_iface.hw_unlock(card->hw,&smp_flags); + + } else { + + aft_lcfg_fe_clk_source(®,WAN_TE1_REFCLK(&card->fe)-1); + wan_set_bit(AFT_LCFG_FE_CLK_ROUTE_BIT,®); + + } + + card->hw_iface.bus_write_4(card->hw, + AFT_PORT_REG(card,AFT_LINE_CFG_REG),reg); + + DEBUG_EVENT("%s: Configuring FE Line=%d Clock Source: Line=%d\n", + card->devname, + card->wandev.comm_port+1, + WAN_TE1_REFCLK(&card->fe)); + } + + } + + /*============ LINE/PORT CONFIG REGISTER ===============*/ + + card->hw_iface.bus_read_4(card->hw, + AFT_PORT_REG(card,AFT_LINE_CFG_REG),®); + wan_set_bit(AFT_LCFG_FE_IFACE_RESET_BIT,®); + card->hw_iface.bus_write_4(card->hw,AFT_PORT_REG(card,AFT_LINE_CFG_REG),reg); + + WP_DELAY(10); + + wan_clear_bit(AFT_LCFG_FE_IFACE_RESET_BIT,®); + card->hw_iface.bus_write_4(card->hw,AFT_PORT_REG(card,AFT_LINE_CFG_REG),reg); + + WP_DELAY(10); + + err=a104_test_sync(card,1); + + card->hw_iface.bus_read_4(card->hw,AFT_PORT_REG(card,AFT_LINE_CFG_REG),®); + if (err != 0){ + DEBUG_EVENT("%s: Error: Front End Interface Not Ready (0x%08X)!\n", + card->devname,reg); + return err; + } else{ + DEBUG_EVENT("%s: Front End Interface Ready 0x%08X\n", + card->devname,reg); + } + + /* Enable Octasic Chip */ + if (card->adptr_subtype == AFT_SUBTYPE_SHARK){ + u16 max_ec_chans; + u32 cfg_reg; + + card->hw_iface.getcfg(card->hw, SDLA_HWEC_NO, &max_ec_chans); + + card->hw_iface.bus_read_4(card->hw,AFT_CHIP_CFG_REG, &cfg_reg); + if (max_ec_chans > aft_chipcfg_get_ec_channels(cfg_reg)){ + DEBUG_EVENT("%s: Critical Error: Exceeded Maximum Available Echo Channels!\n", + card->devname); + DEBUG_EVENT("%s: Critical Error: Max Allowed=%d Configured=%d\n", + card->devname, + aft_chipcfg_get_ec_channels(cfg_reg), + max_ec_chans); + return -EINVAL; + } + + if (max_ec_chans){ +#if defined(CONFIG_WANPIPE_HWEC) + card->wandev.ec_dev = wanpipe_ec_register(card, max_ec_chans); + card->wandev.hwec_reset = a104_hwec_reset; + card->wandev.hwec_enable = a104_hwec_enable; +#else + DEBUG_EVENT("%s: Wanpipe HW Echo Canceller modele is not compiled!\n", + card->devname); +#endif + }else{ + DEBUG_EVENT( + "%s: WARNING: No Echo Canceller channels are available!\n", + card->devname); + } + } + + /* Enable only Front End Interrupt + * Wait for front end to come up before enabling DMA */ + card->hw_iface.bus_read_4(card->hw,AFT_PORT_REG(card,AFT_LINE_CFG_REG), ®); + wan_clear_bit(AFT_LCFG_DMA_INTR_BIT,®); + wan_clear_bit(AFT_LCFG_FIFO_INTR_BIT,®); + wan_clear_bit(AFT_LCFG_TDMV_INTR_BIT,®); + + card->hw_iface.bus_write_4(card->hw,AFT_PORT_REG(card,AFT_LINE_CFG_REG), reg); + + card->u.aft.lcfg_reg=reg; + + + + /*============ DMA CONTROL REGISTER ===============*/ + + /* Disable Global DMA because we will be + * waiting for the front end to come up */ + reg=0; + aft_dmactrl_set_max_logic_ch(®,0); + wan_clear_bit(AFT_DMACTRL_GLOBAL_INTR_BIT,®); + card->hw_iface.bus_write_4(card->hw,AFT_PORT_REG(card,AFT_DMA_CTRL_REG),reg); + + + reg=0; + for (i=0;i<32;i++){ + ctrl_ram_reg=AFT_PORT_REG(card,AFT_CONTROL_RAM_ACCESS_BASE_REG); + ctrl_ram_reg+=(i*4); + + aft_ctrlram_set_logic_ch(®,0x1F); + aft_ctrlram_set_fifo_size(®,0); + aft_ctrlram_set_fifo_base(®,0x1F); + + wan_set_bit(AFT_CTRLRAM_HDLC_MODE_BIT,®); + wan_set_bit(AFT_CTRLRAM_HDLC_TXCH_RESET_BIT,®); + wan_set_bit(AFT_CTRLRAM_HDLC_RXCH_RESET_BIT,®); + + card->hw_iface.bus_write_4(card->hw, ctrl_ram_reg, reg); + } + + + aft_wdt_reset(card); + aft_wdt_set(card,AFT_WDTCTRL_TIMEOUT); + + return 0; +} + +int a104_chip_unconfig(sdla_t *card) +{ + u32 reg=0; + + aft_wdt_reset(card); + + /* Disable Octasic Chip */ + if (card->adptr_subtype == AFT_SUBTYPE_SHARK && card->wandev.ec_dev){ + /* ALEX CALL DISABLE */ + if (card->wandev.ec_dev){ +#if defined(CONFIG_WANPIPE_HWEC) + wanpipe_ec_unregister(card->wandev.ec_dev, card); +#else + DEBUG_EVENT("%s: Wanpipe HW Echo Canceller modele is not compiled!\n", + card->devname); +#endif + } + card->wandev.hwec_enable = NULL; + card->wandev.ec_dev = NULL; + } + + /* Unconfiging, only on shutdown */ + if (IS_TE1_CARD(card)) { + wan_smp_flag_t smp_flags,smp_flags1; + card->hw_iface.hw_lock(card->hw,&smp_flags1); + wan_spin_lock_irq(&card->wandev.lock, &smp_flags); + if (card->wandev.fe_iface.unconfig){ + card->wandev.fe_iface.unconfig(&card->fe); + } + wan_spin_unlock_irq(&card->wandev.lock, &smp_flags); + card->hw_iface.hw_unlock(card->hw,&smp_flags1); + + } + + + wan_set_bit(AFT_LCFG_FE_IFACE_RESET_BIT,®); + card->hw_iface.bus_write_4(card->hw,AFT_PORT_REG(card,AFT_LINE_CFG_REG),reg); + + return 0; + +} + +int a104_chan_dev_config(sdla_t *card, void *chan_ptr) +{ + u32 reg; + long i; + private_area_t *chan = (private_area_t*)chan_ptr; + u32 ctrl_ram_reg,dma_ram_reg; + + chan->logic_ch_num=aft_request_logical_channel_num(card, chan); + if (chan->logic_ch_num == -1){ + return -EBUSY; + } + + dma_ram_reg=AFT_PORT_REG(card,AFT_DMA_CHAIN_RAM_BASE_REG); + dma_ram_reg+=(chan->logic_ch_num*4); + + reg=0; + card->hw_iface.bus_write_4(card->hw, dma_ram_reg, reg); + + card->hw_iface.bus_read_4(card->hw, dma_ram_reg, ®); + + aft_dmachain_set_fifo_size(®, chan->fifo_size_code); + aft_dmachain_set_fifo_base(®, chan->fifo_base_addr); + + /* Initially always disable rx synchronization */ + wan_clear_bit(AFT_DMACHAIN_RX_SYNC_BIT,®); + + /* Enable SS7 if configured by user */ + if (chan->cfg.ss7_enable){ + wan_set_bit(AFT_DMACHAIN_SS7_ENABLE_BIT,®); + }else{ + wan_clear_bit(AFT_DMACHAIN_SS7_ENABLE_BIT,®); + } + + if (chan->channelized_cfg && !chan->hdlc_eng){ + aft_dmachain_enable_tdmv_and_mtu_size(®,chan->mru); + } + + card->hw_iface.bus_write_4(card->hw, dma_ram_reg, reg); + + reg=0; + + + for (i=0;iu.xilinx.num_of_time_slots;i++){ + + ctrl_ram_reg=AFT_PORT_REG(card,AFT_CONTROL_RAM_ACCESS_BASE_REG); + ctrl_ram_reg+=(i*4); + + if (wan_test_bit(i,&chan->time_slot_map)){ + + wan_set_bit(i,&card->u.aft.time_slot_map); + + card->hw_iface.bus_read_4(card->hw, ctrl_ram_reg, ®); + + aft_ctrlram_set_logic_ch(®,chan->logic_ch_num); + + if (i == chan->first_time_slot){ + wan_set_bit(AFT_CTRLRAM_SYNC_FST_TSLOT_BIT,®); + } + + aft_ctrlram_set_fifo_size(®,chan->fifo_size_code); + + aft_ctrlram_set_fifo_base(®,chan->fifo_base_addr); + + + if (chan->hdlc_eng){ + wan_set_bit(AFT_CTRLRAM_HDLC_MODE_BIT,®); + }else{ + wan_clear_bit(AFT_CTRLRAM_HDLC_MODE_BIT,®); + } + + if (chan->cfg.data_mux){ + wan_set_bit(AFT_CTRLRAM_DATA_MUX_ENABLE_BIT,®); + }else{ + wan_clear_bit(AFT_CTRLRAM_DATA_MUX_ENABLE_BIT,®); + } + + if (0){ /* FIXME card->fe.fe_cfg.cfg.te1cfg.fcs == 32){ */ + wan_set_bit(AFT_CTRLRAM_HDLC_CRC_SIZE_BIT,®); + }else{ + wan_clear_bit(AFT_CTRLRAM_HDLC_CRC_SIZE_BIT,®); + } + + /* Enable SS7 if configured by user */ + if (chan->cfg.ss7_enable){ + wan_set_bit(AFT_CTRLRAM_SS7_ENABLE_BIT,®); + }else{ + wan_clear_bit(AFT_CTRLRAM_SS7_ENABLE_BIT,®); + } + + wan_clear_bit(AFT_CTRLRAM_HDLC_TXCH_RESET_BIT,®); + wan_clear_bit(AFT_CTRLRAM_HDLC_RXCH_RESET_BIT,®); + + DEBUG_TEST("%s: Configuring %s for timeslot %ld : Offset 0x%X Reg 0x%X\n", + card->devname, chan->if_name, i, + ctrl_ram_reg,reg); + + card->hw_iface.bus_write_4(card->hw, ctrl_ram_reg, reg); + + } + } + + if (chan->channelized_cfg && !chan->hdlc_eng){ + + card->hw_iface.bus_read_4(card->hw,AFT_PORT_REG(card,AFT_LINE_CFG_REG),®); + aft_lcfg_tdmv_cnt_inc(®); + + card->hw_iface.bus_write_4(card->hw,AFT_PORT_REG(card,AFT_LINE_CFG_REG),reg); + card->u.aft.lcfg_reg=reg; + } + + return 0; +} + +int a104_chan_dev_unconfig(sdla_t *card, void *chan_ptr) +{ + private_area_t *chan = (private_area_t *)chan_ptr; + volatile int i; + u32 dma_ram_reg,ctrl_ram_reg,reg; + + /* Select an HDLC logic channel for configuration */ + if (chan->logic_ch_num != -1){ + + dma_ram_reg=AFT_PORT_REG(card,AFT_DMA_CHAIN_RAM_BASE_REG); + dma_ram_reg+=(chan->logic_ch_num*4); + + card->hw_iface.bus_read_4(card->hw, dma_ram_reg, ®); + + aft_dmachain_set_fifo_base(®,0x1F); + aft_dmachain_set_fifo_size(®,0); + card->hw_iface.bus_write_4(card->hw, dma_ram_reg, reg); + + + for (i=0;iu.aft.num_of_time_slots;i++){ + if (wan_test_bit(i,&chan->time_slot_map)){ + + ctrl_ram_reg=AFT_PORT_REG(card,AFT_CONTROL_RAM_ACCESS_BASE_REG); + ctrl_ram_reg+=(i*4); + + reg=0; + aft_ctrlram_set_logic_ch(®,0x1F); + + aft_ctrlram_set_fifo_base(®,0x1F); + aft_ctrlram_set_fifo_size(®,0); + + wan_set_bit(AFT_CTRLRAM_HDLC_MODE_BIT,®); + wan_set_bit(AFT_CTRLRAM_HDLC_TXCH_RESET_BIT,®); + wan_set_bit(AFT_CTRLRAM_HDLC_RXCH_RESET_BIT,®); + + card->hw_iface.bus_write_4(card->hw, ctrl_ram_reg, reg); + } + } + + aft_free_logical_channel_num(card,chan->logic_ch_num); + aft_free_fifo_baddr_and_size(card,chan); + + for (i=0;iu.xilinx.num_of_time_slots;i++){ + if (wan_test_bit(i,&chan->time_slot_map)){ + wan_clear_bit(i,&card->u.xilinx.time_slot_map); + } + } + + if (chan->channelized_cfg && !chan->hdlc_eng){ + card->hw_iface.bus_read_4(card->hw, + AFT_PORT_REG(card,AFT_LINE_CFG_REG),®); + aft_lcfg_tdmv_cnt_dec(®); + card->hw_iface.bus_write_4(card->hw, + AFT_PORT_REG(card,AFT_LINE_CFG_REG),reg); + } + + chan->logic_ch_num=-1; + } + + return 0; +} + +int a104_check_ec_security(sdla_t *card) +{ + u32 cfg_reg; + u32 security_bit=AFT_CHIPCFG_A104D_EC_SECURITY_BIT; + + if (card->adptr_type == A108_ADPTR_8TE1) { + security_bit=AFT_CHIPCFG_A108_EC_SECURITY_BIT; + } + + card->hw_iface.bus_read_4(card->hw,AFT_CHIP_CFG_REG, &cfg_reg); + if (wan_test_bit(security_bit,&cfg_reg)){ + return 1; + } + return 0; +} + + +/*============================================================================ + * Read TE1/56K Front end registers + */ +int __a104_write_fe (void *pcard, ...) +{ + va_list args; + sdla_t *card = (sdla_t*)pcard; + int org_off, off, value; + u8 qaccess = card->wandev.state == WAN_CONNECTED ? 1 : 0; + + va_start(args, pcard); + off = va_arg(args, int); + value = va_arg(args, int); + va_end(args); + + if (card->adptr_type == A104_ADPTR_4TE1) { + off &= ~AFT4_BIT_DEV_ADDR_CLEAR; + }else{ + if (off & 0x800) off |= 0x2000; + if (off & 0x1000) off |= 0x4000; + off &= ~AFT8_BIT_DEV_ADDR_CLEAR; + } + + card->hw_iface.bus_read_2(card->hw, + AFT_MCPU_INTERFACE_ADDR, + (u16*)&org_off); + + card->hw_iface.bus_write_2(card->hw,AFT_MCPU_INTERFACE_ADDR, (u16)off); + + + /* AF: Sep 10, 2003 + * IMPORTANT + * This delays are required to avoid bridge optimization + * (combining two writes together) + */ + if (!qaccess){ + WP_DELAY(5); + } + + card->hw_iface.bus_write_1(card->hw,AFT_MCPU_INTERFACE, (u8)value); + if (!qaccess){ + WP_DELAY(5); + } + + card->hw_iface.bus_write_2(card->hw, + AFT_MCPU_INTERFACE_ADDR, + org_off); + + + if (!qaccess){ + WP_DELAY(5); + } + + return 0; +} + +int a104_write_fe (void *pcard, ...) +{ + va_list args; + sdla_t *card = (sdla_t*)pcard; + int off, value; + + if (card->hw_iface.fe_test_and_set_bit(card->hw)){ + if (WAN_NET_RATELIMIT()){ + DEBUG_EVENT( + "%s: %s:%d: Critical Error: Re-entry in FE!\n", + card->devname, + __FUNCTION__,__LINE__); + } + return -EINVAL; + } + + va_start(args, pcard); + off = va_arg(args, int); + value = va_arg(args, int); + va_end(args); + + __a104_write_fe(card, off, value); + + card->hw_iface.fe_clear_bit(card->hw); + return 0; +} + + +/*============================================================================ + * Read TE1/56K Front end registers + */ +unsigned char __a104_read_fe (void *pcard, ...) +{ + va_list args; + sdla_t *card = (sdla_t*)pcard; + int org_off, off, tmp; + u8 qaccess = card->wandev.state == WAN_CONNECTED ? 1 : 0; + + va_start(args, pcard); + off = (int)va_arg(args, int); + va_end(args); + + if (card->adptr_type == A104_ADPTR_4TE1) { + off &= ~AFT4_BIT_DEV_ADDR_CLEAR; + }else{ + if (off & 0x800) off |= 0x2000; + if (off & 0x1000) off |= 0x4000; + off &= ~AFT8_BIT_DEV_ADDR_CLEAR; + } + + card->hw_iface.bus_read_2(card->hw, + AFT_MCPU_INTERFACE_ADDR, + (u16*)&org_off); + + card->hw_iface.bus_write_2(card->hw, AFT_MCPU_INTERFACE_ADDR, (u16)off); + + card->hw_iface.bus_read_1(card->hw,AFT_MCPU_INTERFACE, (u8*)&tmp); + if (!qaccess){ + WP_DELAY(5); + } + + card->hw_iface.bus_write_2(card->hw, + AFT_MCPU_INTERFACE_ADDR, + (u16)org_off); + + if (!qaccess){ + WP_DELAY(5); + } + + return tmp; +} +unsigned char a104_read_fe (void *pcard, ...) +{ + va_list args; + sdla_t *card = (sdla_t*)pcard; + int off; + unsigned char tmp; + + if (card->hw_iface.fe_test_and_set_bit(card->hw)){ + if (WAN_NET_RATELIMIT()){ + DEBUG_EVENT("%s: %s:%d: Critical Error: Re-entry in FE!\n", + card->devname, __FUNCTION__,__LINE__); + } + return 0x00; + } + + va_start(args, pcard); + off = (int)va_arg(args, int); + va_end(args); + + tmp = __a104_read_fe(card, off); + + card->hw_iface.fe_clear_bit(card->hw); + return tmp; +} + + +unsigned char a104_read_cpld(sdla_t *card, unsigned short cpld_off) +{ + u8 tmp; + int err = -EINVAL; + + if (card->hw_iface.fe_test_and_set_bit(card->hw)){ + DEBUG_EVENT("%s: %s:%d: Critical Error: Re-entry in FE!\n", + card->devname, __FUNCTION__,__LINE__); + return 0x00; + } + +#if 1 + if (card->hw_iface.read_cpld){ + err = card->hw_iface.read_cpld(card->hw, (u16)cpld_off, &tmp); + } +#else + if (card->adptr_type == A104_ADPTR_4TE1) { + cpld_off |= AFT4_BIT_DEV_ADDR_CPLD; + }else{ + cpld_off &= ~AFT8_BIT_DEV_ADDR_CLEAR; + cpld_off |= AFT8_BIT_DEV_ADDR_CPLD; + } + + /*ALEX: Save the current address. */ + card->hw_iface.bus_read_2(card->hw, + AFT_MCPU_INTERFACE_ADDR, + &org_off); + + card->hw_iface.bus_write_2(card->hw, + AFT_MCPU_INTERFACE_ADDR, + cpld_off); + + card->hw_iface.bus_read_1(card->hw,AFT_MCPU_INTERFACE, &tmp); + + /*ALEX: Restore original address */ + card->hw_iface.bus_write_2(card->hw, + AFT_MCPU_INTERFACE_ADDR, + org_off); +#endif + card->hw_iface.fe_clear_bit(card->hw); + return tmp; +} + +int a104_write_cpld(sdla_t *card, unsigned short off,unsigned char data) +{ + int err = -EINVAL; + + if (card->hw_iface.fe_test_and_set_bit(card->hw)){ + DEBUG_EVENT("%s: %s:%d: Critical Error: Re-entry in FE!\n", + card->devname, __FUNCTION__,__LINE__); + return 0x00; + } + +#if 1 + if (card->hw_iface.write_cpld){ + err = card->hw_iface.write_cpld(card->hw, (u16)off, (u8)data); + } +#else + if (card->adptr_type == A104_ADPTR_4TE1) { + off |= AFT4_BIT_DEV_ADDR_CPLD; + }else{ + off &= ~AFT8_BIT_DEV_ADDR_CLEAR; + off |= AFT8_BIT_DEV_ADDR_CPLD; + } + + /*ALEX: Save the current original address */ + card->hw_iface.bus_read_2(card->hw, + AFT_MCPU_INTERFACE_ADDR, + &org_off); + + /* This delay is required to avoid bridge optimization + * (combining two writes together)*/ + WP_DELAY(5); + + card->hw_iface.bus_write_2(card->hw, + AFT_MCPU_INTERFACE_ADDR, + off); + + /* This delay is required to avoid bridge optimization + * (combining two writes together)*/ + WP_DELAY(5); + + card->hw_iface.bus_write_1(card->hw, + AFT_MCPU_INTERFACE, + data); + /*ALEX: Restore the original address */ + card->hw_iface.bus_write_2(card->hw, + AFT_MCPU_INTERFACE_ADDR, + org_off); +#endif + card->hw_iface.fe_clear_bit(card->hw); + return 0; +} + +unsigned char a108m_read_cpld(sdla_t *card, unsigned short cpld_off) +{ + u16 org_off; + u8 tmp; + + if (card->hw_iface.fe_test_and_set_bit(card->hw)){ + DEBUG_EVENT("%s: %s:%d: Critical Error: Re-entry in FE!\n", + card->devname, __FUNCTION__,__LINE__); + return 0x00; + } + cpld_off &= ~AFT8_BIT_DEV_ADDR_CLEAR; + cpld_off |= AFT8_BIT_DEV_MAXIM_ADDR_CPLD; + + /*ALEX: Save the current address. */ + card->hw_iface.bus_read_2(card->hw, + AFT_MCPU_INTERFACE_ADDR, + &org_off); + + card->hw_iface.bus_write_2(card->hw, + AFT_MCPU_INTERFACE_ADDR, + cpld_off); + + card->hw_iface.bus_read_1(card->hw,AFT_MCPU_INTERFACE, &tmp); + + /*ALEX: Restore original address */ + card->hw_iface.bus_write_2(card->hw, + AFT_MCPU_INTERFACE_ADDR, + org_off); + card->hw_iface.fe_clear_bit(card->hw); + return tmp; +} + +int a108m_write_cpld(sdla_t *card, unsigned short off,unsigned char data) +{ + u16 org_off; + + if (card->hw_iface.fe_test_and_set_bit(card->hw)){ + DEBUG_EVENT("%s: %s:%d: Critical Error: Re-entry in FE!\n", + card->devname, __FUNCTION__,__LINE__); + return 0x00; + } + + off &= ~AFT8_BIT_DEV_ADDR_CLEAR; + off |= AFT8_BIT_DEV_MAXIM_ADDR_CPLD; + + /*ALEX: Save the current original address */ + card->hw_iface.bus_read_2(card->hw, + AFT_MCPU_INTERFACE_ADDR, + &org_off); + + /* This delay is required to avoid bridge optimization + * (combining two writes together)*/ + WP_DELAY(5); + + card->hw_iface.bus_write_2(card->hw, + AFT_MCPU_INTERFACE_ADDR, + off); + + /* This delay is required to avoid bridge optimization + * (combining two writes together)*/ + WP_DELAY(5); + + card->hw_iface.bus_write_1(card->hw, + AFT_MCPU_INTERFACE, + data); + /*ALEX: Restore the original address */ + card->hw_iface.bus_write_2(card->hw, + AFT_MCPU_INTERFACE_ADDR, + org_off); + card->hw_iface.fe_clear_bit(card->hw); + return 0; +} + + +void a104_fifo_adjust(sdla_t *card,u32 level) +{ + u32 fifo_size,reg; + card->hw_iface.bus_read_4(card->hw, AFT_FIFO_MARK_REG, &fifo_size); + + aft_fifo_mark_gset(®,level); + + if (fifo_size == reg){ + return; + } + + card->hw_iface.bus_write_4(card->hw, AFT_FIFO_MARK_REG, reg); + DEBUG_EVENT("%s: Fifo Level Map:0x%08X\n",card->devname,reg); +} + +#if defined(CONFIG_WANPIPE_HWEC) +static int a104_hwec_reset(void *pcard, int reset) +{ + sdla_t *card = (sdla_t*)pcard; + wan_smp_flag_t smp_flags; + wan_smp_flag_t flags; + int err = -EINVAL; + + card->hw_iface.hw_lock(card->hw,&smp_flags); + wan_spin_lock_irq(&card->wandev.lock,&flags); + if (!reset){ + DEBUG_EVENT("%s: Clear Echo Canceller chip reset.\n", + card->devname); + + if (card->adptr_type == A108_ADPTR_8TE1) { + a104_write_cpld(card,0x00,0x07); + }else{ + + if (IS_T1_CARD(card)){ + // a104_write_cpld(card, 0x00, 0x00); + // WP_DELAY(1000); + a104_write_cpld(card, 0x00, 0x01); + }else{ + // a104_write_cpld(card,0x00, 0x02); + // WP_DELAY(1000); + a104_write_cpld(card,0x00, 0x03); + } + } + WP_DELAY(1000); + err = 0; + + }else{ + DEBUG_EVENT("%s: Set Echo Canceller chip reset.\n", + card->devname); + if (card->adptr_type == A108_ADPTR_8TE1) { + a104_write_cpld(card,0x00,0x06); + }else{ + + if (IS_T1_CARD(card)){ + a104_write_cpld(card, 0x00, 0x00); + }else{ + a104_write_cpld(card,0x00, 0x02); + } + } + err = 0; + } + wan_spin_unlock_irq(&card->wandev.lock,&flags); + card->hw_iface.hw_unlock(card->hw,&smp_flags); + return err; +} +#endif + +#if defined(CONFIG_WANPIPE_HWEC) +static int a104_hwec_enable(void *pcard, int enable, int channel) +{ + sdla_t *card = (sdla_t*)pcard; + unsigned int value; + + WAN_ASSERT(card == NULL); + if(!wan_test_bit(channel, &card->wandev.ec_enable_map)){ + return -EINVAL; + } + DEBUG_TEST("[HWEC]: %s: %s bypass mode for channel %d!\n", + card->devname, + (enable) ? "Enable" : "Disable", + channel); + + card->hw_iface.bus_read_4( + card->hw, + AFT_PORT_REG(card,0x1000) + channel * 4, + &value); + if (enable){ + wan_set_bit(channel,&card->wandev.ec_map); + value |= 0x20; + }else{ + wan_clear_bit(channel,&card->wandev.ec_map); + value &= ~0x20; + } + card->hw_iface.bus_write_4( + card->hw, + AFT_PORT_REG(card,0x1000) + channel * 4, + value); + + return 0; +} +#endif diff -Nur linux.org/drivers/net/wan/aft_analog.c linux-2.6.17/drivers/net/wan/aft_analog.c --- linux.org/drivers/net/wan/aft_analog.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/drivers/net/wan/aft_analog.c 2006-08-30 10:07:16.000000000 +0000 @@ -0,0 +1,1179 @@ +/***************************************************************************** +* aft_aft_analog.c +* +* WANPIPE(tm) AFT A104 Hardware Support +* +* Authors: Nenad Corbic +* +* Copyright: (c) 2003-2005 Sangoma Technologies Inc. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version +* 2 of the License, or (at your option) any later version. +* ============================================================================ +* Sep 25, 2005 Nenad Corbic Initial Version +*****************************************************************************/ + +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) +# include +# include +# include +# include /* Socket Driver common area */ +# include +//# include +# include +# include +# include +#else +# include +# include +# include +# include +# include +# include /* Socket Driver common area */ +# include +# include +//# include +# include +# include +# include +# include +#endif + +/*============================================== + * PRIVATE FUNCITONS + * + */ +#if defined(CONFIG_WANPIPE_HWEC) +static int aft_analog_hwec_reset(void *pcard, int reset); +static int aft_analog_hwec_enable(void *pcard, int enable, int channel); +#endif + +static int aft_map_fifo_baddr_and_size(sdla_t *card, unsigned char fifo_size, unsigned char *addr); + +static char fifo_size_vector[] = {1, 2, 4, 8, 16, 32}; +static char fifo_code_vector[] = {0, 1, 3, 7,0xF,0x1F}; + +static int request_fifo_baddr_and_size(sdla_t *card, private_area_t *chan) +{ + unsigned char req_fifo_size,fifo_size; + int i; + + /* Calculate the optimal fifo size based + * on the number of time slots requested */ + + req_fifo_size = 1; + + DEBUG_TEST("%s:%s: Optimal Fifo Size =%d Timeslots=%d \n", + card->devname,chan->if_name,req_fifo_size,chan->num_of_time_slots); + + fifo_size=aft_map_fifo_baddr_and_size(card,req_fifo_size,&chan->fifo_base_addr); + if (fifo_size == 0 || chan->fifo_base_addr == 31){ + DEBUG_EVENT("%s:%s: Error: Failed to obtain fifo size %d or addr %d \n", + card->devname,chan->if_name,fifo_size,chan->fifo_base_addr); + return -EINVAL; + } + + DEBUG_TEST("%s:%s: Optimal Fifo Size =%d Timeslots=%d New Fifo Size=%d \n", + card->devname,chan->if_name,req_fifo_size,chan->num_of_time_slots,fifo_size); + + + for (i=0;ififo_size_code=fifo_code_vector[i]; + break; + } + } + + if (fifo_size != req_fifo_size){ + DEBUG_EVENT("%s:%s: Warning: Failed to obtain the req fifo %d got %d\n", + card->devname,chan->if_name,req_fifo_size,fifo_size); + } + + DEBUG_TEST("%s: %s:Fifo Size=%d Timeslots=%d Fifo Code=%d Addr=%d\n", + card->devname,chan->if_name,fifo_size, + chan->num_of_time_slots,chan->fifo_size_code, + chan->fifo_base_addr); + + chan->fifo_size = fifo_size; + + return 0; +} + + +static int aft_map_fifo_baddr_and_size(sdla_t *card, unsigned char fifo_size, unsigned char *addr) +{ + u32 reg=0; + int i; + + for (i=0;idevname,reg,card->u.aft.fifo_addr_map); + + for (i=0;i<32;i+=fifo_size){ + if (card->u.aft.fifo_addr_map & (reg<u.aft.fifo_addr_map |= reg<devname,card->u.aft.fifo_addr_map,i); + + return fifo_size; + } + + if (fifo_size == 1){ + return 0; + } + + fifo_size = fifo_size >> 1; + + return aft_map_fifo_baddr_and_size(card,fifo_size,addr); +} + + +static int aft_free_fifo_baddr_and_size (sdla_t *card, private_area_t *chan) +{ + u32 reg=0; + int i; + + for (i=0;ififo_size;i++){ + wan_set_bit(i,®); + } + + DEBUG_TEST("%s: Unmapping 0x%X from 0x%lX\n", + card->devname,reg<fifo_base_addr, card->u.aft.fifo_addr_map); + + card->u.aft.fifo_addr_map &= ~(reg<fifo_base_addr); + + DEBUG_TEST("%s: New Map is 0x%lX\n", + card->devname, card->u.aft.fifo_addr_map); + + + chan->fifo_size=0; + chan->fifo_base_addr=0; + + return 0; +} + + +static char aft_request_logical_channel_num (sdla_t *card, private_area_t *chan) +{ + signed char logic_ch=-1; + int err; + long i; + int timeslots=0; + + DEBUG_TEST("-- Request_Xilinx_logic_channel_num:--\n"); + + DEBUG_TEST("%s:%d Global Num Timeslots=%d Global Logic ch Map 0x%lX \n", + __FUNCTION__,__LINE__, + card->u.aft.num_of_time_slots, + card->u.aft.logic_ch_map); + + + /* Check that the time slot is not being used. If it is + * stop the interface setup. Notice, though we proceed + * to check for all timeslots before we start binding + * the channels in. This way, we don't have to go back + * and clean the time_slot_map */ + for (i=0;iu.aft.num_of_time_slots;i++){ + if (wan_test_bit(i,&chan->time_slot_map)){ + + if (chan->first_time_slot == -1){ + DEBUG_EVENT("%s: First TSlot :%ld\n", + card->devname,i); + chan->first_time_slot=i; + } + + chan->last_time_slot=i; + + DEBUG_CFG("%s: Configuring %s for timeslot %ld\n", + card->devname, chan->if_name,i+1); + + if (wan_test_bit(i,&card->u.xilinx.time_slot_map)){ + DEBUG_EVENT("%s: Channel/Time Slot resource conflict!\n", + card->devname); + DEBUG_EVENT("%s: %s: Channel/Time Slot %ld, aready in use!\n", + card->devname,chan->if_name,(i+1)); + + return -EEXIST; + } + timeslots++; + } + } + + if (timeslots > 1){ + DEBUG_EVENT("%s: Error: Analog Interface can only support a single timeslot\n", + card->devname); + chan->first_time_slot = -1; + return -1; + } + + + err=request_fifo_baddr_and_size(card,chan); + if (err){ + return -1; + } + + logic_ch = chan->first_time_slot; + + if (wan_test_and_set_bit(logic_ch,&card->u.aft.logic_ch_map)){ + return -1; + } + + if (logic_ch == -1){ + return logic_ch; + } + + for (i=0;iu.aft.num_of_time_slots;i++){ + if (!wan_test_bit(i,&card->u.aft.logic_ch_map)){ + break; + } + } + + if (card->u.aft.dev_to_ch_map[(unsigned char)logic_ch]){ + DEBUG_EVENT("%s: Error, request logical ch=%d map busy\n", + card->devname,logic_ch); + return -1; + } + + card->u.aft.dev_to_ch_map[(unsigned char)logic_ch]=(void*)chan; + + if (logic_ch >= card->u.aft.top_logic_ch){ + card->u.aft.top_logic_ch=logic_ch; + aft_dma_max_logic_ch(card); + } + + + DEBUG_TEST("Binding logic ch %d Ptr=%p\n",logic_ch,chan); + return logic_ch; +} + + + +/*============================================== + * PUBLIC FUNCITONS + * + */ + +int aft_analog_test_sync(sdla_t *card, int tx_only) +{ + volatile int i,err=1; + u32 reg; + + card->hw_iface.bus_read_4(card->hw,AFT_PORT_REG(card,AFT_LINE_CFG_REG), ®); + + if (wan_test_bit(AFT_LCFG_FE_IFACE_RESET_BIT,®)){ + DEBUG_EVENT("%s: Warning: PMC Reset Enabled %d! \n", + card->devname, card->wandev.comm_port+1); + } + + + for (i=0;i<500;i++){ + + card->hw_iface.bus_read_4(card->hw,AFT_PORT_REG(card,AFT_LINE_CFG_REG), ®); + if (tx_only){ + if (wan_test_bit(AFT_LCFG_TX_FE_SYNC_STAT_BIT,®)){ + err=-1; + WP_DELAY(200); + }else{ + err=0; + break; + } + }else{ + if (wan_test_bit(AFT_LCFG_TX_FE_SYNC_STAT_BIT,®) || + wan_test_bit(AFT_LCFG_RX_FE_SYNC_STAT_BIT,®)){ + err=-1; + WP_DELAY(200); + }else{ + err=0; + break; + } + } + } + + DEBUG_TEST("%s: DELAY INDEX = %i\n", + card->devname,i); + + return err; +} + +int aft_analog_led_ctrl(sdla_t *card, int color, int led_pos, int on) +{ + + /* NO LED ON ANALOG CARD */ + return 0; +} + + +int aft_analog_global_chip_config(sdla_t *card) +{ + u32 reg; + int err; + + /*============ GLOBAL CHIP CONFIGURATION ===============*/ + card->hw_iface.bus_read_4(card->hw,AFT_CHIP_CFG_REG, ®); + + /* Enable the chip/hdlc reset condition */ + reg=0; + wan_set_bit(AFT_CHIPCFG_SFR_EX_BIT,®); + wan_set_bit(AFT_CHIPCFG_SFR_IN_BIT,®); + + DEBUG_CFG("--- AFT Chip Reset. -- \n"); + + card->hw_iface.bus_write_4(card->hw,AFT_CHIP_CFG_REG,reg); + + WP_DELAY(10); + + /* Disable the chip/hdlc reset condition */ + wan_clear_bit(AFT_CHIPCFG_SFR_EX_BIT,®); + wan_clear_bit(AFT_CHIPCFG_SFR_IN_BIT,®); + wan_clear_bit(AFT_CHIPCFG_FE_INTR_CFG_BIT,®); +#if 0 + wan_set_bit(AFT_CHIPCFG_SPI_SLOW_BIT,®); +#endif + DEBUG_CFG("--- Chip enable/config. -- \n"); + + card->hw_iface.bus_write_4(card->hw,AFT_CHIP_CFG_REG,reg); + + /* Set Octasic reset */ + aft_analog_write_cpld(card, 0x00, 0x00); + + DEBUG_EVENT("%s: Global Front End Configuraton!\n",card->devname); + err = -EINVAL; +#ifndef CONFIG_PRODUCT_WANPIPE_TDM_VOICE + DEBUG_EVENT("%s: Error: Analog card only supported in TDM mode!\n", + card->devname); +#else + if (card->wandev.fe_iface.config){ + err = card->wandev.fe_iface.config(&card->fe); + } +#endif + if (err){ + DEBUG_EVENT("%s: Failed Front End configuration!\n", + card->devname); + return -EINVAL; + }else{ + DEBUG_EVENT("%s: Remora config done!\n",card->devname); + } + card->hw_iface.bus_write_4(card->hw,AFT_CHIP_CFG_REG,reg); + wan_set_bit(AFT_CHIPCFG_FE_INTR_CFG_BIT,®); + card->hw_iface.bus_write_4(card->hw,AFT_CHIP_CFG_REG,reg); + + return 0; +} + +int aft_analog_global_chip_unconfig(sdla_t *card) +{ + u32 reg=0; + +#ifdef CONFIG_PRODUCT_WANPIPE_TDM_VOICE + if (card->wandev.fe_iface.unconfig){ + card->wandev.fe_iface.unconfig(&card->fe); + } +#endif + + /* Set Octasic to reset */ +#if 0 + aft_analog_write_cpld(card, 0x00, 0x00); +#endif + /* Disable the chip/hdlc reset condition */ + wan_set_bit(AFT_CHIPCFG_SFR_EX_BIT,®); + wan_set_bit(AFT_CHIPCFG_SFR_IN_BIT,®); + + card->hw_iface.bus_write_4(card->hw,AFT_CHIP_CFG_REG,reg); + + return 0; +} + +int aft_analog_chip_config(sdla_t *card) +{ + u32 reg=0; + int err=0; + + card->hw_iface.bus_read_4(card->hw,AFT_PORT_REG(card,AFT_LINE_CFG_REG), ®); + if (!wan_test_bit(AFT_LCFG_FE_IFACE_RESET_BIT,®)){ + DEBUG_EVENT("%s: Error: Physical Port %i is busy! \n", + card->devname, card->wandev.comm_port+1); + return -EBUSY; + } + + + /*============ LINE/PORT CONFIG REGISTER ===============*/ + + card->hw_iface.bus_read_4(card->hw, + AFT_PORT_REG(card,AFT_LINE_CFG_REG),®); + wan_set_bit(AFT_LCFG_FE_IFACE_RESET_BIT,®); + card->hw_iface.bus_write_4(card->hw,AFT_PORT_REG(card,AFT_LINE_CFG_REG),reg); + + WP_DELAY(10); + + wan_clear_bit(AFT_LCFG_FE_IFACE_RESET_BIT,®); + card->hw_iface.bus_write_4(card->hw,AFT_PORT_REG(card,AFT_LINE_CFG_REG),reg); + + WP_DELAY(10); + + err=aft_analog_test_sync(card,1); + + card->hw_iface.bus_read_4(card->hw,AFT_PORT_REG(card,AFT_LINE_CFG_REG),®); + if (err != 0){ + DEBUG_EVENT("%s: Error: Front End Interface Not Ready (0x%08X)!\n", + card->devname,reg); + return err; + } else{ + DEBUG_EVENT("%s: Front End Interface Ready 0x%08X\n", + card->devname,reg); + } + + /* Enable Octasic Chip */ + if (card->adptr_subtype == AFT_SUBTYPE_SHARK){ + u16 max_ec_chans; + u32 cfg_reg; + + card->hw_iface.getcfg(card->hw, SDLA_HWEC_NO, &max_ec_chans); + + card->hw_iface.bus_read_4(card->hw,AFT_CHIP_CFG_REG, &cfg_reg); + if (max_ec_chans > aft_chipcfg_get_a200_ec_channels(cfg_reg)){ + DEBUG_EVENT( + "%s: Critical Error: Exceeded Maximum Available Echo Channels!\n", + card->devname); + DEBUG_EVENT( + "%s: Critical Error: Max Allowed=%d Configured=%d (%X)\n", + card->devname, + aft_chipcfg_get_a200_ec_channels(cfg_reg), + max_ec_chans, + cfg_reg); + return -EINVAL; + } + + if (max_ec_chans){ +#if defined(CONFIG_WANPIPE_HWEC) + card->wandev.ec_dev = wanpipe_ec_register(card, max_ec_chans); + card->wandev.hwec_reset = aft_analog_hwec_reset; + card->wandev.hwec_enable = aft_analog_hwec_enable; +#else + DEBUG_EVENT("%s: Wanpipe HW Echo Canceller modele is not compiled!\n", + card->devname); +#endif + }else{ + DEBUG_EVENT( + "%s: WARNING: No Echo Canceller channels are available!\n", + card->devname); + } + } + + /* Enable only Front End Interrupt + * Wait for front end to come up before enabling DMA */ + card->hw_iface.bus_read_4(card->hw,AFT_PORT_REG(card,AFT_LINE_CFG_REG), ®); + wan_clear_bit(AFT_LCFG_DMA_INTR_BIT,®); + wan_clear_bit(AFT_LCFG_FIFO_INTR_BIT,®); + wan_clear_bit(AFT_LCFG_TDMV_INTR_BIT,®); + + card->hw_iface.bus_write_4(card->hw,AFT_PORT_REG(card,AFT_LINE_CFG_REG), reg); + card->u.aft.lcfg_reg=reg; + + aft_analog_led_ctrl(card, WAN_AFT_RED, 0,WAN_AFT_ON); + aft_analog_led_ctrl(card, WAN_AFT_GREEN, 0, WAN_AFT_OFF); + + + /*============ DMA CONTROL REGISTER ===============*/ + + /* Disable Global DMA because we will be + * waiting for the front end to come up */ + reg=0; + aft_dmactrl_set_max_logic_ch(®,0); + wan_clear_bit(AFT_DMACTRL_GLOBAL_INTR_BIT,®); + card->hw_iface.bus_write_4(card->hw,AFT_PORT_REG(card,AFT_DMA_CTRL_REG),reg); + + + + + /*============ ENABLE MUX ==================*/ + + reg=0; /* 0xFFFFFFFF; */ + card->hw_iface.bus_write_4(card->hw,AFT_ANALOG_DATA_MUX_CTRL_REG,reg); + + + aft_wdt_reset(card); +#if 0 +/*FIXME: NC Dont need watchdog */ + aft_wdt_set(card,AFT_WDTCTRL_TIMEOUT); +#endif + + return 0; +} + +int aft_analog_chip_unconfig(sdla_t *card) +{ + u32 reg=0; + + aft_wdt_reset(card); + + /* Disable Octasic Chip */ + if (card->adptr_subtype == AFT_SUBTYPE_SHARK){ + if (card->wandev.ec_dev){ +#if defined(CONFIG_WANPIPE_HWEC) + wanpipe_ec_unregister(card->wandev.ec_dev, card); +#else + DEBUG_EVENT( + "%s: Wanpipe HW Echo Canceller modele is not compiled!\n", + card->devname); +#endif + } + card->wandev.hwec_enable = NULL; + card->wandev.ec_dev = NULL; + } + + wan_set_bit(AFT_LCFG_FE_IFACE_RESET_BIT,®); + card->hw_iface.bus_write_4(card->hw,AFT_PORT_REG(card,AFT_LINE_CFG_REG),reg); + + return 0; +} + +int aft_analog_chan_dev_config(sdla_t *card, void *chan_ptr) +{ + u32 reg; + private_area_t *chan = (private_area_t*)chan_ptr; + u32 dma_ram_reg; + + + chan->logic_ch_num=aft_request_logical_channel_num(card, chan); + if (chan->logic_ch_num == -1){ + return -EBUSY; + } + + dma_ram_reg=AFT_PORT_REG(card,AFT_DMA_CHAIN_RAM_BASE_REG); + dma_ram_reg+=(chan->logic_ch_num*4); + + reg=0; + card->hw_iface.bus_write_4(card->hw, dma_ram_reg, reg); + + card->hw_iface.bus_read_4(card->hw, dma_ram_reg, ®); + + aft_dmachain_set_fifo_size(®, chan->fifo_size_code); + aft_dmachain_set_fifo_base(®, chan->fifo_base_addr); + + /* Initially always disable rx synchronization */ + wan_clear_bit(AFT_DMACHAIN_RX_SYNC_BIT,®); + + if (chan->channelized_cfg && !chan->hdlc_eng){ + aft_dmachain_enable_tdmv_and_mtu_size(®,chan->mru); + } + + card->hw_iface.bus_write_4(card->hw, dma_ram_reg, reg); + + reg=0; + + if (chan->channelized_cfg && !chan->hdlc_eng){ + + card->hw_iface.bus_read_4(card->hw,AFT_PORT_REG(card,AFT_LINE_CFG_REG),®); + aft_lcfg_tdmv_cnt_inc(®); + + card->hw_iface.bus_write_4(card->hw,AFT_PORT_REG(card,AFT_LINE_CFG_REG),reg); + card->u.aft.lcfg_reg=reg; + } + + return 0; +} + +int aft_analog_chan_dev_unconfig(sdla_t *card, void *chan_ptr) +{ + private_area_t *chan = (private_area_t *)chan_ptr; + u32 dma_ram_reg,reg; + volatile int i; + + /* Select an HDLC logic channel for configuration */ + if (chan->logic_ch_num != -1){ + + dma_ram_reg=AFT_PORT_REG(card,AFT_DMA_CHAIN_RAM_BASE_REG); + dma_ram_reg+=(chan->logic_ch_num*4); + + card->hw_iface.bus_read_4(card->hw, dma_ram_reg, ®); + + aft_dmachain_set_fifo_base(®,0x1F); + aft_dmachain_set_fifo_size(®,0); + card->hw_iface.bus_write_4(card->hw, dma_ram_reg, reg); + + + aft_free_logical_channel_num(card,chan->logic_ch_num); + aft_free_fifo_baddr_and_size(card,chan); + + for (i=0;iu.xilinx.num_of_time_slots;i++){ + if (wan_test_bit(i,&chan->time_slot_map)){ + wan_clear_bit(i,&card->u.xilinx.time_slot_map); + } + } + + if (chan->channelized_cfg && !chan->hdlc_eng){ + card->hw_iface.bus_read_4(card->hw, + AFT_PORT_REG(card,AFT_LINE_CFG_REG),®); + aft_lcfg_tdmv_cnt_dec(®); + card->hw_iface.bus_write_4(card->hw, + AFT_PORT_REG(card,AFT_LINE_CFG_REG),reg); + } + + chan->logic_ch_num=-1; + } + + return 0; +} + +int a200_check_ec_security(sdla_t *card) +{ + u32 cfg_reg; + + card->hw_iface.bus_read_4(card->hw,AFT_CHIP_CFG_REG, &cfg_reg); + if (wan_test_bit(AFT_CHIPCFG_A200_EC_SECURITY_BIT,&cfg_reg)){ + return 1; + } + return 0; +} + +/*============================================================================ + * Read TE1/56K Front end registers + */ +int __aft_analog_write_fe (void* pcard, ...) +{ + va_list args; + sdla_t *card = (sdla_t*)pcard; + int mod_no, type, chain; + int reg, value; + u32 data = 0; + unsigned char cs = 0x00, ctrl_byte = 0x00; + int i; + + WAN_ASSERT(card == NULL); + WAN_ASSERT(card->hw_iface.bus_write_4 == NULL); + WAN_ASSERT(card->hw_iface.bus_read_4 == NULL); + + va_start(args, pcard); + mod_no = va_arg(args, int); + type = va_arg(args, int); + chain = va_arg(args, int); + reg = va_arg(args, int); + value = va_arg(args, int); + va_end(args); +#if 0 + if (!wan_test_bit(mod_no, card->fe.fe_param.remora.module_map)){ + DEBUG_EVENT("%s: %s:%d: Internal Error: Module %d\n", + card->devname, __FUNCTION__,__LINE__,mod_no); + return -EINVAL; + } +#endif + DEBUG_RM("%s:%d: Module %d: Write Remora Front-End code (reg %d, value %02X)!\n", + __FUNCTION__,__LINE__, + mod_no, reg, (u8)value); + + /* bit 0-7: data byte */ + data = value & 0xFF; + if (type == MOD_TYPE_FXO){ + + /* bit 8-15: register number */ + data |= (reg & 0xFF) << 8; + + /* bit 16-23: chip select byte + ** bit 16 + ** + ** + ** */ + cs = 0x20; + cs |= MOD_SPI_CS_FXO_WRITE; + if (mod_no % 2 == 0){ + /* Select second chip in a chain */ + cs |= MOD_SPI_CS_FXO_CHIP_1; + } + data |= (cs & 0xFF) << 16; + + /* bit 24-31: ctrl byte + ** bit 24 + ** + ** + ** */ + ctrl_byte = mod_no / 2; +#if !defined(SPI2STEP) + if (card->u.aft.firm_ver > 3){ + ctrl_byte |= MOD_SPI_CTRL_START; + }else{ + ctrl_byte |= MOD_SPI_CTRL_V3_START; + } +#endif + ctrl_byte |= MOD_SPI_CTRL_CHAIN; /* always chain */ + data |= ctrl_byte << 24; + + }else if (type == MOD_TYPE_FXS){ + + /* bit 8-15: register byte */ + reg = reg & 0x7F; + reg |= MOD_SPI_ADDR_FXS_WRITE; + data |= (reg & 0xFF) << 8; + + /* bit 16-23: chip select byte + ** bit 16 + ** + ** + ** */ + if (mod_no % 2){ + /* Select first chip in a chain */ + cs = MOD_SPI_CS_FXS_CHIP_0; + }else{ + /* Select second chip in a chain */ + cs = MOD_SPI_CS_FXS_CHIP_1; + } + data |= cs << 16; + + /* bit 24-31: ctrl byte + ** bit 24 + ** + ** + ** */ + ctrl_byte = mod_no / 2; +#if !defined(SPI2STEP) + if (card->u.aft.firm_ver > 3){ + ctrl_byte |= MOD_SPI_CTRL_START; + }else{ + ctrl_byte |= MOD_SPI_CTRL_V3_START; + } +#endif + ctrl_byte |= MOD_SPI_CTRL_FXS; + if (chain){ + ctrl_byte |= MOD_SPI_CTRL_CHAIN; + } + data |= ctrl_byte << 24; + + }else{ + DEBUG_EVENT("%s: Module %d: Unsupported module type %d!\n", + card->devname, mod_no, type); + return -EINVAL; + } + + card->hw_iface.bus_write_4( card->hw, + SPI_INTERFACE_REG, + data); +#if defined(SPI2STEP) + WP_DELAY(1); + if (card->u.aft.firm_ver > 3){ + data |= MOD_SPI_START; + }else{ + data |= MOD_SPI_V3_START; + } + card->hw_iface.bus_write_4( card->hw, + SPI_INTERFACE_REG, + data); +#endif +#if 0 + DEBUG_EVENT("%s: %s: Module %d - Execute SPI command %08X\n", + card->fe.name, + __FUNCTION__, + mod_no, + data); +#endif + + for (i=0;i<10;i++){ + WP_DELAY(10); + card->hw_iface.bus_read_4( card->hw, + SPI_INTERFACE_REG, + &data); + + if (data & MOD_SPI_BUSY){ + continue; + } + } + + if (data & MOD_SPI_BUSY) { + DEBUG_EVENT("%s: Module %d: Critical Error (%s:%d)!\n", + card->devname, mod_no, + __FUNCTION__,__LINE__); + return -EINVAL; + } + return 0; +} +int aft_analog_write_fe (void* pcard, ...) +{ + va_list args; + sdla_t *card = (sdla_t*)pcard; + int mod_no, type, chain, reg, value; +#if defined(WAN_DEBUG_FE) + char *fname; + int fline; +#endif + + WAN_ASSERT(card == NULL); + WAN_ASSERT(card->hw_iface.bus_write_4 == NULL); + WAN_ASSERT(card->hw_iface.bus_read_4 == NULL); + + va_start(args, pcard); + mod_no = va_arg(args, int); + type = va_arg(args, int); + chain = va_arg(args, int); + reg = va_arg(args, int); + value = va_arg(args, int); +#if defined(WAN_DEBUG_FE) + fname = va_arg(args, char*); + fline = va_arg(args, int); +#endif + va_end(args); + + if (card->hw_iface.fe_test_and_set_bit(card->hw)){ +#if defined(WAN_DEBUG_FE) + DEBUG_EVENT("%s: %s:%d: Critical Error: Re-entry in FE (%s:%d)!\n", + card->devname, __FUNCTION__,__LINE__, fname, fline); +#else + DEBUG_EVENT("%s: %s:%d: Critical Error: Re-entry in FE!\n", + card->devname, __FUNCTION__,__LINE__); +#endif + return -EINVAL; + } + + __aft_analog_write_fe(card, mod_no, type, chain, reg, value); + + card->hw_iface.fe_clear_bit(card->hw); + return 0; +} + +unsigned char __aft_analog_read_fe (void* pcard, ...) +{ + va_list args; + sdla_t *card = (sdla_t*)pcard; + int mod_no, type, chain, reg; + u32 data = 0; + unsigned char cs = 0x00, ctrl_byte = 0x00; + int i; + + WAN_ASSERT(card == NULL); + WAN_ASSERT(card->hw_iface.bus_write_4 == NULL); + WAN_ASSERT(card->hw_iface.bus_read_4 == NULL); + + va_start(args, pcard); + mod_no = va_arg(args, int); + type = va_arg(args, int); + chain = va_arg(args, int); + reg = va_arg(args, int); + va_end(args); +#if 0 + if (!wan_test_bit(mod_no, card->fe.fe_param.remora.module_map)){ + DEBUG_EVENT("%s: %s:%d: Internal Error: Module %d\n", + card->devname, __FUNCTION__,__LINE__,mod_no); + return 0x00; + } +#endif + DEBUG_RM("%s:%d: %s: Module %d: Read Remora Front-End code (reg %d)!\n", + __FUNCTION__,__LINE__, + card->devname, mod_no, reg); + + /* bit 0-7: data byte */ + data = 0x00; + if (type == MOD_TYPE_FXO){ + + /* bit 8-15: register byte */ + data |= (reg & 0xFF) << 8; + + /* bit 16-23: chip select byte + ** bit 16 + ** + ** + ** */ + cs = 0x20; + cs |= MOD_SPI_CS_FXO_READ; + if (mod_no % 2 == 0){ + /* Select second chip in a chain */ + cs |= MOD_SPI_CS_FXO_CHIP_1; + } + data |= (cs & 0xFF) << 16; + + /* bit 24-31: ctrl byte + ** bit 24 + ** + ** + ** */ + ctrl_byte = mod_no / 2; +#if !defined(SPI2STEP) + if (card->u.aft.firm_ver > 3){ + ctrl_byte |= MOD_SPI_CTRL_START; + }else{ + ctrl_byte |= MOD_SPI_CTRL_V3_START; + } +#endif + ctrl_byte |= MOD_SPI_CTRL_CHAIN; /* always chain */ + data |= ctrl_byte << 24; + + }else if (type == MOD_TYPE_FXS){ + + /* bit 8-15: register byte */ + reg = reg & 0x7F; + reg |= MOD_SPI_ADDR_FXS_READ; + data |= (reg & 0xFF) << 8; + + /* bit 16-23: chip select byte + ** bit 16 + ** + ** + ** */ + if (mod_no % 2){ + /* Select first chip in a chain */ + cs = MOD_SPI_CS_FXS_CHIP_0; + }else{ + /* Select second chip in a chain */ + cs = MOD_SPI_CS_FXS_CHIP_1; + } + data |= cs << 16; + + /* bit 24-31: ctrl byte + ** bit 24 + ** + ** + ** */ + ctrl_byte = mod_no / 2; +#if !defined(SPI2STEP) + if (card->u.aft.firm_ver > 3){ + ctrl_byte |= MOD_SPI_CTRL_START; + }else{ + ctrl_byte |= MOD_SPI_CTRL_V3_START; + } +#endif + ctrl_byte |= MOD_SPI_CTRL_FXS; + if (chain){ + ctrl_byte |= MOD_SPI_CTRL_CHAIN; + } + data |= ctrl_byte << 24; + + }else{ + DEBUG_EVENT("%s: Module %d: Unsupported module type %d!\n", + card->devname, mod_no, type); + return -EINVAL; + } + + card->hw_iface.bus_write_4( card->hw, + SPI_INTERFACE_REG, + data); +#if defined(SPI2STEP) + WP_DELAY(1); + if (card->u.aft.firm_ver > 3){ + data |= MOD_SPI_START; + }else{ + data |= MOD_SPI_V3_START; + } + card->hw_iface.bus_write_4( card->hw, + SPI_INTERFACE_REG, + data); +#endif +#if 0 + DEBUG_EVENT("%s: %s: Module %d - Execute SPI command %08X\n", + card->fe.name, + __FUNCTION__, + mod_no, + data); +#endif + for (i=0;i<10;i++){ + WP_DELAY(10); + card->hw_iface.bus_read_4( card->hw, + SPI_INTERFACE_REG, + &data); + if (data & MOD_SPI_BUSY) { + continue; + } + } + + if (data & MOD_SPI_BUSY){ + DEBUG_EVENT("%s: Module %d: Critical Error (%s:%d)!\n", + card->devname, mod_no, + __FUNCTION__,__LINE__); + return 0xFF; + } + + return (u8)(data & 0xFF); +} + +unsigned char aft_analog_read_fe (void* pcard, ...) +{ + va_list args; + sdla_t *card = (sdla_t*)pcard; + int mod_no, type, chain, reg; + unsigned char data = 0; +#if defined(WAN_DEBUG_FE) + char *fname; + int fline; +#endif + + WAN_ASSERT(card == NULL); + WAN_ASSERT(card->hw_iface.bus_write_4 == NULL); + WAN_ASSERT(card->hw_iface.bus_read_4 == NULL); + + va_start(args, pcard); + mod_no = va_arg(args, int); + type = va_arg(args, int); + chain = va_arg(args, int); + reg = va_arg(args, int); +#if defined(WAN_DEBUG_FE) + fname = va_arg(args, char*); + fline = va_arg(args, int); +#endif + va_end(args); + + if (card->hw_iface.fe_test_and_set_bit(card->hw)){ +#if defined(WAN_DEBUG_FE) + DEBUG_EVENT("%s: %s:%d: Critical Error: Re-entry in FE (%s:%d)!\n", + card->devname, __FUNCTION__,__LINE__,fname,fline); +#else + DEBUG_EVENT("%s: %s:%d: Critical Error: Re-entry in FE!\n", + card->devname, __FUNCTION__,__LINE__); +#endif + return 0x00; + } + data = __aft_analog_read_fe (card, mod_no, type, chain, reg); + + card->hw_iface.fe_clear_bit(card->hw); + return data; +} + +unsigned char aft_analog_read_cpld(sdla_t *card, unsigned short cpld_off) +{ + u16 org_off; + u8 tmp; + + if (card->hw_iface.fe_test_and_set_bit(card->hw)){ + DEBUG_EVENT("%s: %s:%d: Critical Error: Re-entry in FE!\n", + card->devname, __FUNCTION__,__LINE__); + return 0x00; + } + + cpld_off |= AFT4_BIT_DEV_ADDR_CPLD; + + /*ALEX: Save the current address. */ + card->hw_iface.bus_read_2(card->hw, + AFT_MCPU_INTERFACE_ADDR, + &org_off); + + card->hw_iface.bus_write_2(card->hw, + AFT_MCPU_INTERFACE_ADDR, + cpld_off); + + card->hw_iface.bus_read_1(card->hw,AFT_MCPU_INTERFACE, &tmp); + + /*ALEX: Restore original address */ + card->hw_iface.bus_write_2(card->hw, + AFT_MCPU_INTERFACE_ADDR, + org_off); + card->hw_iface.fe_clear_bit(card->hw); + return tmp; +} + +int aft_analog_write_cpld(sdla_t *card, unsigned short off,unsigned char data) +{ + u16 org_off; + + if (card->hw_iface.fe_test_and_set_bit(card->hw)){ + DEBUG_EVENT("%s: %s:%d: Critical Error: Re-entry in FE!\n", + card->devname, __FUNCTION__,__LINE__); + return 0x00; + } + + off |= AFT4_BIT_DEV_ADDR_CPLD; + + /*ALEX: Save the current original address */ + card->hw_iface.bus_read_2(card->hw, + AFT_MCPU_INTERFACE_ADDR, + &org_off); + + /* This delay is required to avoid bridge optimization + * (combining two writes together)*/ + WP_DELAY(5); + + card->hw_iface.bus_write_2(card->hw, + AFT_MCPU_INTERFACE_ADDR, + off); + + /* This delay is required to avoid bridge optimization + * (combining two writes together)*/ + WP_DELAY(5); + + card->hw_iface.bus_write_1(card->hw, + AFT_MCPU_INTERFACE, + data); + /*ALEX: Restore the original address */ + card->hw_iface.bus_write_2(card->hw, + AFT_MCPU_INTERFACE_ADDR, + org_off); + card->hw_iface.fe_clear_bit(card->hw); + return 0; +} + +void aft_analog_fifo_adjust(sdla_t *card,u32 level) +{ + return; +} + +#if defined(CONFIG_WANPIPE_HWEC) +static int aft_analog_hwec_reset(void *pcard, int reset) +{ + sdla_t *card = (sdla_t*)pcard; + wan_smp_flag_t smp_flags,flags; + int err = -EINVAL; + + card->hw_iface.hw_lock(card->hw,&smp_flags); + wan_spin_lock_irq(&card->wandev.lock,&flags); + if (!reset){ + DEBUG_EVENT("%s: Clear Echo Canceller chip reset.\n", + card->devname); + + aft_analog_write_cpld(card, 0x00, 0x01); + WP_DELAY(1000); + err = 0; + + }else{ + DEBUG_EVENT("%s: Set Echo Canceller chip reset.\n", + card->devname); + aft_analog_write_cpld(card, 0x00, 0x00); + err = 0; + } + wan_spin_unlock_irq(&card->wandev.lock,&flags); + card->hw_iface.hw_unlock(card->hw,&smp_flags); + + return err; +} +#endif + +#if defined(CONFIG_WANPIPE_HWEC) +#define AFT_REMORA_MUX_TS_EC_ENABLE 0x210 +static int aft_analog_hwec_enable(void *pcard, int enable, int channel) +{ + sdla_t *card = (sdla_t*)pcard; + unsigned int value = 0x00; + + WAN_ASSERT(card == NULL); + if(!wan_test_bit(channel, &card->wandev.ec_enable_map)){ + return -EINVAL; + } + + card->hw_iface.bus_read_4( + card->hw, + AFT_REMORA_MUX_TS_EC_ENABLE, + &value); + if (enable){ + wan_set_bit(channel,&card->wandev.ec_map); + value |= (1 << channel); + }else{ + wan_clear_bit(channel,&card->wandev.ec_map); + value &= ~(1 << channel); + } + card->hw_iface.bus_write_4( + card->hw, + AFT_REMORA_MUX_TS_EC_ENABLE, + value); + DEBUG_HWEC("[HWEC]: %s: %s bypass mode for channel %d (value=%X)!\n", + card->devname, + (enable) ? "Enable" : "Disable", + channel, + value); + + return 0; +} +#endif + + + diff -Nur linux.org/drivers/net/wan/af_wanpipe.mod.c linux-2.6.17/drivers/net/wan/af_wanpipe.mod.c --- linux.org/drivers/net/wan/af_wanpipe.mod.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/drivers/net/wan/af_wanpipe.mod.c 2006-08-30 10:07:16.000000000 +0000 @@ -0,0 +1,30 @@ +#include +#include +#include + +MODULE_INFO(vermagic, VERMAGIC_STRING); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,6) || defined(WANPIPE_MOD_266_FORCE_UPDATE) +#undef unix +struct module __this_module +__attribute__((section(".gnu.linkonce.this_module"))) = { + .name = __stringify(KBUILD_MODNAME), + .init = init_module, +#ifdef CONFIG_MODULE_UNLOAD + .exit = cleanup_module, +#endif +}; +#endif + + +static const struct modversion_info ____versions[] +__attribute__((section("__versions"))) = { + +}; + + +static const char __module_depends[] +__attribute_used__ +__attribute__((section(".modinfo"))) = +"depends=wanrouter"; + diff -Nur linux.org/drivers/net/wan/sdla_56k.c linux-2.6.17/drivers/net/wan/sdla_56k.c --- linux.org/drivers/net/wan/sdla_56k.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/drivers/net/wan/sdla_56k.c 2006-08-30 10:07:16.000000000 +0000 @@ -0,0 +1,482 @@ +/****************************************************************************** + * sdla_56k.c WANPIPE(tm) Multiprotocol WAN Link Driver. + * 56K board configuration. + * + * Author: Nenad Corbic + * + * Copyright: (c) 1995-2001 Sangoma Technologies Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * ============================================================================ + * Jul 22, 2001 Nenad Corbic Initial version. + * Oct 01, 2001 Gideon Hack Modifications for interrupt usage. + ****************************************************************************** + */ + + +/* + ****************************************************************************** + INCLUDE FILES + ****************************************************************************** +*/ + +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) +# include +# include +# include +#elif defined(__WINDOWS__) +# include +# include +#else +# include +# include +# include +# include +# include /* WANPIPE common user API definitions */ +#endif + +/****************************************************************************** + DEFINES AND MACROS +******************************************************************************/ +#define WRITE_REG(reg,val) fe->write_fe_reg(fe->card, (int)(reg),(int)(val)) +#define READ_REG(reg) fe->read_fe_reg(fe->card, (int)(reg)) + + +/****************************************************************************** + STRUCTURES AND TYPEDEFS +******************************************************************************/ + + +/****************************************************************************** + GLOBAL VARIABLES +******************************************************************************/ + +/****************************************************************************** + FUNCTION PROTOTYPES +******************************************************************************/ + +static int sdla_56k_config(void* pfe); +static void display_Rx_code_condition(sdla_fe_t* fe); +static int sdla_56k_print_alarm(sdla_fe_t* fe, unsigned int); +static unsigned int sdla_56k_alarm(sdla_fe_t *fe, int manual_read); +static int sdla_56k_update_alarm_info(sdla_fe_t *fe, struct seq_file* m, int* stop_cnt); +static int sdla_56k_udp(sdla_fe_t*, void*, unsigned char*); + +/****************************************************************************** + FUNCTION DEFINITIONS +******************************************************************************/ + +/****************************************************************************** + * sdla_56k_get_fe_status() + * + * Description: + * Arguments: + * Returns: + ****************************************************************************** + */ +static char* sdla_56k_get_fe_media_string(void) +{ + return ("S514_56K"); +} + +/****************************************************************************** + * sdla_56k_get_fe_status() + * + * Description: + * Arguments: + * Returns: + ****************************************************************************** + */ +static unsigned char sdla_56k_get_fe_media(sdla_fe_t *fe) +{ + return fe->fe_cfg.media; +} + +/****************************************************************************** + * sdla_56k_get_fe_status() + * + * Description: + * Arguments: + * Returns: + ****************************************************************************** + */ +static int sdla_56k_get_fe_status(sdla_fe_t *fe, unsigned char *status) +{ + *status = fe->fe_status; + return 0; +} + +static unsigned int sdla_56k_alarm(sdla_fe_t *fe, int manual_read) +{ + + unsigned short status = 0x00; + + WAN_ASSERT(fe->write_fe_reg == NULL); + WAN_ASSERT(fe->read_fe_reg == NULL); + /* set to manually read the front-end registers */ + if(manual_read) { + fe->fe_param.k56_param.RR8_reg_56k = 0; + fe->fe_param.k56_param.RR8_reg_56k = READ_REG(REG_INT_EN_STAT); + fe->fe_param.k56_param.RRA_reg_56k = READ_REG(REG_DEV_STAT); + fe->fe_param.k56_param.RRC_reg_56k = READ_REG(REG_RX_CODES); + status |= fe->fe_param.k56_param.RRA_reg_56k; + status = (status << 8) & 0xFF00; + status |= fe->fe_param.k56_param.RRC_reg_56k; + } + + DEBUG_56K("56K registers: 8-%02X,C-%02X,A-%02X\n", + fe->fe_param.k56_param.RR8_reg_56k, + fe->fe_param.k56_param.RRC_reg_56k, + fe->fe_param.k56_param.RRA_reg_56k); + + /* discard an invalid Rx code interrupt */ + if((fe->fe_param.k56_param.RR8_reg_56k & BIT_INT_EN_STAT_RX_CODE) && + (!fe->fe_param.k56_param.RRC_reg_56k)) { + return(status); + } + + /* record an RLOS (Receive Loss of Signal) condition */ + if(fe->fe_param.k56_param.RRA_reg_56k & BIT_DEV_STAT_RLOS) { + fe->fe_param.k56_param.RLOS_56k = 1; + } + + /* display Rx code conditions if necessary */ + if(!((fe->fe_param.k56_param.RRC_reg_56k ^ fe->fe_param.k56_param.prev_RRC_reg_56k) & + fe->fe_param.k56_param.delta_RRC_reg_56k) || + (fe->fe_status == FE_CONNECTED)) { + display_Rx_code_condition(fe); + } + + /* record the changes that occurred in the Rx code conditions */ + fe->fe_param.k56_param.delta_RRC_reg_56k |= + (fe->fe_param.k56_param.RRC_reg_56k ^ fe->fe_param.k56_param.prev_RRC_reg_56k); + + + if(manual_read || (fe->fe_param.k56_param.RR8_reg_56k & BIT_INT_EN_STAT_ACTIVE)) { + + /* if Insertion Loss is less than 44.4 dB, then we are connected */ + if ((fe->fe_param.k56_param.RRA_reg_56k & 0x0F) > BIT_DEV_STAT_IL_44_dB) { + if((fe->fe_status == FE_DISCONNECTED) || + (fe->fe_status == FE_UNITIALIZED)) { + + fe->fe_status = FE_CONNECTED; + /* reset the Rx code condition changes */ + fe->fe_param.k56_param.delta_RRC_reg_56k = 0; + + if(fe->fe_param.k56_param.RLOS_56k == 1) { + fe->fe_param.k56_param.RLOS_56k = 0; + DEBUG_EVENT("%s: 56k Receive Signal Recovered\n", + fe->name); + } + DEBUG_EVENT("%s: 56k Connected\n", + fe->name); + } + }else{ + if((fe->fe_status == FE_CONNECTED) || + (fe->fe_status == FE_UNITIALIZED)) { + + fe->fe_status = FE_DISCONNECTED; + /* reset the Rx code condition changes */ + fe->fe_param.k56_param.delta_RRC_reg_56k = 0; + + if(fe->fe_param.k56_param.RLOS_56k == 1) { + DEBUG_EVENT("%s: 56k Receive Loss of Signal\n", + fe->name); + } + DEBUG_EVENT("%s: 56k Disconnected (loopback)\n", + fe->name); + } + } + } + + fe->fe_param.k56_param.prev_RRC_reg_56k = + fe->fe_param.k56_param.RRC_reg_56k; + fe->fe_alarm = status; + return(status); +} + + +int sdla_56k_default_cfg(void* pcard, void* p56k_cfg) +{ + return 0; +} + + +int sdla_56k_iface_init(void* pfe_iface) +{ + sdla_fe_iface_t *fe_iface = (sdla_fe_iface_t*)pfe_iface; + + fe_iface->config = &sdla_56k_config; + fe_iface->get_fe_status = &sdla_56k_get_fe_status; + fe_iface->get_fe_media = &sdla_56k_get_fe_media; + fe_iface->get_fe_media_string = &sdla_56k_get_fe_media_string; + fe_iface->print_fe_alarm = &sdla_56k_print_alarm; + fe_iface->read_alarm = &sdla_56k_alarm; + fe_iface->update_alarm_info = &sdla_56k_update_alarm_info; + fe_iface->process_udp = &sdla_56k_udp; + return 0; +} + +static int sdla_56k_config(void* pfe) +{ + sdla_fe_t *fe = (sdla_fe_t*)pfe; + sdla_t *card = (sdla_t *)fe->card; + + WAN_ASSERT(fe->write_fe_reg == NULL); + WAN_ASSERT(fe->read_fe_reg == NULL); + + /* The 56k CSU/DSU front end status has not been initialized */ + fe->fe_status = FE_UNITIALIZED; + + /* Zero the previously read RRC register value */ + fe->fe_param.k56_param.prev_RRC_reg_56k = 0; + + /* Zero the RRC register changes */ + fe->fe_param.k56_param.delta_RRC_reg_56k = 0; + + if(WRITE_REG(REG_INT_EN_STAT, (BIT_INT_EN_STAT_IDEL | + BIT_INT_EN_STAT_RX_CODE | BIT_INT_EN_STAT_ACTIVE))) { + return 1; + } + + if(WRITE_REG(REG_RX_CODES, 0xFF & ~(BIT_RX_CODES_ZSC))) { + return 1; + } + + if (card->wandev.clocking == WANOPT_EXTERNAL){ + DEBUG_EVENT("%s: Configuring 56K CSU/DSU for External Clocking\n", + card->devname); + if(WRITE_REG(REG_DEV_CTRL, + (BIT_DEV_CTRL_SCT_E_OUT | BIT_DEV_CTRL_DDS_PRI))) { + return 1; + } + }else{ + DEBUG_EVENT("%s: Configuring 56K CSU/DSU for Internal Clocking\n", + fe->name); + if(WRITE_REG(REG_DEV_CTRL, (BIT_DEV_CTRL_XTALI_INT | + BIT_DEV_CTRL_SCT_E_OUT | BIT_DEV_CTRL_DDS_PRI))) { + return 1; + } + } + + if(WRITE_REG(REG_TX_CTRL, 0x00)) { + return 1; + } + + if(WRITE_REG(REG_RX_CTRL, 0x00)) { + return 1; + } + + if(WRITE_REG(REG_EIA_SEL, 0x00)) { + return 1; + } + + if(WRITE_REG(REG_EIA_TX_DATA, 0x00)) { + return 1; + } + + if(WRITE_REG(REG_EIA_CTRL, (BIT_EIA_CTRL_RTS_ACTIVE | + BIT_EIA_CTRL_DTR_ACTIVE | BIT_EIA_CTRL_DTE_ENABLE))) { + return 1; + } + + return 0; +} + + +static void display_Rx_code_condition(sdla_fe_t* fe) +{ + sdla_56k_param_t *k56_param = &fe->fe_param.k56_param; + + /* check for a DLP (DSU Non-latching loopback) code condition */ + if((k56_param->RRC_reg_56k ^ k56_param->prev_RRC_reg_56k) & + BIT_RX_CODES_DLP) { + if(k56_param->RRC_reg_56k & BIT_RX_CODES_DLP) { + DEBUG_EVENT("%s: 56k receiving DSU Loopback code\n", + fe->name); + } else { + DEBUG_EVENT("%s: 56k DSU Loopback code condition ceased\n", + fe->name); + } + } + + /* check for an OOF (Out of Frame) code condition */ + if((k56_param->RRC_reg_56k ^ k56_param->prev_RRC_reg_56k) & + BIT_RX_CODES_OOF) { + if(k56_param->RRC_reg_56k & BIT_RX_CODES_OOF) { + DEBUG_EVENT("%s: 56k receiving Out of Frame code\n", + fe->name); + } else { + DEBUG_EVENT("%s: 56k Out of Frame code condition ceased\n", + fe->name); + } + } + + /* check for an OOS (Out of Service) code condition */ + if((k56_param->RRC_reg_56k ^ k56_param->prev_RRC_reg_56k) & + BIT_RX_CODES_OOS) { + if(k56_param->RRC_reg_56k & BIT_RX_CODES_OOS) { + DEBUG_EVENT("%s: 56k receiving Out of Service code\n", + fe->name); + } else { + DEBUG_EVENT("%s: 56k Out of Service code condition ceased\n", + fe->name); + } + } + + /* check for a CMI (Control Mode Idle) condition */ + if((k56_param->RRC_reg_56k ^ k56_param->prev_RRC_reg_56k) & + BIT_RX_CODES_CMI) { + if(k56_param->RRC_reg_56k & BIT_RX_CODES_CMI) { + DEBUG_EVENT("%s: 56k receiving Control Mode Idle\n", + fe->name); + } else { + DEBUG_EVENT("%s: 56k Control Mode Idle condition ceased\n", + fe->name); + } + } + + /* check for a ZSC (Zero Suppression Code) condition */ + if((k56_param->RRC_reg_56k ^ k56_param->prev_RRC_reg_56k) & + BIT_RX_CODES_ZSC) { + if(k56_param->RRC_reg_56k & BIT_RX_CODES_ZSC) { + DEBUG_EVENT("%s: 56k receiving Zero Suppression code\n", + fe->name); + } else { + DEBUG_EVENT("%s: 56k Zero Suppression code condition ceased\n", + fe->name); + } + } + + /* check for a DMI (Data Mode Idle) condition */ + if((k56_param->RRC_reg_56k ^ k56_param->prev_RRC_reg_56k) & + BIT_RX_CODES_DMI) { + if(k56_param->RRC_reg_56k & BIT_RX_CODES_DMI) { + DEBUG_EVENT("%s: 56k receiving Data Mode Idle\n", + fe->name); + } else { + DEBUG_EVENT("%s: 56k Data Mode Idle condition ceased\n", + fe->name); + } + } +} + +/* + ****************************************************************************** + * sdla_56k_udp() + * + * Description: + * Arguments: + * Returns: + ****************************************************************************** + */ +static int sdla_56k_udp(sdla_fe_t *fe, void* pudp_cmd, unsigned char* data) +{ + wan_cmd_t *udp_cmd = (wan_cmd_t*)pudp_cmd; + + switch(udp_cmd->wan_cmd_command){ + case WAN_GET_MEDIA_TYPE: + data[0] = (IS_56K_FEMEDIA(fe) ? WAN_MEDIA_56K : + WAN_MEDIA_NONE); + udp_cmd->wan_cmd_return_code = WAN_CMD_OK; + udp_cmd->wan_cmd_data_len = sizeof(unsigned char); + break; + + case WAN_FE_GET_STAT: + /* 56K Update CSU/DSU alarms */ + fe->fe_alarm = sdla_56k_alarm(fe, 1); + memcpy(&data[0], &fe->fe_stats, sizeof(sdla_fe_stats_t)); + udp_cmd->wan_cmd_return_code = WAN_CMD_OK; + udp_cmd->wan_cmd_data_len = sizeof(sdla_fe_stats_t); + break; + + case WAN_FE_SET_LB_MODE: + case WAN_FE_FLUSH_PMON: + case WAN_FE_GET_CFG: + default: + udp_cmd->wan_cmd_return_code = WAN_UDP_INVALID_CMD; + udp_cmd->wan_cmd_data_len = 0; + break; + } + return 0; +} + +/* +******************************************************************************* +** sdla_56k_alaram_print() +** +** Description: +** Arguments: +** Returns: +*/ +static int sdla_56k_print_alarm(sdla_fe_t* fe, unsigned int status) +{ + unsigned int alarms = (unsigned int)status; + + if (!alarms){ + alarms = sdla_56k_alarm(fe, 0); + } + + DEBUG_EVENT("%s: 56K Alarms:\n", fe->name); + DEBUG_EVENT("%s: In Service: %s Data mode idle: %s\n", + fe->name, + INS_ALARM_56K(alarms), + DMI_ALARM_56K(alarms)); + + DEBUG_EVENT("%s: Zero supp. code: %s Ctrl mode idle: %s\n", + fe->name, + ZCS_ALARM_56K(alarms), + CMI_ALARM_56K(alarms)); + + DEBUG_EVENT("%s: Out of service code: %s Out of frame code: %s\n", + fe->name, + OOS_ALARM_56K(alarms), + OOF_ALARM_56K(alarms)); + + DEBUG_EVENT("%s: Valid DSU NL loopback: %s Unsigned mux code: %s\n", + fe->name, + DLP_ALARM_56K(alarms), + UMC_ALARM_56K(alarms)); + + DEBUG_EVENT("%s: Rx loss of signal: %s \n", + fe->name, + RLOS_ALARM_56K(alarms)); + return 0; +} + +static int sdla_56k_update_alarm_info(sdla_fe_t* fe, struct seq_file* m, int* stop_cnt) +{ + PROC_ADD_LINE(m, + "\n====================== Rx 56K CSU/DSU Alarms ==============================\n"); + PROC_ADD_LINE(m, + PROC_STATS_ALARM_FORMAT, + "In service", INS_ALARM_56K(fe->fe_alarm), + "Data mode idle", DMI_ALARM_56K(fe->fe_alarm)); + + PROC_ADD_LINE(m, + PROC_STATS_ALARM_FORMAT, + "Zero supp. code", ZCS_ALARM_56K(fe->fe_alarm), + "Ctrl mode idle", CMI_ALARM_56K(fe->fe_alarm)); + + PROC_ADD_LINE(m, + PROC_STATS_ALARM_FORMAT, + "Out of service code", OOS_ALARM_56K(fe->fe_alarm), + "Out of frame code", OOF_ALARM_56K(fe->fe_alarm)); + + PROC_ADD_LINE(m, + PROC_STATS_ALARM_FORMAT, + "Valid DSU NL loopback", DLP_ALARM_56K(fe->fe_alarm), + "Unsigned mux code", UMC_ALARM_56K(fe->fe_alarm)); + + PROC_ADD_LINE(m, + PROC_STATS_ALARM_FORMAT, + "Rx loss of signal", RLOS_ALARM_56K(fe->fe_alarm), + "N/A", "N/A"); + + return m->count; +} + + diff -Nur linux.org/drivers/net/wan/sdla_8te1.c linux-2.6.17/drivers/net/wan/sdla_8te1.c --- linux.org/drivers/net/wan/sdla_8te1.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/drivers/net/wan/sdla_8te1.c 2006-08-30 10:07:16.000000000 +0000 @@ -0,0 +1,2630 @@ +/* + * Copyright (c) 2006 + * Alex Feldman . All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Alex Feldman. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Alex Feldman AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Alex Feldman OR THE VOICES IN HIS HEAD + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + * $Id$ + */ + +/* + ****************************************************************************** + * sdla_8te1.c WANPIPE(tm) Multiprotocol WAN Link Driver. + * 8 ports T1/E1 board configuration. + * + * Author: Alex Feldman + * + * ============================================================================ + * Feb 18, 2006 Alex Feldma Initial version. + ****************************************************************************** + */ + +/****************************************************************************** +* INCLUDE FILES +******************************************************************************/ +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) +# include +# if !defined(CONFIG_PRODUCT_WANPIPE_GENERIC) +# include +# endif +# include +# include /* WANPIPE common user API definitions */ +# include +#elif (defined __WINDOWS__) +# include +# include /* WANPIPE common user API definitions */ +# include +# include +# if defined te_cfg +# undef te_cfg +# endif +#elif (defined __LINUX__) || (defined __KERNEL__) +# include +# include +# include +# include +# if !defined(CONFIG_PRODUCT_WANPIPE_GENERIC) +# include +# endif +# include +# include /* WANPIPE common user API definitions */ +#else +# error "No OS Defined" +#endif + +/****************************************************************************** +* DEFINES AND MACROS +******************************************************************************/ +#define CLEAR_REG(sreg,ereg) { \ + unsigned short reg; \ + for(reg = sreg; reg < ereg; reg++){ \ + WRITE_REG(reg, 0x00); \ + } \ + } + +#define IS_GLREG(reg) ((reg) >= 0xF0 && (reg) <= 0xFF) +#define IS_FRREG(reg) ((reg) <= 0x1F0) +#define IS_LIUREG(reg) ((reg) >= 0x1000 && (reg) <= 0x101F) +#define IS_BERTREG(reg) ((reg) >= 0x1100 && (reg) <= 0x110F) + +#define DLS_PORT_DELTA(reg) \ + IS_GLREG(reg) ? 0x000 : \ + IS_FRREG(reg) ? 0x200 : \ + IS_LIUREG(reg) ? 0x020 : \ + IS_BERTREG(reg) ? 0x010 : 0x001 + +/* Read/Write to front-end register */ +#define WRITE_REG(reg,val) \ + fe->write_fe_reg( \ + fe->card, \ + (int)((reg) + ((fe->fe_cfg.line_no)*(DLS_PORT_DELTA(reg)))),\ + (int)(val)) + +#define WRITE_REG_LINE(fe_line_no, reg,val) \ + fe->write_fe_reg( \ + fe->card, \ + (int)((reg) + (fe_line_no)*(DLS_PORT_DELTA(reg))), \ + (int)(val)) + +#define READ_REG(reg) \ + fe->read_fe_reg( \ + fe->card, \ + (int)((reg) + ((fe->fe_cfg.line_no)*(DLS_PORT_DELTA(reg))))) + +#define __READ_REG(reg) \ + fe->__read_fe_reg( \ + fe->card, \ + (int)((reg) + ((fe->fe_cfg.line_no)*(DLS_PORT_DELTA(reg))))) + +#define READ_REG_LINE(fe_line_no, reg) \ + fe->read_fe_reg( \ + fe->card, \ + (int)((reg) + (fe_line_no)*(DLS_PORT_DELTA(reg)))) + +#define IS_T1_ALARM(alarm) \ + (alarm & \ + ( \ + WAN_TE_BIT_RED_ALARM | \ + WAN_TE_BIT_AIS_ALARM | \ + WAN_TE_BIT_OOF_ALARM | \ + WAN_TE_BIT_LOS_ALARM | \ + WAN_TE_BIT_ALOS_ALARM \ + )) + +#define IS_E1_ALARM(alarm) \ + (alarm & \ + ( \ + WAN_TE_BIT_RED_ALARM | \ + WAN_TE_BIT_AIS_ALARM | \ + WAN_TE_BIT_OOF_ALARM | \ + WAN_TE_BIT_LOS_ALARM | \ + WAN_TE_BIT_ALOS_ALARM \ + )) + + +/****************************************************************************** +* STRUCTURES AND TYPEDEFS +******************************************************************************/ + + +/****************************************************************************** +* GLOBAL VERIABLES +******************************************************************************/ + +/****************************************************************************** +* FUNCTION PROTOTYPES +******************************************************************************/ +static int sdla_8te1_global_config(void* pfe); /* Change to static */ +static int sdla_8te1_global_unconfig(void* pfe); /* Change to static */ +static int sdla_8te1_config(void* pfe); /* Change to static */ +static int sdla_8te1_unconfig(void* pfe); /* Change to static */ +static int sdla_8te1_TxChanCtrl(sdla_fe_t* fe, int channel, int enable); +static int sdla_8te1_RxChanCtrl(sdla_fe_t* fe, int channel, int enable); +static int sdla_8te1_intr_ctrl(sdla_fe_t*, int, int, int, unsigned int); +static int sdla_8te1_check_intr(sdla_fe_t *fe); +static int sdla_8te1_intr(sdla_fe_t *fe); +static int sdla_8te1_udp(sdla_fe_t *fe, void* p_udp_cmd, unsigned char* data); +static int sdla_8te1_flush_pmon(sdla_fe_t *fe); +static int sdla_8te1_pmon(sdla_fe_t *fe, int action); +static int sdla_8te1_polling(sdla_fe_t* fe); +static unsigned int sdla_8te1_read_alarms(sdla_fe_t *fe, int read); +static int sdla_8te1_set_alarms(sdla_fe_t* fe, unsigned long alarms); +static int sdla_8te1_clear_alarms(sdla_fe_t* fe, unsigned long alarms); +static void sdla_8te1_set_status(sdla_fe_t* fe, unsigned long alarms); +static int sdla_8te1_print_alarms(sdla_fe_t*, unsigned int); +static int sdla_8te1_set_lbmode(sdla_fe_t*, unsigned char, unsigned char); +static int sdla_8te1_rbs_update(sdla_fe_t* fe, int, unsigned char); +static int sdla_8te1_set_rbsbits(sdla_fe_t *fe, int, unsigned char); +static int sdla_8te1_rbs_report(sdla_fe_t* fe); +static int sdla_8te1_check_rbsbits(sdla_fe_t* fe, int, unsigned int, int); +static unsigned char sdla_8te1_read_rbsbits(sdla_fe_t* fe, int, int); +static void sdla_8te1_enable_timer(sdla_fe_t*, unsigned char, unsigned long); +static int sdla_8te1_post_config(sdla_fe_t* fe); + +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) +static void sdla_8te1_timer(void* pfe); +#elif defined(__WINDOWS__) +static void sdla_8te1_timer(IN PKDPC Dpc, void* pfe, void* arg2, void* arg3); +#else +static void sdla_8te1_timer(unsigned long pfe); +#endif + +static int sdla_8te1_update_alarm_info(sdla_fe_t*, struct seq_file*, int*); +static int sdla_8te1_update_pmon_info(sdla_fe_t*, struct seq_file*, int*); + +/****************************************************************************** +* FUNCTION DEFINITIONS +******************************************************************************/ + +/****************************************************************************** + * sdla_te3_get_fe_status() + * + * Description: + * Arguments: + * Returns: + ****************************************************************************** + */ +static char* sdla_8te1_get_fe_media_string(void) +{ + return ("AFT-A108 T1/E1"); +} + +/****************************************************************************** + * sdla_8te1_get_fe_status() + * + * Description: + * Arguments: + * Returns: + ****************************************************************************** + */ +static unsigned char sdla_8te1_get_fe_media(sdla_fe_t *fe) +{ + return fe->fe_cfg.media; +} + +/****************************************************************************** + * sdla_8te1_get_fe_status() + * + * Description: + * Arguments: + * Returns: + ****************************************************************************** + */ +static int sdla_8te1_get_fe_status(sdla_fe_t *fe, unsigned char *status) +{ + *status = fe->fe_status; + return 0; +} + +/* + ****************************************************************************** + * sdla_8te1_TxChanCtrl() + * + * Description: + * Arguments: + * Returns: + ****************************************************************************** + */ +static int sdla_8te1_TxChanCtrl(sdla_fe_t* fe, int channel, int enable) +{ + int off = channel / 8; + int bit = channel % 8; + unsigned char value; + + value = READ_REG(REG_TGCCS1 + off); + if (enable){ + value &= ~(1 << (bit-1)); + }else{ + value |= (1 << (bit-1)); + } + WRITE_REG(REG_TGCCS1 + off, value); + return 0; +} + +/* + ****************************************************************************** + * sdla_8te1_RxChanCtrl() + * + * Description: + * Arguments: + * Returns: + ****************************************************************************** + */ +static int sdla_8te1_RxChanCtrl(sdla_fe_t* fe, int channel, int enable) +{ + int off = channel / 8; + int bit = channel % 8; + unsigned char value; + + value = READ_REG(REG_RGCCS1 + off); + if (enable){ + value &= ~(1 << (bit-1)); + }else{ + value |= (1 << (bit-1)); + } + WRITE_REG(REG_RGCCS1 + off, value); + return 0; +} + + +int sdla_8te1_iface_init(void *p_fe_iface) +{ + sdla_fe_iface_t *fe_iface = (sdla_fe_iface_t*)p_fe_iface; + + fe_iface->global_config = &sdla_8te1_global_config; + fe_iface->global_unconfig = &sdla_8te1_global_unconfig; + fe_iface->config = &sdla_8te1_config; + fe_iface->unconfig = &sdla_8te1_unconfig; + fe_iface->isr = &sdla_8te1_intr; + fe_iface->check_isr = &sdla_8te1_check_intr; + fe_iface->intr_ctrl = &sdla_8te1_intr_ctrl; + fe_iface->polling = &sdla_8te1_polling; + fe_iface->process_udp = &sdla_8te1_udp; + + fe_iface->print_fe_alarm = &sdla_8te1_print_alarms; + /*fe_iface->print_fe_act_channels = &sdla_te_print_channels;*/ + fe_iface->read_alarm = &sdla_8te1_read_alarms; + /*fe_iface->set_fe_alarm = &sdla_te_set_alarms;*/ + fe_iface->read_pmon = &sdla_8te1_pmon; + fe_iface->flush_pmon = &sdla_8te1_flush_pmon; + fe_iface->get_fe_status = &sdla_8te1_get_fe_status; + fe_iface->get_fe_media = &sdla_8te1_get_fe_media; + fe_iface->get_fe_media_string = &sdla_8te1_get_fe_media_string; + fe_iface->update_alarm_info = &sdla_8te1_update_alarm_info; + fe_iface->update_pmon_info = &sdla_8te1_update_pmon_info; + fe_iface->set_fe_lbmode = &sdla_8te1_set_lbmode; + fe_iface->read_rbsbits = &sdla_8te1_read_rbsbits; + fe_iface->check_rbsbits = &sdla_8te1_check_rbsbits; + fe_iface->report_rbsbits = &sdla_8te1_rbs_report; + fe_iface->set_rbsbits = &sdla_8te1_set_rbsbits; + fe_iface->post_config = &sdla_8te1_post_config; + +#if 0 + fe_iface->set_fe_sigctrl = &sdla_te_sigctrl; + fe_iface->led_ctrl = &sdla_te_led_ctrl; +#endif + return 0; +} + +/* + ****************************************************************************** + * sdla_8te_global_config() + * + * Description: Global configuration for Sangoma TE1 PMC board. + * Note: These register should be program only once for AFT-OCTAL + * cards. + * Arguments: + * Returns: WANTRUE - TE1 configred successfully, otherwise WAN_FALSE. + ****************************************************************************** + */ +static int sdla_8te1_global_config(void* pfe) +{ + sdla_fe_t *fe = (sdla_fe_t*)pfe; + + DEBUG_EVENT("%s: %s Global Front End configuration\n", + fe->name, FE_MEDIA_DECODE(fe)); + WRITE_REG_LINE(0, REG_GTCCR, 0x00); + WRITE_REG_LINE(0, REG_GTCR1, 0x00); + + WRITE_REG_LINE(0, REG_GLSRR, 0xFF); + WRITE_REG_LINE(0, REG_GFSRR, 0xFF); + WP_DELAY(1000); + WRITE_REG_LINE(0, REG_GLSRR, 0x00); + WRITE_REG_LINE(0, REG_GFSRR, 0x00); + + return 0; +} + +/* + ****************************************************************************** + * sdla_8te1_global_unconfig() + * + * Description: Global configuration for Sangoma TE1 PMC board. + * Note: These register should be program only once for AFT-QUAD + * cards. + * Arguments: + * Returns: WANTRUE - TE1 configred successfully, otherwise WAN_FALSE. + ****************************************************************************** + */ +static int sdla_8te1_global_unconfig(void* pfe) +{ + sdla_fe_t *fe = (sdla_fe_t*)pfe; + + DEBUG_EVENT("%s: T1/E1 Global unconfiguration!\n", fe->name); + WRITE_REG_LINE(0, REG_GLSRR, 0xFF); + WRITE_REG_LINE(0, REG_GFSRR, 0xFF); + WP_DELAY(1000); + return 0; +} + +/* + ****************************************************************************** + * sdla_8te1_config() + * + * Description: Configure Sangoma 8 ports T1/E1 board + * Arguments: + * Returns: WANTRUE - TE1 configred successfully, otherwise WAN_FALSE. + ****************************************************************************** + */ +static int sdla_8te1_config(void* pfe) +{ + + sdla_fe_t *fe = (sdla_fe_t*)pfe; + unsigned char value = 0x00; + + WAN_ASSERT(fe->write_fe_reg == NULL); + WAN_ASSERT(fe->read_fe_reg == NULL); + + /* Initial FE state */ + fe->fe_status=FE_DISCONNECTED; + + /* Revision/Chip ID (Reg. 0x0D) */ + value = READ_REG_LINE(0, REG_IDR); + fe->fe_chip_id = DEVICE_ID_DS(value); + switch(fe->fe_chip_id){ + case DEVICE_ID_DS26528: + if (WAN_FE_LINENO(fe) < 0 || WAN_FE_LINENO(fe) > 8){ + DEBUG_EVENT( + "%s: TE Config: Invalid Port selected %d (Min=1 Max=8)\n", + fe->name, + WAN_FE_LINENO(fe)+1); + return -EINVAL; + } + break; + case DEVICE_ID_DS26524: + if (WAN_FE_LINENO(fe) < 0 || WAN_FE_LINENO(fe) > 4){ + DEBUG_EVENT( + "%s: TE Config: Invalid Port selected %d (Min=1 Max=8)\n", + fe->name, + WAN_FE_LINENO(fe)+1); + return -EINVAL; + } + break; + case DEVICE_ID_DS26522: + case DEVICE_ID_DS26521: + default: + DEBUG_EVENT("%s: ERROR: Unsupported %s CHIP (0x%02X)\n", + fe->name, + FE_MEDIA_DECODE(fe), + fe->fe_chip_id); + return -EINVAL; + } + + DEBUG_TE1("%s: %s:%d Line decoding %s\n", + fe->name, + FE_MEDIA_DECODE(fe), WAN_FE_LINENO(fe)+1, + FE_LCODE_DECODE(fe)); + DEBUG_TE1("%s: %s:%d Frame type %s\n", + fe->name, + FE_MEDIA_DECODE(fe), WAN_FE_LINENO(fe)+1, + FE_FRAME_DECODE(fe)); + DEBUG_TE1("%s: %s LBO %s\n", + fe->name, + FE_MEDIA_DECODE(fe), + TE_LBO_DECODE(fe)); + if (WAN_TE1_CLK(fe) == WAN_MASTER_CLK){ + DEBUG_TE1("%s: %s Clock mode Master (Osciliator)\n", + fe->name, + FE_MEDIA_DECODE(fe)); +#if 0 + if (WAN_TE1_REFCLK(fe) != WAN_TE1_REFCLK_OSC){ + DEBUG_TE1("%s: %s Clock mode Master (refclk from Port %d)\n", + fe->name, + FE_MEDIA_DECODE(fe), + WAN_TE1_REFCLK(fe)); + }else{ + DEBUG_TE1("%s: %s Clock mode Master (Osciliator)\n", + fe->name, + FE_MEDIA_DECODE(fe)); + } +#endif + }else{ + DEBUG_TE1("%s: %s Clock mode Normal\n", + fe->name, + FE_MEDIA_DECODE(fe)); + } + + /* Init Rx Framer registers */ + CLEAR_REG(0x0000, 0x00F0); + /* Init Tx Framer registers */ + CLEAR_REG(0x0100, 0x01F0); + /* Init LIU registers */ + CLEAR_REG(0x1000, 0x1020); + /* Init BERT registers */ + CLEAR_REG(0x1100, 0x1110); + + /* Set Rx Framer soft reset */ + WRITE_REG(REG_RMMR, BIT_RMMR_SFTRST); + /* Set Tx Framer soft reset */ + WRITE_REG(REG_TMMR, BIT_RMMR_SFTRST); + if (IS_T1_FEMEDIA(fe)){ + /* Clear Rx Framer soft reset */ + WRITE_REG(REG_RMMR, 0x00); + /* Clear Tx Framer soft reset */ + WRITE_REG(REG_TMMR, 0x00); + /* Enable Rx Framer */ + WRITE_REG(REG_RMMR, BIT_RMMR_FRM_EN); + /* Enable Tx Framer */ + WRITE_REG(REG_TMMR, BIT_TMMR_FRM_EN); + }else{ + /* Clear Rx Framer soft reset */ + WRITE_REG(REG_RMMR, BIT_RMMR_T1E1); + /* Clear Tx Framer soft reset */ + WRITE_REG(REG_TMMR, BIT_TMMR_T1E1); + /* Enable Rx Framer */ + WRITE_REG(REG_RMMR, (BIT_RMMR_FRM_EN | BIT_RMMR_T1E1)); + /* Enable Tx Framer */ + WRITE_REG(REG_TMMR, (BIT_TMMR_FRM_EN | BIT_TMMR_T1E1)); + } + + if (IS_T1_FEMEDIA(fe)){ + WRITE_REG(REG_RCR1, BIT_RCR1_T1_SYNCT); + } + switch(WAN_FE_FRAME(fe)){ + case WAN_FR_D4: + value = READ_REG(REG_RCR1); + WRITE_REG(REG_RCR1, value | BIT_RCR1_T1_RFM | BIT_RCR1_T1_SYNCC); + + value = READ_REG(REG_TCR3); + WRITE_REG(REG_TCR3, value | BIT_TCR3_TFM); + break; + + case WAN_FR_ESF: + value = READ_REG(REG_RCR1); + value |= BIT_RCR1_T1_SYNCC; + value &= ~BIT_RCR1_T1_RFM; + WRITE_REG(REG_RCR1, value); + + value = READ_REG(REG_TCR3); + value &= ~BIT_TCR3_TFM; + WRITE_REG(REG_TCR3, value); + break; + case WAN_FR_NCRC4: + break; + case WAN_FR_CRC4: + value = READ_REG(REG_RCR1); + WRITE_REG(REG_RCR1, value | BIT_RCR1_E1_RCRC4); + value = READ_REG(REG_TCR1); + WRITE_REG(REG_TCR1, value | BIT_TCR1_E1_TCRC4); + break; + default: + DEBUG_EVENT("%s: Unsupported Frame mode (%X)\n", + fe->name, WAN_FE_FRAME(fe)); + return -EINVAL; + } + + if (IS_E1_FEMEDIA(fe)){ + if (WAN_TE1_SIG_MODE(fe) == WAN_TE1_SIG_CAS){ + + /* CAS signalling mode */ + value = READ_REG(REG_RCR1); + WRITE_REG(REG_RCR1, value & ~BIT_RCR1_E1_RSIGM); +// value = READ_REG(REG_RSIGC); +// WRITE_REG(REG_RSIGC, value | BIT_RSIGC_CASMS); + }else{ + + /* CCS signalling mode */ + WAN_TE1_SIG_MODE(fe) = WAN_TE1_SIG_CCS; + value = READ_REG(REG_RCR1); + WRITE_REG(REG_RCR1, value | BIT_RCR1_E1_RSIGM); + } + } + + switch(WAN_FE_LCODE(fe)){ + case WAN_LCODE_B8ZS: + value = READ_REG(REG_RCR1); + WRITE_REG(REG_RCR1, value | BIT_RCR1_T1_RB8ZS); + value = READ_REG(REG_TCR1); + WRITE_REG(REG_TCR1, value | BIT_TCR1_T1_TB8ZS); + break; + + case WAN_LCODE_HDB3: + value = READ_REG(REG_RCR1); + WRITE_REG(REG_RCR1, value | BIT_RCR1_E1_RHDB3); + value = READ_REG(REG_TCR1); + WRITE_REG(REG_TCR1, value | BIT_TCR1_E1_THDB3); + break; + + case WAN_LCODE_AMI: + if (IS_T1_FEMEDIA(fe)){ + value = READ_REG(REG_RCR1); + WRITE_REG(REG_RCR1, value & ~BIT_RCR1_T1_RB8ZS); + value = READ_REG(REG_TCR1); + WRITE_REG(REG_TCR1, value & ~BIT_TCR1_T1_TB8ZS); + }else{ + value = READ_REG(REG_RCR1); + WRITE_REG(REG_RCR1, value & ~BIT_RCR1_E1_RHDB3); + value = READ_REG(REG_TCR1); + WRITE_REG(REG_TCR1, value & ~BIT_TCR1_E1_THDB3); + } + break; + + default: + DEBUG_EVENT("%s: Unsupported Line code mode (%X)\n", + fe->name, WAN_FE_LCODE(fe)); + return -EINVAL; + } + + /* RSYSCLK output */ + WRITE_REG(REG_RIOCR, BIT_RIOCR_RSCLKM); + /* TSYSCLK input */ + if (IS_T1_FEMEDIA(fe)){ + WRITE_REG(REG_TIOCR, 0x00); + }else{ + WRITE_REG(REG_TIOCR, BIT_TIOCR_TSCLKM); + } +#if 0 + if (WAN_TE1_CLK(fe) == WAN_MASTER_CLK){ + /* RSYNC as input */ + value = READ_REG(REG_RIOCR); + value |= BIT_RIOCR_RSIO; + WRITE_REG(REG_RIOCR, value); + /* RESE enable */ + value = READ_REG(REG_RESCR); + value |= BIT_RESCR_RESE; + WRITE_REG(REG_RESCR, value); + + /* TSYNC as output */ + value = READ_REG(REG_TIOCR); + value |= BIT_TIOCR_TSIO; + WRITE_REG(REG_TIOCR, value); + } +#endif + if (IS_E1_FEMEDIA(fe)){ + WRITE_REG(REG_E1TAF, 0x1B); + WRITE_REG(REG_E1TNAF, 0x40); + } + + /* Set INIT_DONE */ + value = READ_REG(REG_RMMR); + WRITE_REG(REG_RMMR, value | BIT_RMMR_INIT_DONE); + /* Set INIT_DONE */ + value = READ_REG(REG_TMMR); + WRITE_REG(REG_TMMR, value | BIT_TMMR_INIT_DONE); + + /* T1/J1 or E1 */ + if (IS_T1_FEMEDIA(fe)){ + WRITE_REG(REG_LTRCR, BIT_LTRCR_T1J1E1S); + }else{ + /* E1 | G.775 LOS */ + WRITE_REG(REG_LTRCR, 0x00); + } + + value = 0x00; + switch(WAN_TE1_LBO(fe)) { + case WAN_T1_LBO_0_DB: + value = 0x00; + break; + case WAN_T1_LBO_75_DB: + value = BIT_LTITSR_L2 | BIT_LTITSR_L0; + break; + case WAN_T1_LBO_15_DB: + value = BIT_LTITSR_L2 | BIT_LTITSR_L1; + break; + case WAN_T1_LBO_225_DB: + value = BIT_LTITSR_L2 | BIT_LTITSR_L1 | BIT_LTITSR_L0; + break; + case WAN_T1_0_133: + value = 0x00; + break; + case WAN_T1_133_266: + value = BIT_LTITSR_L0; + break; + case WAN_T1_266_399: + value = BIT_LTITSR_L1; + break; + case WAN_T1_399_533: + value = BIT_LTITSR_L1 | BIT_LTITSR_L0; + break; + case WAN_T1_533_655: + value = BIT_LTITSR_L2; + break; + case WAN_E1_120: + value = BIT_LTITSR_L0; + break; + case WAN_E1_75: + value = 0x00; + break; + default: + if (IS_E1_FEMEDIA(fe)){ + value = BIT_LTITSR_L0; + } + break; + } + if (IS_T1_FEMEDIA(fe)){ + WRITE_REG(REG_LTITSR, value | BIT_LTITSR_TIMPL0); + }else{ + WRITE_REG(REG_LTITSR, + value | BIT_LTITSR_TIMPL1 | BIT_LTITSR_TIMPL0); + } + + value = BIT_LRISMR_RSMS1 | BIT_LRISMR_RSMS0; + if (IS_T1_FEMEDIA(fe)){ + WRITE_REG(REG_LRISMR, value | BIT_LRISMR_RIMPM0); + }else{ + if (WAN_TE1_LBO(fe) == WAN_E1_120){ + value |= BIT_LRISMR_RIMPM1 | BIT_LRISMR_RIMPM0; + } + WRITE_REG(REG_LRISMR, value); + } + + /* Additional front-end settings */ + value = READ_REG(REG_ERCNT); + if (WAN_FE_LCODE(fe) == WAN_LCODE_AMI){ + value &= ~BIT_ERCNT_LCVCRF; + }else{ + value |= BIT_ERCNT_LCVCRF; + } + WRITE_REG(REG_ERCNT, value); + +#if 1 + if (WAN_TE1_ACTIVE_CH(fe) != ENABLE_ALL_CHANNELS){ + unsigned long active_ch = WAN_TE1_ACTIVE_CH(fe); + int channel_range = (IS_T1_FEMEDIA(fe)) ? + NUM_OF_T1_CHANNELS : NUM_OF_E1_TIMESLOTS; + unsigned char rescr, tescr, gfcr; + int i = 0; + + DEBUG_EVENT("%s: %s:%d: Disable channels: ", + fe->name, + FE_MEDIA_DECODE(fe), WAN_FE_LINENO(fe)+1); + for(i = 1; i <= channel_range; i++){ + if (!(active_ch & (1 << (i-1)))){ + _DEBUG_EVENT("%d ", i); + sdla_8te1_TxChanCtrl(fe, i, 0); + sdla_8te1_RxChanCtrl(fe, i, 0); + } + } + _DEBUG_EVENT("\n"); + gfcr = READ_REG(REG_GFCR); + WRITE_REG(REG_GFCR, gfcr | BIT_GFCR_TCBCS | BIT_GFCR_RCBCS); + rescr = READ_REG(REG_RESCR); + WRITE_REG(REG_RESCR, rescr | BIT_RESCR_RGCLKEN); + tescr = READ_REG(REG_TESCR); + WRITE_REG(REG_TESCR, tescr | BIT_TESCR_TGPCKEN); + } +#endif + fe->te_param.max_channels = + (IS_E1_FEMEDIA(fe)) ? NUM_OF_E1_TIMESLOTS: NUM_OF_T1_CHANNELS; + + /* Turn on LIU output */ + WRITE_REG(REG_LMCR, BIT_LMCR_TE); + + /* Initialize and start T1/E1 timer */ + wan_set_bit(TE_TIMER_KILL,(void*)&fe->te_param.critical); + wan_init_timer( + &fe->te_param.timer, + sdla_8te1_timer, + (wan_timer_arg_t)fe); + + /* LIU alarms are available in A108 */ + fe->fe_stats.liu_alarms = WAN_TE_BIT_LIU_ALARM; + + wan_set_bit(TE_CONFIGURED,(void*)&fe->te_param.critical); + + /* Enable interrupts */ + sdla_8te1_intr_ctrl(fe, 0, WAN_TE_INTR_BASIC, WAN_FE_INTR_ENABLE, 0x00); + /* Enable manual update pmon counter */ + sdla_8te1_intr_ctrl(fe, 0, WAN_TE_INTR_PMON, WAN_FE_INTR_MASK, 0x00); + + /* Initialize T1/E1 timer */ + wan_clear_bit(TE_TIMER_KILL,(void*)&fe->te_param.critical); + + /* Start T1/E1 timer */ + sdla_8te1_enable_timer(fe, TE_LINKDOWN_TIMER, POLLING_TE1_TIMER); + + return 0; + +} + +/* + ****************************************************************************** + * sdla_8te1_unconfig() + * + * Description: T1/E1 unconfig. + * Arguments: + * Returns: + ****************************************************************************** + */ +static int sdla_8te1_unconfig(void* pfe) +{ + sdla_fe_t *fe = (sdla_fe_t*)pfe; + + if (!wan_test_bit(TE_CONFIGURED,(void*)&fe->te_param.critical)){ + return -EINVAL; + } + + /* Clear and Kill TE timer poll command */ + wan_clear_bit(TE_CONFIGURED,(void*)&fe->te_param.critical); + wan_set_bit(TE_TIMER_KILL,(void*)&fe->te_param.critical); + + /* FIXME: Alex to disable interrupts here */ + sdla_8te1_intr_ctrl(fe, 0, WAN_TE_INTR_GLOBAL, WAN_FE_INTR_MASK, 0x00); + sdla_8te1_intr_ctrl(fe, 0, WAN_TE_INTR_BASIC, WAN_FE_INTR_MASK, 0x00); + + wan_del_timer(&fe->te_param.timer); + + fe->te_param.timer_cmd = 0x00; + wan_clear_bit(TE_TIMER_RUNNING,(void*)&fe->te_param.critical); + + + return 0; +} + +/* + ****************************************************************************** + * sdla_8te1_post_config() + * + * Description: T1/E1 post configuration. + * Arguments: + * Returns: + ****************************************************************************** + */ +static int sdla_8te1_post_config(sdla_fe_t* fe) +{ +#if 1 + DEBUG_EVENT("ADBG> %s: Unsupported function!\n", fe->name); +#else + unsigned char value; + + if (IS_E1_FEMEDIA(fe)){ + if (WAN_TE1_SIG_MODE(fe) == WAN_TE1_SIG_CAS){ + DEBUG_EVENT("%s: Enable E1 CAS signalling mode!\n", + fe->name); + /* CAS signalling mode */ + value = READ_REG(REG_RCR1); + WRITE_REG(REG_RCR1, value & ~BIT_RCR1_E1_RSIGM); + + value = READ_REG(REG_RSIGC); + WRITE_REG(REG_RSIGC, value | BIT_RSIGC_CASMS); + + }else if (WAN_TE1_SIG_MODE(fe) == WAN_TE1_SIG_CCS){ + DEBUG_EVENT("%s: Disable E1 CAS signalling mode!\n", + fe->name); + /* CCS signalling mode */ + value = READ_REG(REG_RCR1); + WRITE_REG(REG_RCR1, value | BIT_RCR1_E1_RSIGM); + + value = READ_REG(REG_RSIGC); + WRITE_REG(REG_RSIGC, value & ~BIT_RSIGC_CASMS); + } + } +#endif + return 0; +} + +/* + ****************************************************************************** + * sdla_8te1_set_status() + * + * Description: Set T1/E1 status. Enable OOF and LCV interrupt (if status + * changed to disconnected. + * Arguments: + * Returns: + ****************************************************************************** + */ +static void sdla_8te1_set_status(sdla_fe_t* fe, unsigned long alarms) +{ + sdla_t *card = (sdla_t*)fe->card; + unsigned char curr_fe_status = fe->fe_status; + + if (IS_T1_FEMEDIA(fe)){ + if (IS_T1_ALARM(alarms)){ + if (fe->fe_status != FE_DISCONNECTED){ + sdla_8te1_set_alarms(fe, WAN_TE_BIT_YEL_ALARM); + fe->fe_status = FE_DISCONNECTED; + } + }else{ + sdla_8te1_clear_alarms(fe, WAN_TE_BIT_YEL_ALARM); + if (!(fe->fe_alarm & WAN_TE_BIT_YEL_ALARM)){ + if (fe->fe_status != FE_CONNECTED){ + fe->fe_status = FE_CONNECTED; + } + }else{ + fe->fe_status = FE_DISCONNECTED; + } + } + }else{ + if (IS_E1_ALARM(alarms)){ + if (fe->fe_status != FE_DISCONNECTED){ + fe->fe_status = FE_DISCONNECTED; + } + }else{ + if (fe->fe_status != FE_CONNECTED){ + fe->fe_status = FE_CONNECTED; + } + } + } + if (curr_fe_status != fe->fe_status){ + if (fe->fe_status == FE_CONNECTED){ + DEBUG_EVENT("%s: %s connected!\n", + fe->name, + FE_MEDIA_DECODE(fe)); + }else{ + DEBUG_EVENT("%s: %s disconnected!\n", + fe->name, + FE_MEDIA_DECODE(fe)); + } + + } + + if (card->wandev.te_report_alarms){ + card->wandev.te_report_alarms(card, alarms); + } + + return; +} + + +/* +******************************************************************************* +** sdla_te_alaram_print() +** +** Description: +** Arguments: +** Returns: +*/ +static int sdla_8te1_print_alarms(sdla_fe_t* fe, unsigned int alarms) +{ + if (!alarms){ + alarms = fe->fe_alarm; + } + + if (!alarms){ + DEBUG_EVENT("%s: %s Alarms status: No alarms detected!\n", + fe->name, + FE_MEDIA_DECODE(fe)); + return 0; + } + DEBUG_EVENT("%s: %s Framer Alarms status (%X):\n", + fe->name, + FE_MEDIA_DECODE(fe), + alarms); + if (alarms & WAN_TE_BIT_RAI_ALARM){ + DEBUG_EVENT("%s: RAI is ON\n", fe->name); + } + if (alarms & WAN_TE_BIT_LOS_ALARM){ + DEBUG_EVENT("%s: LOS is ON\n", fe->name); + } + if (alarms & WAN_TE_BIT_OOF_ALARM){ + DEBUG_EVENT("%s: OOF is ON\n", fe->name); + } + if (alarms & WAN_TE_BIT_RED_ALARM){ + DEBUG_EVENT("%s: RED is ON\n", fe->name); + } + DEBUG_EVENT("%s: %s LIU Alarms status (%X):\n", + fe->name, + FE_MEDIA_DECODE(fe), + fe->liu_alarm); + if (fe->liu_alarm & WAN_TE_BIT_LIU_ALARM_OC){ + DEBUG_EVENT("%s: Open Circuit is detected!\n", + fe->name); + } + if (fe->liu_alarm & WAN_TE_BIT_LIU_ALARM_SC){ + DEBUG_EVENT("%s: Short Circuit is detected!\n", + fe->name); + } + if (fe->liu_alarm & WAN_TE_BIT_LIU_ALARM_LOS){ + DEBUG_EVENT("%s: Lost of Signal is detected!\n", + fe->name); + } + + return 0; +} + +static unsigned int sdla_8te1_read_alarms(sdla_fe_t *fe, int action) +{ + + if (IS_FE_ALARM_READ(action)){ + unsigned char rrts1 = READ_REG(REG_RRTS1); + unsigned char lrsr = READ_REG(REG_LRSR); + + DEBUG_TE1("%s: Alarm status = %02X\n", + fe->name, rrts1); + /* Framer alarms */ + if (rrts1 & BIT_RRTS1_RRAI){ + fe->fe_alarm |= WAN_TE_BIT_RAI_ALARM; + }else{ + fe->fe_alarm &= ~WAN_TE_BIT_RAI_ALARM; + } + if (rrts1 & BIT_RRTS1_RAIS){ + fe->fe_alarm |= WAN_TE_BIT_AIS_ALARM; + }else{ + fe->fe_alarm &= ~WAN_TE_BIT_AIS_ALARM; + } + if (rrts1 & BIT_RRTS1_RLOS){ + fe->fe_alarm |= WAN_TE_BIT_LOS_ALARM; + }else{ + fe->fe_alarm &= ~WAN_TE_BIT_LOS_ALARM; + } + if (rrts1 & BIT_RRTS1_RLOF){ + fe->fe_alarm |= WAN_TE_BIT_OOF_ALARM; + }else{ + fe->fe_alarm &= ~WAN_TE_BIT_OOF_ALARM; + } + if (IS_T1_FEMEDIA(fe)){ + if (IS_TE_OOF_ALARM(fe->fe_alarm) && + IS_TE_LOS_ALARM(fe->fe_alarm)){ + fe->fe_alarm |= WAN_TE_BIT_RED_ALARM; + }else{ + fe->fe_alarm &= ~WAN_TE_BIT_RED_ALARM; + } + } + + /* LIU alarms */ + if (lrsr & BIT_LRSR_OCS){ + fe->liu_alarm |= WAN_TE_BIT_LIU_ALARM_OC; + }else{ + fe->liu_alarm &= ~WAN_TE_BIT_LIU_ALARM_OC; + } + if (lrsr & BIT_LRSR_SCS){ + fe->liu_alarm |= WAN_TE_BIT_LIU_ALARM_SC; + }else{ + fe->liu_alarm &= ~WAN_TE_BIT_LIU_ALARM_SC; + } + if (lrsr & BIT_LRSR_LOSS){ + fe->liu_alarm |= WAN_TE_BIT_LIU_ALARM_LOS; + }else{ + fe->liu_alarm &= ~WAN_TE_BIT_LIU_ALARM_LOS; + } + } + if (IS_FE_ALARM_PRINT(action)){ + sdla_8te1_print_alarms(fe, fe->fe_alarm); + } + return fe->fe_alarm; +} + +/* +******************************************************************************* +** sdla_8te1_set_alarms() +** +** Description: +** Arguments: +** Returns: +*/ +static int sdla_8te1_set_alarms(sdla_fe_t* fe, unsigned long alarms) +{ + if (alarms & WAN_TE_BIT_YEL_ALARM){ + DEBUG_TEST("%s: Setting YELLOW alarm (not supported)!\n", + fe->name); + } + return 0; +} + +/* +******************************************************************************* +** sdla_8te1_clear_alarms() +** +** Description: +** Arguments: +** Returns: +*/ +static int sdla_8te1_clear_alarms(sdla_fe_t* fe, unsigned long alarms) +{ + if (alarms & WAN_TE_BIT_YEL_ALARM){ + DEBUG_TEST("%s: Clearing YELLOW alarm (not supported)!\n", + fe->name); + } + return 0; +} + +/* + ****************************************************************************** + * sdla_8te1_rbs_report() + * + * Description: + * Arguments: + * Returns: + ****************************************************************************** + */ +static int sdla_8te1_rbs_report(sdla_fe_t* fe) +{ + DEBUG_EVENT("%s: Internal Error (%s:%d)!\n", + fe->name, __FUNCTION__,__LINE__); + return 0; +} + + +/* + ****************************************************************************** + * sdla_8te1_read_rbsbits() + * + * Description: + * Arguments: channo: 1-24 for T1 + * 1-32 for E1 + * Returns: + ****************************************************************************** + */ +static unsigned char sdla_8te1_read_rbsbits(sdla_fe_t* fe, int channo, int mode) +{ + sdla_t* card = (sdla_t*)fe->card; + int rs_offset = 0, range = 0; + unsigned char rbsbits = 0x00, status = 0x00; + + if (IS_E1_FEMEDIA(fe)){ + rs_offset = (channo - 1) % 16; + range = 16; + }else{ + rs_offset = (channo - 1) % 12; + range = 12; + } + rbsbits = READ_REG(REG_RS1 + rs_offset - 1); + if (channo <= range){ + rbsbits = (rbsbits >> 4) & 0x0F; + }else{ + rbsbits &= 0xF; + } + + if (rbsbits & BIT_RS_A) status |= WAN_RBS_SIG_A; + if (rbsbits & BIT_RS_B) status |= WAN_RBS_SIG_B; + if (rbsbits & BIT_RS_C) status |= WAN_RBS_SIG_C; + if (rbsbits & BIT_RS_D) status |= WAN_RBS_SIG_D; + + if (mode & WAN_TE_RBS_UPDATE){ + sdla_8te1_rbs_update(fe, channo, status); + } + + if ((mode & WAN_TE_RBS_REPORT) && card->wandev.te_report_rbsbits){ + card->wandev.te_report_rbsbits( + card, + channo, + status); + } + return status; +} + +/* + ****************************************************************************** + * sdla_te_rbs_update() + * + * Description: + * Arguments: + * Returns: + ****************************************************************************** + */ +static int +sdla_8te1_rbs_update(sdla_fe_t* fe, int channo, unsigned char status) +{ + + if (fe->fe_debug & WAN_FE_DEBUG_RBS_RX_ENABLE){ + DEBUG_EVENT( + "%s: %s:%-3d RX RBS A:%1d B:%1d C:%1d D:%1d\n", + fe->name, + FE_MEDIA_DECODE(fe), + channo, + (status & WAN_RBS_SIG_A) ? 1 : 0, + (status & WAN_RBS_SIG_B) ? 1 : 0, + (status & WAN_RBS_SIG_C) ? 1 : 0, + (status & WAN_RBS_SIG_D) ? 1 : 0); + } + + /* Update rbs value in private structures */ + wan_set_bit(channo, &fe->te_param.rx_rbs_status); + fe->te_param.rx_rbs[channo] = status; + + if (status & WAN_RBS_SIG_A){ + wan_set_bit(channo, + (unsigned long*)&fe->te_param.rx_rbs_A); + }else{ + wan_clear_bit(channo, + (unsigned long*)&fe->te_param.rx_rbs_A); + } + if (status & WAN_RBS_SIG_B){ + wan_set_bit(channo, + (unsigned long*)&fe->te_param.rx_rbs_B); + }else{ + wan_clear_bit(channo, + (unsigned long*)&fe->te_param.rx_rbs_B); + } + if (status & WAN_RBS_SIG_C){ + wan_set_bit(channo, + (unsigned long*)&fe->te_param.rx_rbs_C); + }else{ + wan_clear_bit(channo, + (unsigned long*)&fe->te_param.rx_rbs_C); + } + if (status & WAN_RBS_SIG_D){ + wan_set_bit(channo, + (unsigned long*)&fe->te_param.rx_rbs_D); + }else{ + wan_clear_bit(channo, + (unsigned long*)&fe->te_param.rx_rbs_D); + } + + return 0; +} + +/* + ****************************************************************************** + * sdla_8te1_check_rbsbits() + * + * Description: + * Arguments: + * Returns: + ****************************************************************************** + */ +static int +sdla_8te1_check_rbsbits(sdla_fe_t* fe, int ch_base, unsigned int ts_map, int report) +{ + sdla_t* card = (sdla_t*)fe->card; + unsigned char rs_status = 0x0, rbsbits = 0x00, bit_mask = 0x00; + int rs_reg = 0, rs_offset = 0; + int i = 0, channel, range = 12; + + switch(ch_base){ + case 1: + rs_reg = REG_RSS1; + break; + case 9: + rs_reg = REG_RSS2; + break; + case 17: + rs_reg = REG_RSS3; + break; + case 25: + rs_reg = REG_RSS4; + break; + } + rs_status = READ_REG(rs_reg); + + if (rs_status == 0x00){ + return 0; + } + + if (IS_E1_FEMEDIA(fe)){ + range = 16; + } + for(i = 0; i < 8; i ++) { + channel = ch_base + i; + if (IS_E1_FEMEDIA(fe)){ + if (channel == 1 || channel == 17){ + continue; + } + rs_offset = (channel - 1) % 16; + }else{ + rs_offset = (channel - 1) % 12; + } + /* If this channel/timeslot is not selected, move to + * another channel/timeslot */ + if (!wan_test_bit(channel-1, &ts_map)){ + continue; + } + bit_mask = (1 << i); + if(rs_status & bit_mask) { + unsigned char abcd_status = 0x00; + + rbsbits = READ_REG(REG_RS1 + rs_offset); + DEBUG_TE1("%s: Channel %d RS=%02X Val=%02X\n", + fe->name, channel, REG_RS1+rs_offset, rbsbits); + if (channel > range){ + rbsbits &= 0x0F; + }else{ + rbsbits = (rbsbits >> 4) & 0x0F; + } + + if (rbsbits & BIT_RS_A) abcd_status |= WAN_RBS_SIG_A; + if (rbsbits & BIT_RS_B) abcd_status |= WAN_RBS_SIG_B; + if (rbsbits & BIT_RS_C) abcd_status |= WAN_RBS_SIG_C; + if (rbsbits & BIT_RS_D) abcd_status |= WAN_RBS_SIG_D; + if (IS_E1_FEMEDIA(fe)){ + channel--; + } + + sdla_8te1_rbs_update(fe, channel, abcd_status); + if (report && card->wandev.te_report_rbsbits){ + card->wandev.te_report_rbsbits( + card, + channel, + abcd_status); + } + WRITE_REG(rs_reg, bit_mask); + } + } + return 0; +} + +/* + ****************************************************************************** + * sdla_8te1_set_RBS() + * + * Description: + * Arguments: T1: 1-24 E1: 0-31 + * Returns: + ****************************************************************************** + */ +static int +sdla_8te1_set_rbsbits(sdla_fe_t *fe, int channel, unsigned char status) +{ + int ts_off = 0, range = 0; + unsigned char rbsbits = 0x00, ts_org; + + if (channel > fe->te_param.max_channels){ + DEBUG_EVENT("%s: Invalid channel number %d (%d)\n", + fe->name, channel, fe->te_param.max_channels); + return -EINVAL; + } + + if (IS_E1_FEMEDIA(fe) && (channel == 0 || channel == 16)){ + DEBUG_EVENT("%s: Invalid channel number %d for Rx SIG\n", + fe->name, channel); + return 0; + } + + if (status & WAN_RBS_SIG_A) rbsbits |= BIT_TS_A; + if (status & WAN_RBS_SIG_B) rbsbits |= BIT_TS_B; + if (status & WAN_RBS_SIG_C) rbsbits |= BIT_TS_C; + if (status & WAN_RBS_SIG_D) rbsbits |= BIT_TS_D; + if (fe->fe_debug & WAN_FE_DEBUG_RBS_TX_ENABLE){ + DEBUG_EVENT("%s: %s:%-3d TX RBS A:%1d B:%1d C:%1d D:%1d\n", + fe->name, + FE_MEDIA_DECODE(fe), + channel, + (rbsbits & BIT_TS_A) ? 1 : 0, + (rbsbits & BIT_TS_B) ? 1 : 0, + (rbsbits & BIT_TS_C) ? 1 : 0, + (rbsbits & BIT_TS_D) ? 1 : 0); + } + if (rbsbits & BIT_TS_A){ + wan_set_bit(channel,(unsigned long*)&fe->te_param.tx_rbs_A); + }else{ + wan_clear_bit(channel,(unsigned long*)&fe->te_param.tx_rbs_A); + } + if (rbsbits & BIT_TS_B){ + wan_set_bit(channel,(unsigned long*)&fe->te_param.tx_rbs_B); + }else{ + wan_clear_bit(channel,(unsigned long*)&fe->te_param.tx_rbs_B); + } + if (rbsbits & BIT_TS_C){ + wan_set_bit(channel,(unsigned long*)&fe->te_param.tx_rbs_C); + }else{ + wan_clear_bit(channel,(unsigned long*)&fe->te_param.tx_rbs_C); + } + if (rbsbits & BIT_TS_D){ + wan_set_bit(channel,(unsigned long*)&fe->te_param.tx_rbs_D); + }else{ + wan_clear_bit(channel,(unsigned long*)&fe->te_param.tx_rbs_D); + } + if (IS_E1_FEMEDIA(fe)){ + ts_off = channel % 16; + range = 15; + }else{ + ts_off = (channel - 1) % 12; + range = 12; + } + ts_org = READ_REG(REG_TS1 + ts_off); + if (channel <= range){ + rbsbits = rbsbits << 4; + ts_org &= 0xF; + }else{ + ts_org &= 0xF0; + } + + DEBUG_TE1("%s: TS=%02X Val=%02X\n", + fe->name, + REG_TS1+ts_off, + rbsbits); + + WRITE_REG(REG_TS1 + ts_off, ts_org | rbsbits); + return 0; +} +/* + ****************************************************************************** + * sdla_te_rbs_print_banner() + * + * Description: + * Arguments: + * Returns: + ****************************************************************************** + */ +static int +sdla_8te1_rbs_print_banner(sdla_fe_t* fe) +{ + if (IS_T1_FEMEDIA(fe)){ + DEBUG_EVENT("%s: 111111111122222\n", + fe->name); + DEBUG_EVENT("%s: 123456789012345678901234\n", + fe->name); + DEBUG_EVENT("%s: ------------------------\n", + fe->name); + }else{ + DEBUG_EVENT("%s: 11111111112222222222333\n", + fe->name); + DEBUG_EVENT("%s: 12345678901234567890123456789012\n", + fe->name); + DEBUG_EVENT("%s: --------------------------------\n", + fe->name); + } + return 0; +} + +/* + ****************************************************************************** + * sdla_8te1_rbs_print_bits() + * + * Description: + * Arguments: + * Returns: + ****************************************************************************** + */ +static int +sdla_8te1_rbs_print_bits(sdla_fe_t* fe, unsigned long bits, char *msg) +{ + int i, max_channels = fe->te_param.max_channels; + int start_chan = 1; + + if (IS_E1_FEMEDIA(fe)){ + start_chan = 0; + } + _DEBUG_EVENT("%s: %s ", fe->name, msg); + for(i=start_chan; i <= max_channels; i++) + _DEBUG_EVENT("%01d", + wan_test_bit(i, &bits) ? 1 : 0); + _DEBUG_EVENT("\n"); + return 0; +} + +/* + ****************************************************************************** + * sdla_8te1_rbs_print() + * + * Description: + * Arguments: + * Returns: + ****************************************************************************** + */ +static int +sdla_8te1_rbs_print(sdla_fe_t* fe, int last_status) +{ + unsigned long rx_a = 0x00; + unsigned long rx_b = 0x00; + unsigned long rx_c = 0x00; + unsigned long rx_d = 0x00; + + if (last_status){ + rx_a = fe->te_param.rx_rbs_A; + rx_b = fe->te_param.rx_rbs_B; + rx_c = fe->te_param.rx_rbs_C; + rx_d = fe->te_param.rx_rbs_D; + + DEBUG_EVENT("%s: Last Status:\n", + fe->name); + sdla_8te1_rbs_print_banner(fe); + sdla_8te1_rbs_print_bits(fe, fe->te_param.tx_rbs_A, "TX A:"); + sdla_8te1_rbs_print_bits(fe, fe->te_param.tx_rbs_B, "TX B:"); + sdla_8te1_rbs_print_bits(fe, fe->te_param.tx_rbs_C, "TX C:"); + sdla_8te1_rbs_print_bits(fe, fe->te_param.tx_rbs_D, "TX D:"); + DEBUG_EVENT("%s:\n", fe->name); + }else{ + int i, chan = 0; + unsigned char abcd = 0x00; + for(i = 1; i <= fe->te_param.max_channels; i++) { + + abcd = sdla_8te1_read_rbsbits(fe, i, WAN_TE_RBS_NONE); + + chan = (IS_E1_FEMEDIA(fe))? i - 1 : i; + if (abcd & WAN_RBS_SIG_A){ + wan_set_bit(chan, &rx_a); + } + if (abcd & WAN_RBS_SIG_B){ + wan_set_bit(chan, &rx_b); + } + if (abcd & WAN_RBS_SIG_C){ + wan_set_bit(chan, &rx_c); + } + if (abcd & WAN_RBS_SIG_D){ + wan_set_bit(chan, &rx_d); + } + } + DEBUG_EVENT("%s: Current Status:\n", + fe->name); + sdla_8te1_rbs_print_banner(fe); + } + + sdla_8te1_rbs_print_bits(fe, rx_a, "RX A:"); + sdla_8te1_rbs_print_bits(fe, rx_b, "RX B:"); + sdla_8te1_rbs_print_bits(fe, rx_c, "RX C:"); + sdla_8te1_rbs_print_bits(fe, rx_d, "RX D:"); + return 0; +} + +/* + ****************************************************************************** + * sdla_8te1_intr_ctrl() + * + * Description: Check interrupt type. + * Arguments: card - pointer to device structure. + * write_register - write register function. + * read_register - read register function. + * Returns: None. + ****************************************************************************** + */ +static int +sdla_8te1_intr_ctrl(sdla_fe_t *fe, int dummy, int type, int mode, unsigned int ts_map) +{ + unsigned char mask, value; + unsigned char rscse, ssie; + int ch, bit, off; + + WAN_ASSERT(fe->write_fe_reg == NULL); + WAN_ASSERT(fe->read_fe_reg == NULL); + if (!wan_test_bit(TE_CONFIGURED,(void*)&fe->te_param.critical)){ + return 0; + } + switch(type){ + case WAN_TE_INTR_GLOBAL: + mask = READ_REG(REG_GFIMR); + if (mode == WAN_FE_INTR_ENABLE){ + mask |= (1<te_param.max_channels; ch++){ + if (!wan_test_bit(ch, &ts_map)){ + continue; + } + if (IS_T1_FEMEDIA(fe)){ + bit = (ch-1) % 8; + off = (ch-1) / 8; + }else{ + if (ch == 16) continue; + bit = ch % 8; + off = ch / 8; + } + rscse = READ_REG(REG_RSCSE1+off); + ssie = READ_REG(REG_SSIE1+off); + if (mode == WAN_FE_INTR_ENABLE){ + rscse |= (1<name, ch, REG_RSCSE1+off, rscse); + WRITE_REG(REG_RSCSE1+off, rscse); + DEBUG_TEST("%s: Ch %d SSIE=%02X Val=%02X\n", + fe->name, ch, REG_SSIE1+off, ssie); + WRITE_REG(REG_SSIE1+off, ssie); + } + break; + + case WAN_TE_INTR_PMON: + value = READ_REG(REG_ERCNT); + if (mode == WAN_FE_INTR_ENABLE){ + value &= ~BIT_ERCNT_EAMS; + }else{ + value |= BIT_ERCNT_EAMS; + } + WRITE_REG(REG_ERCNT, value); + break; + + default: + DEBUG_EVENT("%s: Unsupported interrupt type %X!\n", + fe->name, type); + return -EINVAL; + } + + return 0; +} + + +static int sdla_8te1_framer_rx_intr(sdla_fe_t *fe) +{ + unsigned char istatus; + + istatus = READ_REG(REG_RIIR); + if (istatus & BIT_RIIR_RLS1){ + unsigned char rls1 = READ_REG(REG_RLS1); + unsigned char rrts1 = READ_REG(REG_RRTS1); + + if (rls1 & (BIT_RLS1_RRAIC|BIT_RLS1_RRAID)){ + if (rrts1 & BIT_RRTS1_RRAI){ + fe->fe_alarm |= WAN_TE_BIT_RAI_ALARM; + DEBUG_EVENT("%s: RAI alarm is ON\n", + fe->name); + }else{ + fe->fe_alarm &= ~WAN_TE_BIT_RAI_ALARM; + DEBUG_EVENT("%s: RAI alarm is OFF\n", + fe->name); + } + } + if (rls1 & (BIT_RLS1_RAISC|BIT_RLS1_RAISD)){ + if (rrts1 & BIT_RRTS1_RAIS){ + fe->fe_alarm |= WAN_TE_BIT_AIS_ALARM; + DEBUG_EVENT("%s: AIS alarm is ON\n", + fe->name); + }else{ + fe->fe_alarm &= ~WAN_TE_BIT_AIS_ALARM; + DEBUG_EVENT("%s: AIS alarm is OFF\n", + fe->name); + } + } + if (rls1 & (BIT_RLS1_RLOSC|BIT_RLS1_RLOSD)){ + if (rrts1 & BIT_RRTS1_RLOS){ + fe->fe_alarm |= WAN_TE_BIT_LOS_ALARM; + DEBUG_EVENT("%s: LOS alarm is ON\n", + fe->name); + }else{ + fe->fe_alarm &= ~WAN_TE_BIT_LOS_ALARM; + DEBUG_EVENT("%s: LOS alarm is OFF\n", + fe->name); + } + } + if (rls1 & (BIT_RLS1_RLOFC|BIT_RLS1_RLOFD)){ + if (rrts1 & BIT_RRTS1_RLOF){ + fe->fe_alarm |= WAN_TE_BIT_OOF_ALARM; + DEBUG_EVENT("%s: OOF alarm is ON\n", + fe->name); + }else{ + fe->fe_alarm &= ~WAN_TE_BIT_OOF_ALARM; + DEBUG_EVENT("%s: OOF alarm is OFF\n", + fe->name); + } + } + WRITE_REG(REG_RLS1, 0xFF); + if (IS_T1_FEMEDIA(fe)){ + if (IS_TE_OOF_ALARM(fe->fe_alarm) && + IS_TE_LOS_ALARM(fe->fe_alarm)){ + DEBUG_EVENT("%s: RED alarm is ON\n", + fe->name); + fe->fe_alarm |= WAN_TE_BIT_RED_ALARM; + }else{ + DEBUG_EVENT("%s: RED alarm is OFF\n", + fe->name); + fe->fe_alarm &= ~WAN_TE_BIT_RED_ALARM; + } + } + } + if (istatus & BIT_RIIR_RLS2){ + unsigned char rls2 = READ_REG(REG_RLS2); + if (IS_E1_FEMEDIA(fe)){ + if (rls2 & BIT_RLS2_E1_RSA1){ + DEBUG_EVENT( + "%s: Receive Signalling All Ones Event!\n", + fe->name); + } + if (rls2 & BIT_RLS2_E1_RSA0){ + DEBUG_EVENT( + "%s: Receive Signalling All Ones Event!\n", + fe->name); + } + if (rls2 & BIT_RLS2_E1_RCMF){ + DEBUG_EVENT( + "%s: Receive CRC4 Multiframe Event!\n", + fe->name); + } + if (rls2 & BIT_RLS2_E1_RAF){ + DEBUG_EVENT( + "%s: Receive Align Frame Event!\n", + fe->name); + } + } + WRITE_REG(REG_RLS2, 0xFF); + } + if (istatus & BIT_RIIR_RLS3){ + unsigned char rls3 = READ_REG(REG_RLS3); + if (IS_T1_FEMEDIA(fe)){ + if (rls3 & BIT_RLS3_T1_LORCC){ + DEBUG_EVENT( + "%s: Loss of Receive Clock Condition Clear!\n", + fe->name); + } + if (rls3 & BIT_RLS3_T1_LORCD){ + DEBUG_EVENT( + "%s: Loss of Receive Clock Condition Detect!\n", + fe->name); + } + }else{ + if (rls3 & BIT_RLS3_E1_LORCC){ + DEBUG_EVENT( + "%s: Loss of Receive Clock Condition Clear!\n", + fe->name); + } + if (rls3 & BIT_RLS3_E1_LORCD){ + DEBUG_EVENT( + "%s: Loss of Receive Clock Condition Detect!\n", + fe->name); + } + } + WRITE_REG(REG_RLS3, 0xFF); + } + if (istatus & BIT_RIIR_RLS4){ + unsigned char rls4 = READ_REG(REG_RLS4); + if (rls4 & BIT_RLS4_RSCOS){ + DEBUG_EVENT( + "%s: Receive Signalling status changed!\n", + fe->name); + sdla_8te1_check_rbsbits(fe, 1, ENABLE_ALL_CHANNELS, 1); + sdla_8te1_check_rbsbits(fe, 9, ENABLE_ALL_CHANNELS, 1); + sdla_8te1_check_rbsbits(fe, 17, ENABLE_ALL_CHANNELS, 1); + if (IS_E1_FEMEDIA(fe)){ + sdla_8te1_check_rbsbits(fe, 25, ENABLE_ALL_CHANNELS, 1); + } + } + if (rls4 & BIT_RLS4_TIMER){ + DEBUG_TEST( + "%s: Performance monitor counters have been updated!\n", + fe->name); + sdla_8te1_pmon(fe, WAN_FE_PMON_READ); + } + WRITE_REG(REG_RLS4, 0xFF); + } + if (istatus & BIT_RIIR_RLS5){ + DEBUG_EVENT("%s: Internal Error (%s:%d)!\n", + fe->name, __FUNCTION__,__LINE__); + WRITE_REG(REG_RLS5, 0xFF); + } + if (istatus & BIT_RIIR_RLS6){ + DEBUG_EVENT("%s: Internal Error (%s:%d)!\n", + fe->name, __FUNCTION__,__LINE__); + WRITE_REG(REG_RLS6, 0xFF); + } + if (istatus & BIT_RIIR_RLS7){ + DEBUG_EVENT("%s: Internal Error (%s:%d)!\n", + fe->name, __FUNCTION__,__LINE__); + WRITE_REG(REG_RLS7, 0xFF); + } + + return 0; +} + +static int sdla_8te1_framer_tx_intr(sdla_fe_t *fe) +{ + unsigned char istatus; + unsigned char status; + + istatus = READ_REG(REG_TIIR); + if (istatus & BIT_TIIR_TLS1){ + status = READ_REG(REG_TLS1); + if (status & BIT_TLS1_TPDV){ + DEBUG_EVENT( + "%s: Transmit Pulse Density Violation Event!\n", + fe->name); + } + if (status & BIT_TLS1_LOTCC){ + DEBUG_EVENT( + "%s: Loss of Transmit Clock condition Clear!\n", + fe->name); + } + WRITE_REG(REG_TLS1, 0xFF); + } + if (istatus & BIT_TIIR_TLS2){ + DEBUG_EVENT("%s: Internal Error (%s:%d)!\n", + fe->name, __FUNCTION__,__LINE__); + WRITE_REG(REG_TLS2, 0xFF); + } + if (istatus & BIT_TIIR_TLS3){ + DEBUG_EVENT("%s: Internal Error (%s:%d)!\n", + fe->name, __FUNCTION__,__LINE__); + WRITE_REG(REG_TLS3, 0xFF); + } + return 0; +} + +static int sdla_8te1_bert_intr(sdla_fe_t *fe) +{ + DEBUG_EVENT("%s: Internal Error (%s:%d)!\n", + fe->name, __FUNCTION__,__LINE__); + WRITE_REG(REG_BLSR, 0xFF); + return 0; +} + +static int sdla_8te1_liu_intr(sdla_fe_t *fe) +{ + unsigned char llsr = READ_REG(REG_LLSR); + unsigned char lrsr = READ_REG(REG_LRSR); + + if (llsr & BIT_LLSR_JALTC){ + DEBUG_EVENT("%s: Jitter Attenuator Limit Trip Clear!\n", + fe->name); + } + if (llsr & BIT_LLSR_JALTS){ + DEBUG_EVENT("%s: Jitter Attenuator Limit Trip Set!\n", + fe->name); + } + if (llsr & (BIT_LLSR_OCC | BIT_LLSR_OCD)){ + if (lrsr & BIT_LRSR_OCS){ + if (!(fe->liu_alarm & WAN_TE_BIT_LIU_ALARM_OC)){ + DEBUG_EVENT("%s: Open Circuit is detected!\n", + fe->name); + fe->liu_alarm |= WAN_TE_BIT_LIU_ALARM_OC; + } + }else{ + if (fe->liu_alarm & WAN_TE_BIT_LIU_ALARM_OC){ + DEBUG_EVENT("%s: Open Circuit is cleared!\n", + fe->name); + fe->liu_alarm &= ~WAN_TE_BIT_LIU_ALARM_OC; + } + } + } + if (llsr & (BIT_LLSR_SCC | BIT_LLSR_SCD)){ + if (lrsr & BIT_LRSR_SCS){ + if (!(fe->liu_alarm & WAN_TE_BIT_LIU_ALARM_SC)){ + DEBUG_EVENT("%s: Short Circuit is detected!\n", + fe->name); + fe->liu_alarm |= WAN_TE_BIT_LIU_ALARM_SC; + } + }else{ + if (fe->liu_alarm & WAN_TE_BIT_LIU_ALARM_SC){ + DEBUG_EVENT("%s: Short Circuit is cleared!\n", + fe->name); + fe->liu_alarm &= ~WAN_TE_BIT_LIU_ALARM_SC; + } + } + } + if (llsr & (BIT_LLSR_LOSC | BIT_LLSR_LOSD)){ + if (lrsr & BIT_LRSR_LOSS){ + if (!(fe->liu_alarm & WAN_TE_BIT_LIU_ALARM_LOS)){ + DEBUG_EVENT("%s: Lost of Signal is detected!\n", + fe->name); + fe->liu_alarm |= WAN_TE_BIT_LIU_ALARM_LOS; + } + }else{ + if (fe->liu_alarm & WAN_TE_BIT_LIU_ALARM_LOS){ + DEBUG_EVENT("%s: Lost of Signal is cleared!\n", + fe->name); + fe->liu_alarm &= ~WAN_TE_BIT_LIU_ALARM_LOS; + } + } + } + WRITE_REG(REG_LLSR, llsr); + return 0; +} + +static int sdla_8te1_check_intr(sdla_fe_t *fe) +{ + unsigned char framer_istatus; + unsigned char liu_istatus; + unsigned char bert_istatus; + + WAN_ASSERT(fe->write_fe_reg == NULL); + WAN_ASSERT(fe->read_fe_reg == NULL); + + if (!wan_test_bit(TE_CONFIGURED,(void*)&fe->te_param.critical)){ + return 0; + } + + framer_istatus = __READ_REG(REG_GFISR); + liu_istatus = __READ_REG(REG_GLISR); + bert_istatus = __READ_REG(REG_GBISR); + + if (framer_istatus & (1 << WAN_FE_LINENO(fe))){ + DEBUG_ISR("%s: Interrupt for line %d (framer)\n", + fe->name, WAN_FE_LINENO(fe)); + return 1; + } + if (liu_istatus & (1 << WAN_FE_LINENO(fe))){ + DEBUG_ISR("%s: Interrupt for line %d (liu)\n", + fe->name, WAN_FE_LINENO(fe)); + return 1; + } + if (bert_istatus & (1 << WAN_FE_LINENO(fe))){ + DEBUG_ISR("%s: Interrupt for line %d (bert)\n", + fe->name, WAN_FE_LINENO(fe)); + return 1; + } + DEBUG_ISR("%s: This interrupt not for this port %d\n", + fe->name, + WAN_FE_LINENO(fe)+1); + return 0; +} + +static int sdla_8te1_intr(sdla_fe_t *fe) +{ + unsigned char status = fe->fe_status; + unsigned char framer_istatus; + unsigned char liu_istatus; + unsigned char bert_istatus; + + WAN_ASSERT(fe->write_fe_reg == NULL); + WAN_ASSERT(fe->read_fe_reg == NULL); + + framer_istatus = READ_REG(REG_GFISR); + liu_istatus = READ_REG(REG_GLISR); + bert_istatus = READ_REG(REG_GBISR); + + if (framer_istatus & (1 << WAN_FE_LINENO(fe))){ + sdla_8te1_framer_rx_intr(fe); + sdla_8te1_framer_tx_intr(fe); + WRITE_REG(REG_GFISR, (1<name,fe->fe_alarm); + + sdla_8te1_set_status(fe, fe->fe_alarm); + if (status != fe->fe_status){ + if (fe->fe_status == FE_DISCONNECTED){ + /* AL: March 1, 2006: Mask global FE intr */ + sdla_8te1_intr_ctrl(fe, 0, WAN_TE_INTR_GLOBAL, WAN_FE_INTR_MASK, 0x00); + /* Disable automatic update */ + sdla_8te1_intr_ctrl(fe, 0, WAN_TE_INTR_PMON, WAN_FE_INTR_MASK, 0x00); + /* Start LINKDOWN poll */ + sdla_8te1_enable_timer( + fe, + TE_LINKDOWN_TIMER, + POLLING_TE1_TIMER*5); + } + } + return 0; +} + +/* + ****************************************************************************** + * sdla_8te1_timer() + * + * Description: + * Arguments: + * Returns: + ****************************************************************************** + */ +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) +static void sdla_8te1_timer(void* pfe) +#elif defined(__WINDOWS__) +static void sdla_8te1_timer(IN PKDPC Dpc, void* pfe, void* arg2, void* arg3) +#else +static void sdla_8te1_timer(unsigned long pfe) +#endif +{ + sdla_fe_t *fe = (sdla_fe_t*)pfe; + sdla_t *card = (sdla_t*)fe->card; + wan_device_t *wandev = &card->wandev; + + if (wan_test_bit(TE_TIMER_KILL,(void*)&fe->te_param.critical)){ + wan_clear_bit(TE_TIMER_RUNNING,(void*)&fe->te_param.critical); + return; + } + /*WAN_ASSERT1(wandev->te_enable_timer == NULL); */ + DEBUG_TIMER("%s: TE1 timer!\n", fe->name); + /* Enable hardware interrupt for TE1 */ + + if (wandev->fe_enable_timer){ + wandev->fe_enable_timer(fe->card); + }else{ + sdla_8te1_polling(fe); + } + + return; +} + +/* + ****************************************************************************** + * sdla_8te1_enable_timer() + * + * Description: Enable software timer interrupt in delay ms. + * Arguments: + * Returns: + ****************************************************************************** + */ +static void sdla_8te1_enable_timer(sdla_fe_t* fe, unsigned char cmd, unsigned long delay) +{ + sdla_t *card = (sdla_t*)fe->card; + + WAN_ASSERT1(card == NULL); + + DEBUG_TIMER("%s: %s:%d Cmd=0x%X\n", + fe->name,__FUNCTION__,__LINE__,cmd); + +#if defined (__WINDOWS__) + if(KeGetCurrentIrql() > DISPATCH_LEVEL){ + /* May get here on AFT card because front end interrupt + is handled inside ISR not in DPC as on S514. + The KeSetTimer() function is illegal inside ISR, + so queue 'front_end_dpc_obj' DPC and this routine + will be called again from xilinx_front_end_dpc(). + */ + card->xilinx_fe_dpc.te_timer_delay = delay; + fe->te_param.timer_cmd=(unsigned char)cmd; + + if(KeInsertQueueDpc(&card->front_end_dpc_obj, NULL, + (PVOID)ENABLE_TE_TIMER) == FALSE){ + + DEBUG_TE1("Failed to queue 'front_end_dpc_obj'!\n"); + }else{ + DEBUG_TEST("Successfully queued 'front_end_dpc_obj'.\n"); + } + return; + }/* if() */ +#endif + if (wan_test_bit(TE_TIMER_KILL,(void*)&fe->te_param.critical)){ + wan_clear_bit( + TE_TIMER_RUNNING, + (void*)&fe->te_param.critical); + return; + } + + if (wan_test_bit(TE_TIMER_RUNNING,(void*)&fe->te_param.critical)){ + if (fe->te_param.timer_cmd == cmd){ + /* Just ignore current request */ + return; + } + DEBUG_TEST("%s: TE_TIMER_RUNNING: new_cmd=%X curr_cmd=%X\n", + fe->name, + cmd, + fe->te_param.timer_cmd); + return; + } + + wan_set_bit(TE_TIMER_RUNNING,(void*)&fe->te_param.critical); + + fe->te_param.timer_cmd=cmd; + + wan_add_timer(&fe->te_param.timer, delay * HZ / 1000); + return; +} + +/* + ****************************************************************************** + * sdla_8te1_polling() + * + * Description: + * Arguments: + * Returns: + ****************************************************************************** + */ +static int sdla_8te1_polling(sdla_fe_t* fe) +{ + sdla_t *card = (sdla_t*)fe->card; + + WAN_ASSERT(fe->write_fe_reg == NULL); + WAN_ASSERT(fe->read_fe_reg == NULL); + + DEBUG_TIMER("%s: TE1 Polling State=%s Cmd=0x%X!\n", + fe->name, fe->fe_status==FE_CONNECTED?"Con":"Disconn", + fe->te_param.timer_cmd); + + wan_clear_bit(TE_TIMER_RUNNING,(void*)&fe->te_param.critical); + + switch(fe->te_param.timer_cmd){ + case TE_LINKDOWN_TIMER: + sdla_8te1_read_alarms(fe, WAN_FE_ALARM_READ); + sdla_8te1_pmon(fe, WAN_FE_PMON_UPDATE); + sdla_8te1_set_status(fe, fe->fe_alarm); + if (fe->fe_status == FE_CONNECTED){ + sdla_8te1_enable_timer(fe, TE_LINKUP_TIMER, POLLING_TE1_TIMER); + }else{ + sdla_8te1_enable_timer(fe, TE_LINKDOWN_TIMER, POLLING_TE1_TIMER); + } + break; + + case TE_LINKUP_TIMER: + /* ALEX: + ** Do not update protocol front end state from TE_LINKDOWN_TIMER + ** because it cause to stay longer in interrupt handler + ** (critical for XILINX code) */ + if (fe->fe_status == FE_CONNECTED){ + /* Enable Basic Interrupt */ + sdla_8te1_intr_ctrl(fe, 0, WAN_TE_INTR_GLOBAL, WAN_FE_INTR_ENABLE, 0x00); + /* Enable automatic update pmon counters */ + sdla_8te1_intr_ctrl(fe, 0, WAN_TE_INTR_PMON, WAN_FE_INTR_ENABLE, 0x00); + if (card->wandev.te_link_state){ + card->wandev.te_link_state(card); + } + }else{ + sdla_8te1_enable_timer(fe, TE_LINKDOWN_TIMER, POLLING_TE1_TIMER); + } + break; + + case TE_RBS_READ: + /* Physically read RBS status and print */ + sdla_8te1_rbs_print(fe, 0); + break; + + case TE_SET_RBS: + /* Set RBS bits */ + DEBUG_TE1("%s: Set ABCD bits (%X) for channel %d!\n", + fe->name, + fe->te_param.timer_abcd, + fe->te_param.timer_channel); + sdla_8te1_set_rbsbits(fe, fe->te_param.timer_channel, fe->te_param.timer_abcd); + fe->te_param.timer_channel = 0; + fe->te_param.timer_abcd = 0; + break; + + default: + DEBUG_EVENT("%s: T1/E1 Polling cmd %X (Internal Error %s:%d)\n", + fe->name, fe->te_param.timer_cmd, + __FUNCTION__,__LINE__); + break; + } + return 0; +} + +/* + ****************************************************************************** + * sdla_8te1_flush_pmon() + * + * Description: Flush Dallas performance monitoring counters + * Arguments: + * Returns: + ****************************************************************************** + */ +static int sdla_8te1_flush_pmon(sdla_fe_t *fe) +{ + sdla_te_pmon_t *pmon = &fe->fe_stats.u.te_pmon; + pmon->lcv_errors = 0; + pmon->oof_errors = 0; + pmon->bee_errors = 0; + pmon->crc4_errors = 0; + pmon->feb_errors = 0; + pmon->fas_errors = 0; + return 0; +} + +/* + ****************************************************************************** + * sdla_8te1_pmon() + * + * Description: Read DLS performance monitoring counters + * Arguments: + * Returns: + ****************************************************************************** + */ +static int sdla_8te1_pmon(sdla_fe_t *fe, int action) +{ + sdla_te_pmon_t *pmon = &fe->fe_stats.u.te_pmon; + u16 pmon1 = 0, pmon2 = 0, pmon3 = 0, pmon4 = 0; + + WAN_ASSERT(fe->write_fe_reg == NULL); + WAN_ASSERT(fe->read_fe_reg == NULL); + + if (IS_FE_PMON_UPDATE(action)){ + unsigned char ercnt = READ_REG(REG_ERCNT); + WRITE_REG(REG_ERCNT, ercnt | BIT_ERCNT_MECU); + WP_DELAY(250); + WRITE_REG(REG_ERCNT, ercnt); + } + + pmon->mask = 0x00; + /* Line code violation count register */ + pmon1 = READ_REG(REG_LCVCR1) << 8 | READ_REG(REG_LCVCR2); + /* Path code violation count for E1/T1 */ + pmon2 = READ_REG(REG_PCVCR1) << 8 | READ_REG(REG_PCVCR2); + /* OOF Error for T1/E1 */ + pmon3 = READ_REG(REG_FOSCR1) << 8 | READ_REG(REG_FOSCR2); + if (IS_E1_FEMEDIA(fe)){ + /* E-bit counter (Far End Block Errors) */ + pmon4 = READ_REG(REG_E1EBCR1) << 8 | READ_REG(REG_E1EBCR2); + } + + pmon->mask |= WAN_TE_BIT_PMON_LCV; + pmon->lcv_errors += pmon1; + if (IS_T1_FEMEDIA(fe)){ + pmon->mask |= WAN_TE_BIT_PMON_BEE; + pmon->bee_errors += pmon2; + pmon->mask |= WAN_TE_BIT_PMON_OOF; + pmon->oof_errors += pmon3; + }else{ + pmon->mask |= WAN_TE_BIT_PMON_CRC4; + pmon->crc4_errors += pmon2; + pmon->mask |= WAN_TE_BIT_PMON_FAS; + pmon->fas_errors += pmon3; + pmon->mask |= WAN_TE_BIT_PMON_FEB; + pmon->feb_errors += pmon4; + } + + if (IS_FE_PMON_PRINT(action)){ + DEBUG_EVENT("%s: Line Code Viilation: %ld\n", + fe->name, pmon->lcv_errors); + if (IS_T1_FEMEDIA(fe)){ + DEBUG_EVENT("%s: Bit error events: %ld\n", + fe->name, pmon->bee_errors); + DEBUG_EVENT("%s: Frames out of sync: %ld\n", + fe->name, pmon->oof_errors); + }else{ + DEBUG_EVENT("%s: CRC4 errors: %ld\n", + fe->name, pmon->crc4_errors); + DEBUG_EVENT("%s: Frame Alignment signal errors: %ld\n", + fe->name, pmon->fas_errors); + DEBUG_EVENT("%s: Far End Block errors: %ld\n", + fe->name, pmon->feb_errors); + } + } + return 0; +} + + +/* + ****************************************************************************** + * sdla_8te1_liu_alb() + * + * Description: + * Arguments: + * Returns: + ****************************************************************************** + */ +static int sdla_8te1_liu_alb(sdla_fe_t* fe, unsigned char mode) +{ + unsigned char value; + + WAN_ASSERT(fe->write_fe_reg == NULL); + WAN_ASSERT(fe->read_fe_reg == NULL); + + value = READ_REG(REG_LMCR); + if (mode == WAN_TE1_ACTIVATE_LB){ + value |= BIT_LMCR_ALB; + }else{ + value &= ~BIT_LMCR_ALB; + } + WRITE_REG(REG_LMCR, value); + return 0; +} + +/* + ****************************************************************************** + * sdla_8te1_liu_llb() + * + * Description: + * Arguments: + * Returns: + ****************************************************************************** + */ +static int sdla_8te1_liu_llb(sdla_fe_t* fe, unsigned char mode) +{ + unsigned char value; + + WAN_ASSERT(fe->write_fe_reg == NULL); + WAN_ASSERT(fe->read_fe_reg == NULL); + + value = READ_REG(REG_LMCR); + if (mode == WAN_TE1_ACTIVATE_LB){ + value |= BIT_LMCR_LLB; + }else{ + value &= ~BIT_LMCR_LLB; + } + WRITE_REG(REG_LMCR, value); + return 0; +} + +/* + ****************************************************************************** + * sdla_8te1_liu_rlb() + * + * Description: + * Arguments: + * Returns: + ****************************************************************************** + */ +static int sdla_8te1_liu_rlb(sdla_fe_t* fe, unsigned char mode) +{ + unsigned char value; + + WAN_ASSERT(fe->write_fe_reg == NULL); + WAN_ASSERT(fe->read_fe_reg == NULL); + + value = READ_REG(REG_LMCR); + if (mode == WAN_TE1_ACTIVATE_LB){ + value |= BIT_LMCR_RLB; + }else{ + value &= ~BIT_LMCR_RLB; + } + WRITE_REG(REG_LMCR, value); + return 0; +} + +/* + ****************************************************************************** + * sdla_8te1_fr_flb() + * + * Description: + * Arguments: + * Returns: + ****************************************************************************** + */ +static int sdla_8te1_fr_flb(sdla_fe_t* fe, unsigned char mode) +{ + unsigned char value; + + WAN_ASSERT(fe->write_fe_reg == NULL); + WAN_ASSERT(fe->read_fe_reg == NULL); + + value = READ_REG(REG_RCR3); + if (mode == WAN_TE1_ACTIVATE_LB){ + value |= BIT_RCR3_FLB; + }else{ + value &= ~BIT_RCR3_FLB; + } + WRITE_REG(REG_LMCR, value); + return 0; +} + +/* + ****************************************************************************** + * sdla_8te1_fr_plb() + * + * Description: + * Arguments: + * Returns: + ****************************************************************************** + */ +static int sdla_8te1_fr_plb(sdla_fe_t* fe, unsigned char mode) +{ + unsigned char value; + + WAN_ASSERT(fe->write_fe_reg == NULL); + WAN_ASSERT(fe->read_fe_reg == NULL); + + value = READ_REG(REG_RCR3); + if (mode == WAN_TE1_ACTIVATE_LB){ + value |= BIT_RCR3_PLB; + }else{ + value &= ~BIT_RCR3_PLB; + } + WRITE_REG(REG_LMCR, value); + return 0; +} + +/* + ****************************************************************************** + * sdla_8te1_set_lbmode() + * + * Description: + * Arguments: + * Returns: + ****************************************************************************** + */ +static int +sdla_8te1_set_lbmode(sdla_fe_t *fe, unsigned char type, unsigned char mode) +{ + + WAN_ASSERT(fe->write_fe_reg == NULL); + WAN_ASSERT(fe->read_fe_reg == NULL); + DEBUG_EVENT("%s: %s %s mode...\n", + fe->name, + WAN_TE1_LB_MODE_DECODE(mode), + WAN_TE1_LB_TYPE_DECODE(type)); + switch(type){ + case WAN_TE1_LIU_ALB_MODE: + sdla_8te1_liu_alb(fe, mode); + break; + case WAN_TE1_LIU_LLB_MODE: + sdla_8te1_liu_llb(fe, mode); + break; + case WAN_TE1_LIU_RLB_MODE: + sdla_8te1_liu_rlb(fe, mode); + break; + case WAN_TE1_LIU_DLB_MODE: + sdla_8te1_liu_llb(fe, mode); + sdla_8te1_liu_rlb(fe, mode); + break; + case WAN_TE1_FR_FLB_MODE: + sdla_8te1_fr_flb(fe, mode); + break; + case WAN_TE1_FR_PLB_MODE: + sdla_8te1_fr_plb(fe, mode); + break; + case WAN_TE1_FR_RLB_MODE: + break; + } + return 0; +} + +/* + ****************************************************************************** + * sdla_8te1_udp() + * + * Description: + * Arguments: + * Returns: + ****************************************************************************** + */ +static int sdla_8te1_udp(sdla_fe_t *fe, void* p_udp_cmd, unsigned char* data) +{ + wan_cmd_t *udp_cmd = (wan_cmd_t*)p_udp_cmd; + sdla_fe_debug_t *fe_debug; + int err = 0; + + switch(udp_cmd->wan_cmd_command){ + case WAN_GET_MEDIA_TYPE: + data[0] = (IS_T1_FEMEDIA(fe) ? WAN_MEDIA_T1 : + IS_E1_FEMEDIA(fe) ? WAN_MEDIA_E1 : + WAN_MEDIA_NONE); + udp_cmd->wan_cmd_return_code = WAN_CMD_OK; + udp_cmd->wan_cmd_data_len = sizeof(unsigned char); + break; + + case WAN_FE_SET_LB_MODE: + /* Activate/Deactivate Line Loopback modes */ + err = sdla_8te1_set_lbmode(fe, data[0], data[1]); + udp_cmd->wan_cmd_return_code = + (!err) ? WAN_CMD_OK : WAN_UDP_FAILED_CMD; + udp_cmd->wan_cmd_data_len = 0x00; + break; + + case WAN_FE_GET_STAT: + /* TE1 Update T1/E1 perfomance counters */ + memcpy(&data[0], &fe->fe_stats, sizeof(sdla_fe_stats_t)); + udp_cmd->wan_cmd_return_code = WAN_CMD_OK; + udp_cmd->wan_cmd_data_len = sizeof(sdla_fe_stats_t); + break; + + case WAN_FE_FLUSH_PMON: + /* TE1 Flush T1/E1 pmon counters */ + sdla_8te1_flush_pmon(fe); + udp_cmd->wan_cmd_return_code = WAN_CMD_OK; + break; + + case WAN_FE_GET_CFG: + /* Read T1/E1 configuration */ + memcpy(&data[0], + &fe->fe_cfg, + sizeof(sdla_fe_cfg_t)); + udp_cmd->wan_cmd_return_code = WAN_CMD_OK; + udp_cmd->wan_cmd_data_len = sizeof(sdla_fe_cfg_t); + break; + + case WAN_FE_SET_DEBUG_MODE: + fe_debug = (sdla_fe_debug_t*)&data[0]; + switch(fe_debug->type){ + case WAN_FE_DEBUG_RBS: + if (fe_debug->mode == WAN_FE_DEBUG_RBS_READ){ + DEBUG_EVENT("%s: Reading RBS status!\n", + fe->name); + sdla_8te1_enable_timer(fe, TE_RBS_READ, POLLING_TE1_TIMER); + udp_cmd->wan_cmd_return_code = WAN_CMD_OK; + }else if (fe_debug->mode == WAN_FE_DEBUG_RBS_PRINT){ + /* Enable extra debugging */ + sdla_8te1_rbs_print(fe, 1); + udp_cmd->wan_cmd_return_code = WAN_CMD_OK; + }else if (fe_debug->mode == WAN_FE_DEBUG_RBS_RX_ENABLE){ + /* Enable extra debugging */ + DEBUG_EVENT("%s: Enable RBS RX DEBUG mode!\n", + fe->name); + fe->fe_debug |= WAN_FE_DEBUG_RBS_RX_ENABLE; + sdla_8te1_rbs_print(fe, 1); + udp_cmd->wan_cmd_return_code = WAN_CMD_OK; + }else if (fe_debug->mode == WAN_FE_DEBUG_RBS_TX_ENABLE){ + /* Enable extra debugging */ + DEBUG_EVENT("%s: Enable RBS TX DEBUG mode!\n", + fe->name); + fe->fe_debug |= WAN_FE_DEBUG_RBS_TX_ENABLE; + sdla_8te1_rbs_print(fe, 1); + udp_cmd->wan_cmd_return_code = WAN_CMD_OK; + }else if (fe_debug->mode == WAN_FE_DEBUG_RBS_RX_DISABLE){ + /* Disable extra debugging */ + DEBUG_EVENT("%s: Disable RBS RX DEBUG mode!\n", + fe->name); + fe->fe_debug &= ~WAN_FE_DEBUG_RBS_RX_ENABLE; + sdla_8te1_rbs_print(fe, 1); + udp_cmd->wan_cmd_return_code = WAN_CMD_OK; + }else if (fe_debug->mode == WAN_FE_DEBUG_RBS_TX_DISABLE){ + /* Disable extra debugging */ + DEBUG_EVENT("%s: Disable RBS TX DEBUG mode!\n", + fe->name); + fe->fe_debug &= ~WAN_FE_DEBUG_RBS_TX_ENABLE; + sdla_8te1_rbs_print(fe, 1); + udp_cmd->wan_cmd_return_code = WAN_CMD_OK; + }else if (fe_debug->mode == WAN_FE_DEBUG_RBS_SET){ + + if (IS_T1_FEMEDIA(fe)){ + if (fe_debug->channel < 1 || fe_debug->channel > 24){ + DEBUG_EVENT("%s: Invalid channel number %d\n", + fe->name, + fe_debug->channel); + break; + } + }else{ + if (fe_debug->channel < 0 || fe_debug->channel > 31){ + DEBUG_EVENT("%s: Invalid channel number %d\n", + fe->name, + fe_debug->channel); + break; + } + } + + fe->te_param.timer_channel = fe_debug->channel; + fe->te_param.timer_abcd = fe_debug->abcd; + sdla_8te1_enable_timer(fe, TE_SET_RBS, POLLING_TE1_TIMER); + udp_cmd->wan_cmd_return_code = WAN_CMD_OK; + } + break; + case WAN_FE_DEBUG_ALARM: + default: + udp_cmd->wan_cmd_return_code = WAN_UDP_INVALID_CMD; + break; + } + udp_cmd->wan_cmd_data_len = 0; + break; + case WAN_FE_TX_MODE: + fe_debug = (sdla_fe_debug_t*)&data[0]; + switch(fe_debug->mode){ + case WAN_FE_TXMODE_ENABLE: + DEBUG_TEST("%s: Enable Transmitter!\n", + fe->name); + udp_cmd->wan_cmd_return_code = WAN_UDP_INVALID_CMD; + break; + case WAN_FE_TXMODE_DISABLE: + DEBUG_TEST("%s: Disable Transmitter (tx tri-state mode)!\n", + fe->name); + udp_cmd->wan_cmd_return_code = WAN_UDP_INVALID_CMD; + break; + default: + udp_cmd->wan_cmd_return_code = WAN_UDP_INVALID_CMD; + udp_cmd->wan_cmd_data_len = 0; + break; + } + break; + default: + udp_cmd->wan_cmd_return_code = WAN_UDP_INVALID_CMD; + udp_cmd->wan_cmd_data_len = 0; + break; + } + return 0; +} + +static int +sdla_8te1_update_alarm_info(sdla_fe_t* fe, struct seq_file* m, int* stop_cnt) +{ + +#if !defined(__WINDOWS__) + PROC_ADD_LINE(m, + "=============================== %s Alarms ===============================\n", + FE_MEDIA_DECODE(fe)); + PROC_ADD_LINE(m, + PROC_STATS_ALARM_FORMAT, + "ALOS", WAN_TE_ALOS_ALARM(fe->fe_alarm), + "LOS", WAN_TE_LOS_ALARM(fe->fe_alarm)); + PROC_ADD_LINE(m, + PROC_STATS_ALARM_FORMAT, + "RED", WAN_TE_RED_ALARM(fe->fe_alarm), + "AIS", WAN_TE_AIS_ALARM(fe->fe_alarm)); + if (IS_T1_FEMEDIA(fe)){ + PROC_ADD_LINE(m, + PROC_STATS_ALARM_FORMAT, + "YEL", WAN_TE_YEL_ALARM(fe->fe_alarm), + "OOF", WAN_TE_OOF_ALARM(fe->fe_alarm)); + }else{ + PROC_ADD_LINE(m, + PROC_STATS_ALARM_FORMAT, + "OOF", WAN_TE_OOF_ALARM(fe->fe_alarm), + "", ""); + } + return m->count; +#endif + return 0; +} + +static int +sdla_8te1_update_pmon_info(sdla_fe_t* fe, struct seq_file* m, int* stop_cnt) +{ + +#if !defined(__WINDOWS__) + PROC_ADD_LINE(m, + "=========================== %s PMON counters ============================\n", + FE_MEDIA_DECODE(fe)); + if (IS_T1_FEMEDIA(fe)){ + PROC_ADD_LINE(m, + PROC_STATS_PMON_FORMAT, + "Line Code Violation", fe->fe_stats.u.te_pmon.lcv_errors, + "Bit Errors", fe->fe_stats.u.te_pmon.bee_errors); + PROC_ADD_LINE(m, + PROC_STATS_PMON_FORMAT, + "Out of Frame Errors", fe->fe_stats.u.te_pmon.oof_errors, + "", (unsigned long)0); + }else{ + PROC_ADD_LINE(m, + PROC_STATS_PMON_FORMAT, + "Line Code Violation", fe->fe_stats.u.te_pmon.lcv_errors, + "CRC4 Errors", fe->fe_stats.u.te_pmon.crc4_errors); + PROC_ADD_LINE(m, + PROC_STATS_PMON_FORMAT, + "FAS Errors", fe->fe_stats.u.te_pmon.fas_errors, + "Far End Block Errors", fe->fe_stats.u.te_pmon.feb_errors); + } + return m->count; +#endif + return 0; +} + + diff -Nur linux.org/drivers/net/wan/sdla_adccp.c linux-2.6.17/drivers/net/wan/sdla_adccp.c --- linux.org/drivers/net/wan/sdla_adccp.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/drivers/net/wan/sdla_adccp.c 2006-08-30 10:07:16.000000000 +0000 @@ -0,0 +1,5793 @@ +/***************************************************************************** +* sdla_adccp.c WANPIPE(tm) Multiprotocol WAN Link Driver. X.25 module. +* +* Author: Nenad Corbic +* +* Copyright: (c) 1995-2003 Sangoma Technologies Inc. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version +* 2 of the License, or (at your option) any later version. +* ============================================================================ +* Apr 30, 2003 Nenad Corbic o Inital Version based on X25 +*****************************************************************************/ + +/*====================================================== + * Includes + *=====================================================*/ + + +#include +#include +#include /* WAN router definitions */ +#include /* WANPIPE common user API definitions */ +#include +#include +#include /* HDLC API definitions */ +#include +#include +#include + + + +/*====================================================== + * Defines & Macros + *=====================================================*/ + + +#define CMD_OK 0 /* normal firmware return code */ +#define CMD_TIMEOUT 0xFF /* firmware command timed out */ +#define MAX_CMD_RETRY 10 /* max number of firmware retries */ + +#define X25_CHAN_MTU 4096 /* unfragmented logical channel MTU */ +#define X25_HRDHDR_SZ 7 /* max encapsulation header size */ +#define X25_CONCT_TMOUT (90*HZ) /* link connection timeout */ +#define X25_RECON_TMOUT (10*HZ) /* link connection timeout */ +#define CONNECT_TIMEOUT (90*HZ) /* link connection timeout */ +#define HOLD_DOWN_TIME (30*HZ) /* link hold down time */ +#define MAX_BH_BUFF 10 + +#undef PRINT_DEBUG +#ifdef PRINT_DEBUG +#define DBG_PRINTK(format, a...) printk(format, ## a) +#else +#define DBG_PRINTK(format, a...) +#endif + +#define TMR_INT_ENABLED_POLL_ACTIVE 0x01 +#define TMR_INT_ENABLED_POLL_CONNECT_ON 0x02 +#define TMR_INT_ENABLED_POLL_CONNECT_OFF 0x04 +#define TMR_INT_ENABLED_POLL_DISCONNECT 0x08 +#define TMR_INT_ENABLED_CMD_EXEC 0x10 +#define TMR_INT_ENABLED_UPDATE 0x20 +#define TMR_INT_ENABLED_UDP_PKT 0x40 + +#define MAX_X25_ADDR_SIZE 16 +#define MAX_X25_DATA_SIZE 129 +#define MAX_X25_FACL_SIZE 110 + +#define TRY_CMD_AGAIN 2 +#define DELAY_RESULT 1 +#define RETURN_RESULT 0 + +#define DCD(x) (x & 0x03 ? "HIGH" : "LOW") +#define CTS(x) (x & 0x05 ? "HIGH" : "LOW") + +/* Private critical flags */ +enum { + POLL_CRIT = PRIV_CRIT +}; + +/* Driver will not write log messages about + * modem status if defined.*/ +#undef MODEM_NOT_LOG + +/*==================================================== + * For IPXWAN + *===================================================*/ + +#define CVHexToAscii(b) (((unsigned char)(b) > (unsigned char)9) ? ((unsigned char)'A' + ((unsigned char)(b) - (unsigned char)10)) : ((unsigned char)'0' + (unsigned char)(b))) + + +/*==================================================== + * MEMORY DEBUGGING FUNCTION + *==================================================== + +#define KMEM_SAFETYZONE 8 + +static void * dbg_kmalloc(unsigned int size, int prio, int line) { + int i = 0; + void * v = kmalloc(size+sizeof(unsigned int)+2*KMEM_SAFETYZONE*8,prio); + char * c1 = v; + c1 += sizeof(unsigned int); + *((unsigned int *)v) = size; + + for (i = 0; i < KMEM_SAFETYZONE; i++) { + c1[0] = 'D'; c1[1] = 'E'; c1[2] = 'A'; c1[3] = 'D'; + c1[4] = 'B'; c1[5] = 'E'; c1[6] = 'E'; c1[7] = 'F'; + c1 += 8; + } + c1 += size; + for (i = 0; i < KMEM_SAFETYZONE; i++) { + c1[0] = 'M'; c1[1] = 'U'; c1[2] = 'N'; c1[3] = 'G'; + c1[4] = 'W'; c1[5] = 'A'; c1[6] = 'L'; c1[7] = 'L'; + c1 += 8; + } + v = ((char *)v) + sizeof(unsigned int) + KMEM_SAFETYZONE*8; + printk(KERN_INFO "line %d kmalloc(%d,%d) = %p\n",line,size,prio,v); + return v; +} +static void dbg_kfree(void * v, int line) { + unsigned int * sp = (unsigned int *)(((char *)v) - (sizeof(unsigned int) + KMEM_SAFETYZONE*8)); + unsigned int size = *sp; + char * c1 = ((char *)v) - KMEM_SAFETYZONE*8; + int i = 0; + for (i = 0; i < KMEM_SAFETYZONE; i++) { + if ( c1[0] != 'D' || c1[1] != 'E' || c1[2] != 'A' || c1[3] != 'D' + || c1[4] != 'B' || c1[5] != 'E' || c1[6] != 'E' || c1[7] != 'F') { + printk(KERN_INFO "kmalloced block at %p has been corrupted (underrun)!\n",v); + printk(KERN_INFO " %4x: %2x %2x %2x %2x %2x %2x %2x %2x\n", i*8, + c1[0],c1[1],c1[2],c1[3],c1[4],c1[5],c1[6],c1[7] ); + } + c1 += 8; + } + c1 += size; + for (i = 0; i < KMEM_SAFETYZONE; i++) { + if ( c1[0] != 'M' || c1[1] != 'U' || c1[2] != 'N' || c1[3] != 'G' + || c1[4] != 'W' || c1[5] != 'A' || c1[6] != 'L' || c1[7] != 'L' + ) { + printk(KERN_INFO "kmalloced block at %p has been corrupted (overrun):\n",v); + printk(KERN_INFO " %4x: %2x %2x %2x %2x %2x %2x %2x %2x\n", i*8, + c1[0],c1[1],c1[2],c1[3],c1[4],c1[5],c1[6],c1[7] ); + } + c1 += 8; + } + printk(KERN_INFO "line %d kfree(%p)\n",line,v); + v = ((char *)v) - (sizeof(unsigned int) + KMEM_SAFETYZONE*8); + kfree(v); +} + +#define kmalloc(x,y) dbg_kmalloc(x,y,__LINE__) +#define kfree(x) dbg_kfree(x,__LINE__) + +==============================================================*/ + + + +/*=============================================== + * Data Structures + *===============================================*/ + + +/*======================================================== + * Name: x25_channel + * + * Purpose: To hold private informaton for each + * logical channel. + * + * Rationale: Per-channel debugging is possible if each + * channel has its own private area. + * + * Assumptions: + * + * Description: This is an extention of the 'netdevice_t' + * we create for each network interface to keep + * the rest of X.25 channel-specific data. + * + * Construct: Typedef + */ +typedef struct x25_channel +{ + wanpipe_common_t common; /* common area for x25api and socket */ + char name[WAN_IFNAME_SZ+1]; /* interface name, ASCIIZ */ + char addr[WAN_ADDRESS_SZ+1]; /* media address, ASCIIZ */ + unsigned tx_pkt_size; + unsigned short protocol; /* ethertype, 0 - multiplexed */ + char drop_sequence; /* mark sequence for dropping */ + unsigned long state_tick; /* time of the last state change */ + unsigned idle_timeout; /* sec, before disconnecting */ + unsigned long i_timeout_sofar; /* # of sec's we've been idle */ + unsigned hold_timeout; /* sec, before re-connecting */ + unsigned long tick_counter; /* counter for transmit time out */ + char devtint; /* Weather we should dev_tint() */ + struct sk_buff* rx_skb; /* receive socket buffer */ + struct sk_buff* tx_skb; /* transmit socket buffer */ + + unsigned long tq_working; + + sdla_t* card; /* -> owner */ + netdevice_t *dev; /* -> bound devce */ + + int ch_idx; + unsigned char enable_IPX; + unsigned long network_number; + struct net_device_stats ifstats; /* interface statistics */ + if_send_stat_t if_send_stat; + rx_intr_stat_t rx_intr_stat; + pipe_mgmt_stat_t pipe_mgmt_stat; + + unsigned long router_start_time; /* Router start time in seconds */ + unsigned long router_up_time; + + char x25_src_addr[WAN_ADDRESS_SZ+1]; /* x25 media source address, + ASCIIZ */ + char accept_dest_addr[WAN_ADDRESS_SZ+1]; /* pattern match string in -d + for accepting calls, ASCIIZ */ + char accept_src_addr[WAN_ADDRESS_SZ+1]; /* pattern match string in -s + for accepting calls, ASCIIZ */ + char accept_usr_data[WAN_ADDRESS_SZ+1];/* pattern match string in -u + for accepting calls, ASCIIZ */ + + /* Entry in proc fs per each interface */ + struct proc_dir_entry* dent; + int chan_direct; + unsigned long chan_establ_time; + unsigned long chan_clear_time; + unsigned char chan_clear_cause; + unsigned char chan_clear_diagn; + char cleared_called_addr[MAX_X25_ADDR_SIZE]; + char cleared_calling_addr[MAX_X25_ADDR_SIZE]; + char cleared_facil[MAX_X25_ADDR_SIZE]; + + unsigned long disc_delay; + x25api_t x25_api_event; + atomic_t cmd_rc; + unsigned long cmd_timeout; + +} x25_channel_t; + +/* FIXME Take this out */ + +#ifdef NEX_OLD_CALL_INFO +typedef struct x25_call_info +{ + char dest[17]; PACKED;/* ASCIIZ destination address */ + char src[17]; PACKED;/* ASCIIZ source address */ + char nuser; PACKED;/* number of user data bytes */ + unsigned char user[127]; PACKED;/* user data */ + char nfacil; PACKED;/* number of facilities */ + struct + { + unsigned char code; PACKED; + unsigned char parm; PACKED; + } facil[64]; /* facilities */ +} x25_call_info_t; +#else +typedef struct x25_call_info +{ + char dest[MAX_X25_ADDR_SIZE] PACKED;/* ASCIIZ destination address */ + char src[MAX_X25_ADDR_SIZE] PACKED;/* ASCIIZ source address */ + unsigned char nuser PACKED; + unsigned char user[MAX_X25_DATA_SIZE] PACKED;/* user data */ + unsigned char nfacil PACKED; + unsigned char facil[MAX_X25_FACL_SIZE] PACKED; + unsigned short lcn PACKED; +} x25_call_info_t; +#endif + + + +/*=============================================== + * Private Function Prototypes + *==============================================*/ + + +/*================================================= + * WAN link driver entry points. These are + * called by the WAN router module. + */ +static int update (wan_device_t* wandev); +static int new_if (wan_device_t* wandev, netdevice_t* dev, + wanif_conf_t* conf); +static int del_if (wan_device_t* wandev, netdevice_t* dev); +static void disable_comm (sdla_t* card); +static void disable_comm_shutdown(sdla_t *card); + + + +/*================================================= + * WANPIPE-specific entry points + */ +static void x25api_bh (unsigned long data); + + +/*================================================= + * Network device interface + */ +static int if_init (netdevice_t* dev); +static int if_open (netdevice_t* dev); +static int if_close (netdevice_t* dev); +static int if_send (struct sk_buff* skb, netdevice_t* dev); +static struct net_device_stats *if_stats (netdevice_t* dev); +static int if_ioctl (netdevice_t *dev, struct ifreq *ifr, int cmd); + +static void if_tx_timeout (netdevice_t *dev); + +/*================================================= + * Interrupt handlers + */ +static void wpx_isr (sdla_t *); +static void rx_intr (sdla_t *); +static void tx_intr (sdla_t *); +static void status_intr (sdla_t *); +static void event_intr (sdla_t *); +static void spur_intr (sdla_t *); +static void timer_intr (sdla_t *); + + +/*================================================= + * Background polling routines + */ +static void wpx_poll (void*); +#if 0 +static void poll_disconnected (sdla_t* card); +#endif +static void poll_connecting (sdla_t* card); +static void poll_active (sdla_t* card); +static void trigger_x25_poll(sdla_t *card); +static void x25_timer_routine(unsigned long data); + + + +/*================================================= + * X.25 firmware interface functions + */ +static int x25_get_version (sdla_t* card, char* str); +static int hdlc_configure (sdla_t* card, TX25Config* conf); +static int x25_get_err_stats (sdla_t* card); +static int x25_get_stats (sdla_t* card); +static int x25_set_intr_mode (sdla_t* card, int mode); +static int x25_close_hdlc (sdla_t* card); +static int x25_open_hdlc (sdla_t* card); +static int x25_setup_hdlc (sdla_t* card); +static int x25_clear_call (sdla_t* card, int lcn, int cause, int diagn); +static int x25_send (sdla_t* card, int lcn, int qdm, int len, void* buf); +static int x25_fetch_events (sdla_t* card); +static int x25_error (sdla_t* card, int err, int cmd, int lcn); + +/*================================================= + * X.25 asynchronous event handlers + */ +static int incoming_call (sdla_t* card, int cmd, int lcn, wan_mbox_t* mb); +static int call_accepted (sdla_t* card, int cmd, int lcn, wan_mbox_t* mb); +static int call_cleared (sdla_t* card, int cmd, int lcn, wan_mbox_t* mb); +static int timeout_event (sdla_t* card, int cmd, int lcn, wan_mbox_t* mb); +static int restart_event (sdla_t* card, int cmd, int lcn, wan_mbox_t* mb); + + +/*================================================= + * Miscellaneous functions + */ +static int connect (sdla_t* card); +static int disconnect (sdla_t* card); +static int chan_disc (netdevice_t* dev); +static void set_chan_state (netdevice_t* dev, int state); +static int chan_send (netdevice_t* , void* , unsigned, unsigned char); +static unsigned char bps_to_speed_code (unsigned long bps); +static void parse_call_info (unsigned char*, x25_call_info_t*); +static netdevice_t * find_channel(sdla_t *, unsigned); +static int wait_for_cmd_rc(sdla_t *card, x25_channel_t* chan); +static int test_chan_command_busy(sdla_t *card,x25_channel_t *chan); +static int delay_cmd(sdla_t *card, x25_channel_t *chan, int delay); + + +/*================================================= + * X25 API Functions + */ +static int wanpipe_pull_data_in_skb (sdla_t *, netdevice_t *, struct sk_buff **); +static void trigger_intr_exec(sdla_t *, unsigned char); +static int execute_delayed_cmd (sdla_t*, netdevice_t *, char); +static int alloc_and_init_skb_buf (sdla_t *,struct sk_buff **, int); +static int send_oob_msg (sdla_t *, netdevice_t *, wan_mbox_t *); +static int tx_intr_cmd_exec(sdla_t *card); +static void api_oob_event (sdla_t *card,wan_mbox_t *mbox); +static int hdlc_link_down (sdla_t*); + +/*================================================= + * XPIPEMON Functions + */ +static int process_udp_mgmt_pkt(sdla_t *,netdevice_t*); +static int reply_udp( unsigned char *, unsigned int); +static void init_x25_channel_struct( x25_channel_t *); +static void init_global_statistics( sdla_t *); +static unsigned short calc_checksum (char *, int); + + + +/*================================================= + * IPX functions + */ +static void switch_net_numbers(unsigned char *, unsigned long, unsigned char); +static int handle_IPXWAN(unsigned char *, char *, unsigned char , + unsigned long , unsigned short ); + +extern void disable_irq(unsigned int); +extern void enable_irq(unsigned int); + +static void S508_S514_lock(sdla_t *, unsigned long *); +static void S508_S514_unlock(sdla_t *, unsigned long *); + +/*================================================= + * PROC fs functions + */ +static void x25_clear_cmd_update(sdla_t* card, unsigned lcn, wan_mbox_t* mb); + +/*================================================= + * Global Variables + *=================================================*/ +static TX25Stats X25Stats; + + + +/*================================================= + * Public Functions + *=================================================*/ + + + + +/*=================================================================== + * wpx_init: X.25 Protocol Initialization routine. + * + * Purpose: To initialize the protocol/firmware. + * + * Rationale: This function is called by setup() function, in + * sdlamain.c, to dynamically setup the x25 protocol. + * This is the first protocol specific function, which + * executes once on startup. + * + * Description: This procedure initializes the x25 firmware and + * sets up the mailbox, transmit and receive buffer + * pointers. It also initializes all debugging structures + * and sets up the X25 environment. + * + * Sets up hardware options defined by user in [wanpipe#] + * section of wanpipe#.conf configuration file. + * + * At this point adapter is completely initialized + * and X.25 firmware is running. + * o read firmware version (to make sure it's alive) + * o configure adapter + * o initialize protocol-specific fields of the + * adapter data space. + * + * Called by: setup() function in sdlamain.c + * + * Assumptions: None + * + * Warnings: None + * + * Return: 0 o.k. + * < 0 failure. + */ + +int wp_adccp_init (sdla_t* card, wandev_conf_t* conf) +{ + union{ + char str[80]; + TX25Config cfg; + } u; + wan_x25_conf_t* x25_adm_conf = &card->u.x.x25_adm_conf; + wan_x25_conf_t* x25_conf = &card->u.x.x25_conf; + + /* Verify configuration ID */ + if (conf->config_id != WANCONFIG_ADCCP){ + printk(KERN_INFO "%s: invalid configuration ID %u!\n", + card->devname, conf->config_id) + ; + return -EINVAL; + } + + /* Initialize protocol-specific fields */ + /* ALEX Apr 8 2004 Sangoma ISA card */ + card->mbox_off = X25_MB_VECTOR + X25_MBOX_OFFS; + card->flags_off = X25_MB_VECTOR + X25_STATUS_OFFS; + card->rxmb_off = X25_MB_VECTOR + X25_RXMBOX_OFFS; + + /* Read firmware version. Note that when adapter initializes, it + * clears the mailbox, so it may appear that the first command was + * executed successfully when in fact it was merely erased. To work + * around this, we execute the first command twice. + */ + if (x25_get_version(card, NULL) || x25_get_version(card, u.str)) + return -EIO; + + + /* Run only in LAPB HDLC mode. + * Check the user defined option and configure accordingly */ + printk(KERN_INFO "%s: running LAP_B HDLC firmware v%s\n", + card->devname, u.str); + card->u.x.LAPB_hdlc = 1; + + /* Copy Admin configuration to sdla_t structure */ + memcpy(x25_adm_conf, &conf->u.x25, sizeof(wan_x25_conf_t)); + + /* Configure adapter. Here we set resonable defaults, then parse + * device configuration structure and set configuration options. + * Most configuration options are verified and corrected (if + * necessary) since we can't rely on the adapter to do so. + */ + memset(&u.cfg, 0, sizeof(u.cfg)); + u.cfg.t1 = conf->u.x25.t1; + u.cfg.t2 = conf->u.x25.t2; + u.cfg.t4 = conf->u.x25.t4; + u.cfg.n2 = 10; + u.cfg.autoHdlc = 1; /* automatic HDLC connection */ + u.cfg.hdlcWindow = conf->u.x25.hdlc_window; + u.cfg.station = X25_STATION_DTE; /* DTE */ + u.cfg.local_station_address = conf->u.x25.local_station_address; + + if (conf->clocking != WANOPT_EXTERNAL) + u.cfg.baudRate = bps_to_speed_code(conf->bps); + + if (conf->u.x25.station != WANOPT_DTE){ + u.cfg.station = 0; /* DCE mode */ + } + + if (conf->interface != WANOPT_RS232 ){ + u.cfg.hdlcOptions |= 0x80; /* V35 mode */ + } + + DEBUG_EVENT("%s: Lapb Configuration: \n", + card->devname); + DEBUG_EVENT("%s: T1 = %d\n", + card->devname, + u.cfg.t1); + DEBUG_EVENT("%s: T2 = %d\n", + card->devname, + u.cfg.t2); + DEBUG_EVENT("%s: T4 = %d\n", + card->devname, + u.cfg.t4); + DEBUG_EVENT("%s: N2 = %d\n", + card->devname, + u.cfg.n2); + + DEBUG_EVENT("%s: Baud Rate = %d\n", + card->devname, + u.cfg.baudRate); + + DEBUG_EVENT("%s: Hdlc Window = %d\n", + card->devname, + u.cfg.hdlcWindow); + DEBUG_EVENT("%s: Station = %s\n", + card->devname, + u.cfg.station==X25_STATION_DTE?"DTE":"DCE"); + DEBUG_EVENT("%s: Local State Addr = %i\n", + card->devname, + conf->u.x25.local_station_address); + + u.cfg.hdlcMTU = 1027; + + + /* adjust MTU */ + if (!conf->mtu || (conf->mtu >= 1024)) + card->wandev.mtu = 1024; + else if (conf->mtu >= 512) + card->wandev.mtu = 512; + else if (conf->mtu >= 256) + card->wandev.mtu = 256; + else if (conf->mtu >= 128) + card->wandev.mtu = 128; + else + card->wandev.mtu = 64; + + /* Copy the real configuration to card structure */ + x25_conf->hdlc_window = u.cfg.hdlcWindow; + x25_conf->t1 = u.cfg.t1; + x25_conf->t2 = u.cfg.t2; + x25_conf->t4 = u.cfg.t4; + x25_conf->n2 = u.cfg.n2; + x25_conf->oob_on_modem = conf->u.x25.oob_on_modem; + + /* initialize adapter */ + if (hdlc_configure(card, &u.cfg) != CMD_OK) + return -EIO; + + if ((x25_close_hdlc(card) != CMD_OK)){ + return -EIO; + } + + /* Initialize protocol-specific fields of adapter data space */ + card->wandev.bps = conf->bps; + card->wandev.interface = conf->interface; + card->wandev.clocking = conf->clocking; + card->wandev.station = conf->u.x25.station; + card->isr = &wpx_isr; + card->poll = NULL; + card->disable_comm = &disable_comm; + card->exec = NULL; + card->wandev.update = &update; + card->wandev.new_if = &new_if; + card->wandev.del_if = &del_if; + +#if 0 + // Proc fs functions + card->wandev.get_config_info = &x25_get_config_info; + card->wandev.get_status_info = &x25_get_status_info; + card->wandev.get_dev_config_info= &x25_get_dev_config_info; + card->wandev.get_if_info = &x25_get_if_info; + card->wandev.set_dev_config = &x25_set_dev_config; + card->wandev.set_if_info = &x25_set_if_info; + + /* SNMP data */ + card->get_snmp_data = &x25_snmp_data; +#endif + + /* WARNING: This function cannot exit with an error + * after the change of state */ + card->wandev.state = WAN_DISCONNECTED; + + card->wandev.enable_tx_int = 0; + card->irq_dis_if_send_count = 0; + card->irq_dis_poll_count = 0; + card->u.x.tx_dev = NULL; + card->u.x.no_dev = 0; + + + /* Configure for S514 PCI Card */ + /* ALEX Apr 8 2004 Sangoma ISA card */ + card->u.x.hdlc_buf_status_off = + X25_MB_VECTOR + X25_MISC_HDLC_BITS; + + card->u.x.poll_device=NULL; + card->wandev.udp_port = conf->udp_port; + + /* Enable or disable call setup logging */ + if (conf->u.x25.logging == WANOPT_YES){ + printk(KERN_INFO "%s: Enabling Call Logging.\n", + card->devname); + card->u.x.logging = 1; + }else{ + card->u.x.logging = 0; + } + + /* Enable or disable modem status reporting */ + if (conf->u.x25.oob_on_modem == WANOPT_YES){ + printk(KERN_INFO "%s: Enabling OOB on Modem change.\n", + card->devname); + card->u.x.oob_on_modem = 1; + }else{ + card->u.x.oob_on_modem = 0; + } + + init_global_statistics(card); + + INIT_WORK((&card->u.x.x25_poll_task),wpx_poll,card); + + init_timer(&card->u.x.x25_timer); + card->u.x.x25_timer.data = (unsigned long)card; + card->u.x.x25_timer.function = x25_timer_routine; + + return 0; +} + +/*========================================================= + * WAN Device Driver Entry Points + *========================================================*/ + +/*============================================================ + * Name: update(), Update device status & statistics. + * + * Purpose: To provide debugging and statitical + * information to the /proc file system. + * /proc/net/wanrouter/wanpipe# + * + * Rationale: The /proc file system is used to collect + * information about the kernel and drivers. + * Using the /proc file system the user + * can see exactly what the sangoma drivers are + * doing. And in what state they are in. + * + * Description: Collect all driver statistical information + * and pass it to the top laywer. + * + * Since we have to execute a debugging command, + * to obtain firmware statitics, we trigger a + * UPDATE function within the timer interrtup. + * We wait until the timer update is complete. + * Once complete return the appropriate return + * code to indicate that the update was successful. + * + * Called by: device_stat() in wanmain.c + * + * Assumptions: + * + * Warnings: This function will degrade the performance + * of the router, since it uses the mailbox. + * + * Return: 0 OK + * <0 Failed (or busy). + */ + +static int update (wan_device_t* wandev) +{ + sdla_t* card; + netdevice_t *dev; + unsigned long smp_flags; + + /* sanity checks */ + if ((wandev == NULL) || (wandev->private == NULL)) + return -EFAULT; + + if (wandev->state == WAN_UNCONFIGURED) + return -ENODEV; + + if (test_bit(SEND_CRIT, (void*)&wandev->critical)) + return -EAGAIN; + + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&wandev->dev_head)); + if (!dev) + return -ENODEV; + + card = wandev->private; + + DEBUG_EVENT("%s: UPDATE\n",card->devname); + + spin_lock_irqsave(&card->wandev.lock, smp_flags); + +#if 0 + if (*card->u.x.hdlc_buf_status & 0x40){ + x25_get_err_stats(card); + x25_get_stats(card); + } +#else + x25_get_err_stats(card); + x25_get_stats(card); +#endif + spin_unlock_irqrestore(&card->wandev.lock, smp_flags); + + return 0; +} + + +/*=================================================================== + * Name: new_if + * + * Purpose: To allocate and initialize resources for a + * new logical channel. + * + * Rationale: A new channel can be added dynamically via + * ioctl call. + * + * Description: Allocate a private channel structure, x25_channel_t. + * Parse the user interface options from wanpipe#.conf + * configuration file. + * Bind the private are into the network device private + * area pointer (dev->priv). + * Prepare the network device structure for registration. + * + * Called by: ROUTER_IFNEW Ioctl call, from wanrouter_ioctl() + * (wanmain.c) + * + * Assumptions: None + * + * Warnings: None + * + * Return: 0 Ok + * <0 Failed (channel will not be created) + */ +static int new_if (wan_device_t* wandev, netdevice_t* dev, wanif_conf_t* conf) +{ + sdla_t* card = wandev->private; + x25_channel_t* chan; + int err = 0; + + if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)){ + printk(KERN_INFO "%s: invalid interface name!\n", + card->devname); + return -EINVAL; + } + + if(card->wandev.new_if_cnt++ > 0) { + printk(KERN_INFO "%s: Error: Running LAPB HDLC Mode !\n", + card->devname); + printk(KERN_INFO + "%s: Maximum number of network interfaces must be one !\n", + card->devname); + return -EEXIST; + } + + /* allocate and initialize private data */ + chan = kmalloc(sizeof(x25_channel_t), GFP_ATOMIC); + if (chan == NULL){ + printk(KERN_INFO "%s: Error: No memory !\n", + card->devname); + return -ENOMEM; + } + + memset(chan, 0, sizeof(x25_channel_t)); + + WAN_TASKLET_INIT((&chan->common.bh_task),0,x25api_bh,(unsigned long)chan); + + /* Bug Fix: Seg Err on PVC startup + * It must be here since bind_lcn_to_dev expects + * it bellow */ + dev->priv = chan; + + strcpy(chan->name, conf->name); + chan->card = card; + chan->dev = dev; + chan->tx_skb = chan->rx_skb = NULL; + + if(strcmp(conf->usedby, "WANPIPE") == 0){ + printk(KERN_INFO "%s: Running in WANPIPE mode %s\n", + wandev->name, chan->name); + chan->common.usedby = WANPIPE; + chan->protocol = htons(ETH_P_IP); + + }else if(strcmp(conf->usedby, "API") == 0){ + chan->common.usedby = API; + printk(KERN_INFO "%s: Running in API mode %s\n", + wandev->name, chan->name); + wan_reg_api(chan, dev, card->devname); + chan->protocol = htons(WP_LAPB_PROT); + } + + + if (err){ + kfree(chan); + dev->priv = NULL; + return err; + } + + chan->enable_IPX = conf->enable_IPX; + + if (chan->enable_IPX) + chan->protocol = htons(ETH_P_IPX); + + if (conf->network_number) + chan->network_number = conf->network_number; + else + chan->network_number = 0xDEADBEEF; + + /* prepare network device data space for registration */ + dev->init = &if_init; + + init_x25_channel_struct(chan); + + chan->common.state = WAN_DISCONNECTED; + set_chan_state(dev, WAN_DISCONNECTED); + + return 0; +} + +/*=================================================================== + * Name: del_if(), Remove a logical channel. + * + * Purpose: To dynamically remove a logical channel. + * + * Rationale: Each logical channel should be dynamically + * removable. This functin is called by an + * IOCTL_IFDEL ioctl call or shutdown(). + * + * Description: Do nothing. + * + * Called by: IOCTL_IFDEL : wanrouter_ioctl() from wanmain.c + * shutdown() from sdlamain.c + * + * Assumptions: + * + * Warnings: + * + * Return: 0 Ok. Void function. + */ + + +static int del_if (wan_device_t* wandev, netdevice_t* dev) +{ + sdla_t *card=wandev->private; + x25_channel_t* chan = dev->priv; + + set_chan_state(dev, WAN_DISCONNECTED); + WAN_TASKLET_KILL(&chan->common.bh_task); + wan_unreg_api(dev->priv, card->devname); + return 0; +} + + +/*============================================================ + * Name: disable_comm + * + * Description: Disable communications during shutdown. + * Dont check return code because there is + * nothing we can do about it. + * + * Warning: Dev and private areas are gone at this point. + *===========================================================*/ + +static void disable_comm(sdla_t* card) +{ + disable_comm_shutdown(card); + del_timer(&card->u.x.x25_timer); + return; +} + + +/*============================================================ + * Network Device Interface + *===========================================================*/ + +/*=================================================================== + * Name: if_init(), Netowrk Interface Initialization + * + * Purpose: To initialize a network interface device structure. + * + * Rationale: During network interface startup, the if_init + * is called by the kernel to initialize the + * netowrk device structure. Thus a driver + * can customze a network device. + * + * Description: Initialize the netowrk device call back + * routines. This is where we tell the kernel + * which function to use when it wants to send + * via our interface. + * Furthermore, we initialize the device flags, + * MTU and physical address of the board. + * + * Called by: Kernel (/usr/src/linux/net/core/dev.c) + * (dev->init()) + * + * Assumptions: None + * + * Warnings: None + * + * Return: 0 Ok : Void function. + */ +static int if_init (netdevice_t* dev) +{ + x25_channel_t* chan = dev->priv; + sdla_t* card = chan->card; + wan_device_t* wandev = &card->wandev; + + /* Initialize device driver entry points */ + dev->open = &if_open; + dev->stop = &if_close; + dev->hard_header = NULL; + dev->rebuild_header = NULL; + dev->hard_start_xmit = &if_send; + dev->get_stats = &if_stats; + dev->do_ioctl = &if_ioctl; + +#if defined(LINUX_2_4)||defined(LINUX_2_6) + if (chan->common.usedby != API){ + dev->tx_timeout = &if_tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; + } +#endif + + /* Initialize media-specific parameters */ + dev->type = ARPHRD_PPP; /* ARP h/w type */ + dev->flags |= IFF_POINTOPOINT; + dev->flags |= IFF_NOARP; + + if (chan->common.usedby == API){ + dev->mtu = X25_CHAN_MTU+sizeof(x25api_hdr_t); + }else{ + dev->mtu = card->wandev.mtu; + } + + dev->hard_header_len = 0; /* media header length */ + dev->addr_len = 2; /* hardware address length */ + + if (!chan->common.svc){ + *(unsigned short*)dev->dev_addr = htons(chan->common.lcn); + } + + /* Initialize hardware parameters (just for reference) */ + dev->irq = wandev->irq; + dev->dma = wandev->dma; + dev->base_addr = wandev->ioport; + card->hw_iface.getcfg(card->hw, SDLA_MEMBASE, &dev->mem_start); + card->hw_iface.getcfg(card->hw, SDLA_MEMEND, &dev->mem_end); + + /* Set transmit buffer queue length */ + dev->tx_queue_len = 100; + + /* FIXME Why are we doing this */ + set_chan_state(dev, WAN_DISCONNECTED); + return 0; +} + + +/*=================================================================== + * Name: if_open(), Open/Bring up the Netowrk Interface + * + * Purpose: To bring up a network interface. + * + * Rationale: + * + * Description: Open network interface. + * o prevent module from unloading by incrementing use count + * o if link is disconnected then initiate connection + * + * Called by: Kernel (/usr/src/linux/net/core/dev.c) + * (dev->open()) + * + * Assumptions: None + * + * Warnings: None + * + * Return: 0 Ok + * <0 Failur: Interface will not come up. + */ + +static int if_open (netdevice_t* dev) +{ + x25_channel_t* chan = dev->priv; + sdla_t* card = chan->card; + struct timeval tv; + unsigned long smp_flags; + + if (open_dev_check(dev)) + return -EBUSY; + + /* Increment the number of interfaces */ + ++card->u.x.no_dev; + + wanpipe_open(card); + + /* LAPB protocol only uses one interface, thus + * start the protocol after it comes up. */ + if (card->open_cnt == 1){ + TX25Status status; + card->hw_iface.peek(card->hw, card->flags_off, &status, sizeof(status)); + S508_S514_lock(card, &smp_flags); + x25_set_intr_mode(card, INTR_ON_TIMER); + status.imask &= ~INTR_ON_TIMER; + card->hw_iface.poke(card->hw, card->flags_off, &status, sizeof(status)); + S508_S514_unlock(card, &smp_flags); + } + /* Device is not up untill the we are in connected state */ + do_gettimeofday( &tv ); + chan->router_start_time = tv.tv_sec; + + netif_start_queue(dev); + + return 0; +} + +/*=================================================================== + * Name: if_close(), Close/Bring down the Netowrk Interface + * + * Purpose: To bring down a network interface. + * + * Rationale: + * + * Description: Close network interface. + * o decrement use module use count + * + * Called by: Kernel (/usr/src/linux/net/core/dev.c) + * (dev->close()) + * ifconfig down: will trigger the kernel + * which will call this function. + * + * Assumptions: None + * + * Warnings: None + * + * Return: 0 Ok + * <0 Failure: Interface will not exit properly. + */ +static int if_close (netdevice_t* dev) +{ + x25_channel_t* chan = dev->priv; + sdla_t* card = chan->card; + unsigned long smp_flags; + + stop_net_queue(dev); + +#if defined(LINUX_2_1) + dev->start=0; +#endif + + if ((chan->common.state == WAN_CONNECTED) || + (chan->common.state == WAN_CONNECTING)){ + S508_S514_lock(card, &smp_flags); + chan_disc(dev); + S508_S514_unlock(card, &smp_flags); + } + + wanpipe_close(card); + + /* If this is the last close, disconnect physical link */ + if (!card->open_cnt){ + S508_S514_lock(card, &smp_flags); + disconnect(card); + x25_set_intr_mode(card, 0); + S508_S514_unlock(card, &smp_flags); + } + + /* Decrement the number of interfaces */ + --card->u.x.no_dev; + return 0; +} + + +/*============================================================================ + * Handle transmit timeout event from netif watchdog + */ +static void if_tx_timeout (netdevice_t *dev) +{ + x25_channel_t* chan = dev->priv; + sdla_t *card = chan->card; + + /* If our device stays busy for at least 5 seconds then we will + * kick start the device by making dev->tbusy = 0. We expect + * that our device never stays busy more than 5 seconds. So this + * is only used as a last resort. + */ + + ++chan->if_send_stat.if_send_tbusy_timeout; + printk (KERN_INFO "%s: Transmit timed out on %s\n", + card->devname, dev->name); + netif_wake_queue (dev); +} + + +/*========================================================================= + * Send a packet on a network interface. + * o set tbusy flag (marks start of the transmission). + * o check link state. If link is not up, then drop the packet. + * o check channel status. If it's down then initiate a call. + * o pass a packet to corresponding WAN device. + * o free socket buffer + * + * Return: 0 complete (socket buffer must be freed) + * non-0 packet may be re-transmitted (tbusy must be set) + * + * Notes: + * 1. This routine is called either by the protocol stack or by the "net + * bottom half" (with interrupts enabled). + * 2. Setting tbusy flag will inhibit further transmit requests from the + * protocol stack and can be used for flow control with protocol layer. + * + *========================================================================*/ + +static int if_send (struct sk_buff* skb, netdevice_t* dev) +{ + x25_channel_t* chan = dev->priv; + sdla_t* card = chan->card; + TX25Status status; + unsigned long smp_flags=0; + int err=0; + + ++chan->if_send_stat.if_send_entry; + card->hw_iface.peek(card->hw, card->flags_off, &status, sizeof(status)); + +#if defined(LINUX_2_4)||defined(LINUX_2_6) + netif_stop_queue(dev); +#endif + + /* No need to check frame length, since socket code + * will perform the check for us */ + + +#if defined(LINUX_2_1) + if (dev->tbusy){ + if ((jiffies - chan->tick_counter) < (5*HZ)){ + return 1; + } + + if_tx_timeout(dev); + } +#endif + + chan->tick_counter = jiffies; + + /* Critical region starts here */ + S508_S514_lock(card, &smp_flags); + + if (test_and_set_bit(SEND_CRIT, (void*)&card->wandev.critical)){ + printk(KERN_INFO "Hit critical in if_send()! %lx\n",card->wandev.critical); + start_net_queue(dev); + ++chan->if_send_stat.if_send_critical_ISR; + goto if_send_crit_exit; + } + + if (card->wandev.state != WAN_CONNECTED){ + + ++chan->ifstats.tx_dropped; + ++card->wandev.stats.tx_dropped; + ++chan->if_send_stat.if_send_wan_disconnected; + start_net_queue(dev); + + }else if (chan->protocol && (chan->protocol != skb->protocol)){ + + printk(KERN_INFO + "%s: unsupported Ethertype 0x%04X on interface %s!\n", + chan->name, htons(skb->protocol), dev->name); + + printk(KERN_INFO "PROTO %Xn", htons(chan->protocol)); + ++chan->ifstats.tx_errors; + ++chan->ifstats.tx_dropped; + ++card->wandev.stats.tx_dropped; + ++chan->if_send_stat.if_send_protocol_error; + start_net_queue(dev); + + }else switch (chan->common.state){ + + case WAN_DISCONNECTED: + + /* Try to establish connection. If succeded, then start + * transmission, else drop a packet. + */ + ++chan->ifstats.tx_dropped; + ++card->wandev.stats.tx_dropped; + ++chan->if_send_stat.if_send_wan_disconnected; + start_net_queue(dev); + break; + + case WAN_CONNECTED: + + /* We never drop here, if cannot send than, copy + * a packet into a transmit buffer + */ + err=chan_send(dev, skb->data, skb->len, 0); + if (err){ + err=-1; + ++chan->if_send_stat.if_send_bfr_not_passed_to_adptr; + stop_net_queue(dev); + }else{ + ++chan->if_send_stat.if_send_bfr_passed_to_adptr; + start_net_queue(dev); + } + break; + + default: + ++chan->ifstats.tx_dropped; + ++card->wandev.stats.tx_dropped; + ++chan->if_send_stat.if_send_wan_disconnected; + start_net_queue(dev); + break; + } + +if_send_crit_exit: + + if (err==0){ + wan_dev_kfree_skb(skb, FREE_WRITE); + }else{ + if (chan->common.state == WAN_CONNECTED){ + status.imask |= INTR_ON_TX_FRAME; + card->hw_iface.peek(card->hw, card->flags_off, &status, sizeof(status)); + ++chan->if_send_stat.if_send_tx_int_enabled; + } + } + + clear_bit(SEND_CRIT,(void*)&card->wandev.critical); + S508_S514_unlock(card, &smp_flags); + return err; +} + +/*=============================================================== + * net_device_stats + * + * Get ethernet-style interface statistics. + * Return a pointer to struct enet_statistics. + * + *==============================================================*/ +static struct net_device_stats *if_stats (netdevice_t* dev) +{ + x25_channel_t *chan = dev->priv; + + if(chan == NULL) + return NULL; + + return &chan->ifstats; +} + + +static int if_ioctl (netdevice_t *dev, struct ifreq *ifr, int cmd) +{ + x25_channel_t *chan; + sdla_t *card; + unsigned long smp_flags; + wan_udp_pkt_t *wan_udp_pkt; + int err=0; + + if (!dev || !(dev->flags & IFF_UP)){ + return -ENODEV; + } + + if (!(chan = dev->priv)){ + return -ENODEV; + } + + if (!(card = chan->card)){ + return -ENODEV; + } + + switch(cmd) + { + + case SIOC_WANPIPE_BIND_SK: + + if (!ifr){ + DEBUG_EVENT("%s: BIND SK Invalid no dev \n",__FUNCTION__); + return EINVAL; + } + + DEBUG_TEST("%s: SIOC_WANPIPE_BIND_SK \n",__FUNCTION__); + + spin_lock_irqsave(&card->wandev.lock,smp_flags); + err=wan_bind_api_to_svc(chan,ifr->ifr_data); + spin_unlock_irqrestore(&card->wandev.lock,smp_flags); + + return err; + + case SIOC_WANPIPE_UNBIND_SK: + + if (!ifr){ + DEBUG_EVENT("%s: UN BIND SK Invalid no dev \n",__FUNCTION__); + err= -EINVAL; + break; + } + + DEBUG_TEST("%s: SIOC_WANPIPE_UNBIND_SK \n",__FUNCTION__); + + spin_lock_irqsave(&card->wandev.lock,smp_flags); + err=wan_unbind_api_from_svc(chan,ifr->ifr_data); + spin_unlock_irqrestore(&card->wandev.lock,smp_flags); + + + if (chan->common.state != WAN_DISCONNECTED){ + S508_S514_lock(card, &smp_flags); + err=hdlc_link_down(card); + S508_S514_unlock(card, &smp_flags); + + if (err==0){ + delay_cmd(card,chan,HZ/10); + } + } + + S508_S514_lock(card, &smp_flags); + disconnect(card); + set_chan_state(dev,WAN_DISCONNECTED); + S508_S514_unlock(card, &smp_flags); + + err=0; + + break; + + case SIOC_WANPIPE_CHECK_TX: + case SIOC_ANNEXG_CHECK_TX: + err=0; + break; + + case SIOC_WANPIPE_DEV_STATE: + err = chan->common.state; + break; + + case SIOC_ANNEXG_KICK: + err=0; + break; + + case SIOC_X25_PLACE_CALL: + + S508_S514_lock(card, &smp_flags); + connect(card); + set_chan_state(dev,WAN_CONNECTING); + S508_S514_unlock(card, &smp_flags); + + if (atomic_read(&card->u.x.command_busy)){ + atomic_set(&card->u.x.command_busy,0); + } + + atomic_set(&chan->common.disconnect,0); + atomic_set(&chan->common.command,0); + + del_timer(&card->u.x.x25_timer); + card->u.x.x25_timer.expires=jiffies+HZ; + add_timer(&card->u.x.x25_timer); + +#if 0 + err=test_chan_command_busy(card,chan); + if (err){ + break; + } + + atomic_set(&chan->common.command,X25_PLACE_CALL); + trigger_intr_exec(card, TMR_INT_ENABLED_CMD_EXEC); + + del_timer(&card->u.x.x25_timer); + card->u.x.x25_timer.expires=jiffies+1; + add_timer(&card->u.x.x25_timer); + + err=wait_for_cmd_rc(card,chan); + + DEBUG_EVENT("%s:%s PLACE CALL RC %x\n",card->devname,dev->name,err); +#endif + break; + + case SIOC_X25_CLEAR_CALL: + + err=0; + break; + + err=test_chan_command_busy(card,chan); + if (err){ + break; + } + + atomic_set(&chan->common.command,X25_CLEAR_CALL); + trigger_intr_exec(card, TMR_INT_ENABLED_CMD_EXEC); + + err=wait_for_cmd_rc(card,chan); + + DEBUG_EVENT("%s:%s CLEAR CALL RC %i\n",card->devname,dev->name,err); + break; + + + case SIOC_WANPIPE_SNMP: + case SIOC_WANPIPE_SNMP_IFSPEED: + return wan_snmp_data(card, dev, cmd, ifr); + + case SIOC_WANPIPE_PIPEMON: + + if (atomic_read(&card->u.x.udp_pkt_len) != 0){ + return -EBUSY; + } + + atomic_set(&card->u.x.udp_pkt_len,sizeof(wan_udp_hdr_t)); + + wan_udp_pkt=(wan_udp_pkt_t*)&card->u.x.udp_pkt_data; + if (copy_from_user(&wan_udp_pkt->wan_udp_hdr,ifr->ifr_data,sizeof(wan_udp_hdr_t))){ + atomic_set(&card->u.x.udp_pkt_len,0); + return -EFAULT; + } + + spin_lock_irqsave(&card->wandev.lock, smp_flags); + + /* We have to check here again because we don't know + * what happened during spin_lock */ + if (test_bit(0,&card->in_isr)){ + printk(KERN_INFO "%s:%s pipemon command busy: try again!\n", + card->devname,dev->name); + atomic_set(&card->u.x.udp_pkt_len,0); + spin_unlock_irqrestore(&card->wandev.lock, smp_flags); + return -EBUSY; + } + + if (process_udp_mgmt_pkt(card,dev) <= 0 ){ + atomic_set(&card->u.x.udp_pkt_len,0); + spin_unlock_irqrestore(&card->wandev.lock, smp_flags); + return -EINVAL; + } + + + spin_unlock_irqrestore(&card->wandev.lock, smp_flags); + + /* This area will still be critical to other + * PIPEMON commands due to udp_pkt_len + * thus we can release the irq */ + + if (atomic_read(&card->u.x.udp_pkt_len) > sizeof(wan_udp_pkt_t)){ + printk(KERN_INFO "(Debug): PiPemon Buf too bit on the way up! %i\n", + atomic_read(&card->u.x.udp_pkt_len)); + atomic_set(&card->u.x.udp_pkt_len,0); + return -EINVAL; + } + + if (copy_to_user(ifr->ifr_data,&wan_udp_pkt->wan_udp_hdr,sizeof(wan_udp_hdr_t))){ + atomic_set(&card->u.x.udp_pkt_len,0); + return -EFAULT; + } + + atomic_set(&card->u.x.udp_pkt_len,0); + break; + + default: + printk(KERN_INFO "%s: Unsupported Ioctl Call 0x%x \n", + chan->common.dev->name,cmd); + return -EOPNOTSUPP; +#if 0 + DBG_PRINTK(KERN_INFO "Ioctl: Cmd 0x%x\n",atomic_read(&chan->common.command)); + + if (chan->common.usedby == API && + atomic_read(&chan->common.command)){ + + if (card->u.x.LAPB_hdlc && + atomic_read(&chan->common.command) == X25_PLACE_CALL){ + + unsigned long smp_flags; + + S508_S514_lock(card, &smp_flags); + connect(card); + set_chan_state(dev,WAN_CONNECTING); + S508_S514_unlock(card, &smp_flags); + + if (atomic_read(&card->u.x.command_busy)){ + atomic_set(&card->u.x.command_busy,0); + } + + atomic_set(&chan->common.disconnect,0); + atomic_set(&chan->common.command,0); + del_timer(&card->u.x.x25_timer); + card->u.x.x25_timer.expires=jiffies+HZ; + add_timer(&card->u.x.x25_timer); + }else{ + trigger_intr_exec(card,TMR_INT_ENABLED_CMD_EXEC); + } + } + + if ((chan->common.usedby == API) && + atomic_read(&chan->common.disconnect)){ + + unsigned long smp_flags; + + set_bit(0,&chan->common.disconnect); + + if (chan->common.state == WAN_CONNECTED){ + trigger_intr_exec(card,TMR_INT_ENABLED_CMD_EXEC); + }else{ + S508_S514_lock(card, &smp_flags); + hdlc_link_down(card); + disconnect(card); + set_chan_state(dev,WAN_DISCONNECTED); + S508_S514_unlock(card, &smp_flags); + } + } + + break; +#endif + } + return err; +} + +/* + * Interrupt Handlers + */ + +/* + * X.25 Interrupt Service Routine. + */ + +static void wpx_isr (sdla_t* card) +{ + TX25Status status; + card->hw_iface.peek(card->hw, card->flags_off, &status, sizeof(status)); + + /* Sanity check, should never happen */ + if (test_bit(0,&card->in_isr)){ + printk(KERN_INFO "%s: Critical in WPX_ISR\n",card->devname); + status.iflags = 0; + card->hw_iface.poke(card->hw, card->flags_off, &status, sizeof(status)); + return; + } + + card->in_isr = 1; + ++card->statistics.isr_entry; + + if (test_bit(PERI_CRIT,(void*)&card->wandev.critical)){ + printk(KERN_INFO "%s: Critical in PERI\n",card->devname); + card->in_isr=0; + status.iflags = 0; + card->hw_iface.poke(card->hw, card->flags_off, &status, sizeof(status)); + return; + } + + if (test_bit(SEND_CRIT, (void*)&card->wandev.critical)){ + + printk(KERN_INFO "%s: wpx_isr: wandev.critical set to 0x%02lx, int type = 0x%02x\n", + card->devname, card->wandev.critical, status.iflags); + card->in_isr = 0; + status.iflags = 0; + card->hw_iface.poke(card->hw, card->flags_off, &status, sizeof(status)); + return; + } + + + /* For all interrupts set the critical flag to CRITICAL_RX_INTR. + * If the if_send routine is called with this flag set it will set + * the enable transmit flag to 1. (for a delayed interrupt) + */ + switch (status.iflags){ + + case RX_INTR_PENDING: /* receive interrupt */ + ++card->statistics.isr_rx; + rx_intr(card); + break; + + case TX_INTR_PENDING: /* transmit interrupt */ + ++card->statistics.isr_tx; + tx_intr(card); + break; + + case MODEM_INTR_PENDING: /* modem status interrupt */ + status_intr(card); + break; + + case X25_ASY_TRANS_INTR_PENDING: /* network event interrupt */ + event_intr(card); + break; + + case TIMER_INTR_PENDING: + timer_intr(card); + break; + + default: /* unwanted interrupt */ + ++card->statistics.isr_spurious; + spur_intr(card); + } + + card->in_isr = 0; + status.iflags = 0; + card->hw_iface.poke(card->hw, card->flags_off, &status, sizeof(status)); +} + +/* + * Receive interrupt handler. + * This routine handles fragmented IP packets using M-bit according to the + * RFC1356. + * o map ligical channel number to network interface. + * o allocate socket buffer or append received packet to the existing one. + * o if M-bit is reset (i.e. it's the last packet in a sequence) then + * decapsulate packet and pass socket buffer to the protocol stack. + * + * Notes: + * 1. When allocating a socket buffer, if M-bit is set then more data is + * coming and we have to allocate buffer for the maximum IP packet size + * expected on this channel. + * 2. If something goes wrong and X.25 packet has to be dropped (e.g. no + * socket buffers available) the whole packet sequence must be discarded. + */ + +static void rx_intr (sdla_t* card) +{ + wan_mbox_t rxmb; + unsigned lcn; + netdevice_t* dev = NULL; + x25_channel_t* chan; + struct sk_buff* skb=NULL; + + card->hw_iface.peek(card->hw, card->rxmb_off, &rxmb, sizeof(rxmb)); + lcn = rxmb.wan_x25_lcn; + dev = find_channel(card,lcn); + if (dev == NULL){ + /* Invalid channel, discard packet */ + DEBUG_EVENT("%s: receiving on orphaned LCN %d!\n", + card->devname, lcn); + return; + } + + chan = dev->priv; + chan->i_timeout_sofar = jiffies; + + + /* Copy the data from the board, into an + * skb buffer + */ + if (wanpipe_pull_data_in_skb(card,dev,&skb)){ + ++chan->ifstats.rx_dropped; + ++card->wandev.stats.rx_dropped; + ++chan->rx_intr_stat.rx_intr_no_socket; + ++chan->rx_intr_stat.rx_intr_bfr_not_passed_to_stack; + return; + } + + dev->last_rx = jiffies; /* timestamp */ + + + /* ------------ API ----------------*/ + + if (chan->common.usedby == API){ + + if (wan_api_enqueue_skb(chan,skb) < 0){ + ++chan->ifstats.rx_dropped; + ++card->wandev.stats.rx_dropped; + ++chan->rx_intr_stat.rx_intr_bfr_not_passed_to_stack; + wan_dev_kfree_skb(skb, FREE_READ); + return; + } + + chan->rx_skb = NULL; + + WAN_TASKLET_SCHEDULE(&chan->common.bh_task); + + return; + } + + + /* ------------- WANPIPE -------------------*/ + + /* set rx_skb to NULL so we won't access it later when kernel already owns it */ + chan->rx_skb=NULL; + + /* Decapsulate packet, if necessary */ + if (!skb->protocol && !wanrouter_type_trans(skb, dev)){ + /* can't decapsulate packet */ + wan_dev_kfree_skb(skb, FREE_READ); + ++chan->ifstats.rx_errors; + ++chan->ifstats.rx_dropped; + ++card->wandev.stats.rx_dropped; + ++chan->rx_intr_stat.rx_intr_bfr_not_passed_to_stack; + + }else{ + if( handle_IPXWAN(skb->data, chan->name, + chan->enable_IPX, chan->network_number, + skb->protocol)){ + + if( chan->enable_IPX ){ + if(chan_send(dev, skb->data, skb->len,0)){ + chan->tx_skb = skb; + }else{ + wan_dev_kfree_skb(skb, FREE_WRITE); + ++chan->rx_intr_stat.rx_intr_bfr_not_passed_to_stack; + } + }else{ + /* increment IPX packet dropped statistic */ + ++chan->ifstats.rx_dropped; + ++chan->rx_intr_stat.rx_intr_bfr_not_passed_to_stack; + } + }else{ + skb->mac.raw = skb->data; + chan->ifstats.rx_bytes += skb->len; + ++chan->ifstats.rx_packets; + ++chan->rx_intr_stat.rx_intr_bfr_passed_to_stack; + netif_rx(skb); + } + } + + return; +} + + +static int wanpipe_pull_data_in_skb (sdla_t *card, netdevice_t *dev, struct sk_buff **skb) +{ + void* bufptr; + wan_mbox_t rxmb; + unsigned len; + x25_channel_t* chan = dev->priv; + struct sk_buff* new_skb = *skb; + + card->hw_iface.peek(card->hw, card->rxmb_off, &rxmb, sizeof(rxmb)); + len = rxmb.wan_data_len; + /* Add on the API header to the received + * data + */ + len += sizeof(x25api_hdr_t); + + /* Allocate new socket buffer */ + new_skb = dev_alloc_skb(len + 15); + if (new_skb == NULL){ + printk(KERN_INFO "%s: no socket buffers available!\n", + card->devname); + chan->drop_sequence = 1; /* set flag */ + ++chan->ifstats.rx_dropped; + return 1; + } + + bufptr = skb_put(new_skb,len); + + if (chan->common.usedby == API){ + /* Fill in the x25api header + */ + x25api_t * api_data = (x25api_t*)bufptr; + api_data->hdr.qdm = rxmb.wan_x25_qdm; + api_data->hdr.cause = rxmb.wan_x25_cause; + api_data->hdr.diagn = rxmb.wan_x25_diagn; + api_data->hdr.length = rxmb.wan_data_len; + api_data->hdr.lcn = rxmb.wan_x25_lcn; + memcpy(api_data->data, rxmb.wan_data, rxmb.wan_data_len); + }else{ + memcpy(bufptr, rxmb.wan_data, len); + } + + new_skb->dev = dev; + + if (chan->common.usedby == API){ + new_skb->mac.raw = new_skb->data; + new_skb->protocol = htons(X25_PROT); + new_skb->pkt_type = WAN_PACKET_DATA; + }else{ + new_skb->protocol = chan->protocol; + } + + *skb = new_skb; + + return 0; +} + +/*=============================================================== + * tx_intr + * + * Transmit interrupt handler. + * For each dev, check that there is something to send. + * If data available, transmit. + * + *===============================================================*/ + +static void tx_intr (sdla_t* card) +{ + netdevice_t *dev; + TX25Status status; + x25_channel_t *chan=NULL; + + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + if (!dev || !wan_netif_priv(dev)) + return; + card->hw_iface.peek(card->hw, card->flags_off, &status, sizeof(status)); + + +#if 1 + /* Try sending an async packet first */ + if (card->u.x.timer_int_enabled & TMR_INT_ENABLED_CMD_EXEC){ + if (tx_intr_cmd_exec(card) == 0){ + card->u.x.timer_int_enabled &= + ~TMR_INT_ENABLED_CMD_EXEC; + }else{ + /* There are more commands pending + * re-trigger tx interrupt */ + DEBUG_TX("Re Triggerint Cmd\n"); + ++card->statistics.isr_enable_tx_int; + return; + } + } +#endif + + chan = dev->priv; + + + /* Device was set to transmit, check if the TX + * buffers are available + */ + + if (is_queue_stopped(dev)){ + if (chan->common.usedby == API){ + start_net_queue(dev); + wan_wakeup_api(chan); + }else{ + wake_net_dev(dev); + } + } + + /* if any other interfaces have transmit interrupts pending, */ + /* do not disable the global transmit interrupt */ + status.imask &= ~INTR_ON_TX_FRAME; + card->hw_iface.poke(card->hw, card->flags_off, &status, sizeof(status)); + return; +} + + +/*=============================================================== + * timer_intr + * + * Timer interrupt handler. + * Check who called the timer interrupt and perform + * action accordingly. + * + *===============================================================*/ + +static void timer_intr (sdla_t *card) +{ + TX25Status status; + + card->hw_iface.peek(card->hw, card->flags_off, &status, sizeof(status)); + if(card->u.x.timer_int_enabled & TMR_INT_ENABLED_UDP_PKT) { + + if (card->u.x.udp_type == UDP_XPIPE_TYPE){ + if(process_udp_mgmt_pkt(card,NULL)) { + card->u.x.timer_int_enabled &= + ~TMR_INT_ENABLED_UDP_PKT; + } + } + + }else if (card->u.x.timer_int_enabled & TMR_INT_ENABLED_POLL_ACTIVE) { + + netdevice_t *dev = card->u.x.poll_device; + x25_channel_t *chan = NULL; + + if (!dev){ + card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_POLL_ACTIVE; + return; + } + chan = dev->priv; + + printk(KERN_INFO + "%s: Closing down Idle link %s on LCN %d\n", + card->devname,chan->name,chan->common.lcn); + chan->i_timeout_sofar = jiffies; + chan_disc(dev); + card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_POLL_ACTIVE; + card->u.x.poll_device=NULL; + + }else if (card->u.x.timer_int_enabled & TMR_INT_ENABLED_POLL_CONNECT_ON) { + + netdevice_t *dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + wanpipe_set_state(card, WAN_CONNECTED); + set_chan_state(dev,WAN_CONNECTED); + + /* 0x8F enable all interrupts */ + x25_set_intr_mode(card, INTR_ON_RX_FRAME| + INTR_ON_TX_FRAME| + INTR_ON_MODEM_STATUS_CHANGE| + X25_ASY_TRANS_INTR_PENDING | + INTR_ON_TIMER | + DIRECT_RX_INTR_USAGE + ); + + status.imask &= ~INTR_ON_TX_FRAME; /* mask Tx interrupts */ + card->hw_iface.poke(card->hw, card->flags_off, &status, sizeof(status)); + card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_POLL_CONNECT_ON; + + }else if (card->u.x.timer_int_enabled & TMR_INT_ENABLED_POLL_CONNECT_OFF) { + DEBUG_TX("%s: Poll connect, Turning OFF\n",card->devname); + disconnect(card); + if (card->u.x.LAPB_hdlc){ + netdevice_t *dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + set_chan_state(dev,WAN_DISCONNECTED); + send_oob_msg(card,dev,&card->wan_mbox); + } + card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_POLL_CONNECT_OFF; + + }else if (card->u.x.timer_int_enabled & TMR_INT_ENABLED_POLL_DISCONNECT) { + + DBG_PRINTK(KERN_INFO "POll disconnect, trying to connect\n"); + connect(card); + if (card->u.x.LAPB_hdlc){ + netdevice_t *dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + set_chan_state(dev,WAN_CONNECTED); + } + card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_POLL_DISCONNECT; + + }else if (card->u.x.timer_int_enabled & TMR_INT_ENABLED_UPDATE){ + +#if 0 + if (*card->u.x.hdlc_buf_status & 0x40){ + x25_get_err_stats(card); + x25_get_stats(card); + card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_UPDATE; + } +#else + x25_get_err_stats(card); + x25_get_stats(card); + card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_UPDATE; +#endif + } + + if(!(card->u.x.timer_int_enabled & ~TMR_INT_ENABLED_CMD_EXEC)){ + //printk(KERN_INFO "Turning Timer Off \n"); + status.imask &= ~INTR_ON_TIMER; + card->hw_iface.poke(card->hw, card->flags_off, &status, sizeof(status)); + } +} + +/*==================================================================== + * Modem status interrupt handler. + *===================================================================*/ +static void status_intr (sdla_t* card) +{ + + /* Added to avoid Modem status message flooding */ + static TX25ModemStatus last_stat; + wan_mbox_t* mbox = &card->wan_mbox; + TX25ModemStatus* modem_status; + netdevice_t* dev; + x25_channel_t* chan; + int err; + + memset(&mbox->wan_command, 0, sizeof(TX25Cmd)); + mbox->wan_command = X25_READ_MODEM_STATUS; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mbox); + if (err){ + x25_error(card, err, X25_READ_MODEM_STATUS, 0); + }else{ + + modem_status = (TX25ModemStatus*)mbox->wan_data; + + /* Check if the last status was the same + * if it was, do NOT print message again */ + + if (last_stat.status != modem_status->status){ + + printk(KERN_INFO "%s: Modem Status Change: DCD=%s, CTS=%s\n", + card->devname,DCD(modem_status->status),CTS(modem_status->status)); + + last_stat.status = modem_status->status; + + if (card->u.x.oob_on_modem){ + struct wan_dev_le *devle; + + DBG_PRINTK(KERN_INFO "Modem status oob msg!\n"); + + mbox->wan_x25_pktType = mbox->wan_command; + mbox->wan_return_code = 0x08; + + /* Send a OOB to all connected sockets */ + WAN_LIST_FOREACH(devle, &card->wandev.dev_head, dev_link){ + dev = WAN_DEVLE2DEV(devle); + if (!dev || !wan_netif_priv(dev)) + continue; + chan = wan_netif_priv(dev); + if (chan->common.usedby == API){ + printk(KERN_INFO "(Debug): Send oob msg 5\n"); + + send_oob_msg(card,dev,mbox); + } + } + + /* The modem OOB message will probably kill the + * the link. If we don't clear the flag here, + * a deadlock could occur */ + if (atomic_read(&card->u.x.command_busy)){ + atomic_set(&card->u.x.command_busy,0); + } + } + } + } + + memset(&mbox->wan_command, 0, sizeof(TX25Cmd)); + mbox->wan_command = X25_HDLC_LINK_STATUS; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mbox); + if (err){ + x25_error(card, err, X25_HDLC_LINK_STATUS, 0); + } + +} + +/*==================================================================== + * Network event interrupt handler. + *===================================================================*/ +static void event_intr (sdla_t* card) +{ + x25_fetch_events(card); +} + +/*==================================================================== + * Spurious interrupt handler. + * o print a warning + * o + *====================================================================*/ + +static void spur_intr (sdla_t* card) +{ + printk(KERN_INFO "%s: spurious interrupt!\n", card->devname); +} + + +/* + * Background Polling Routines + */ + +/*==================================================================== + * Main polling routine. + * This routine is repeatedly called by the WANPIPE 'thead' to allow for + * time-dependent housekeeping work. + * + * Notes: + * 1. This routine may be called on interrupt context with all interrupts + * enabled. Beware! + *====================================================================*/ + +static void wpx_poll (void *card_ptr) +{ + netdevice_t *dev; + sdla_t *card=card_ptr; + ++card->statistics.poll_processed; + + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + if (!dev){ + goto wpx_poll_exit; + } + + if (test_bit(PERI_CRIT,&card->wandev.critical)){ + goto wpx_poll_exit; + } + + if (test_bit(SEND_CRIT,&card->wandev.critical)){ + goto wpx_poll_exit; + } + + switch(card->wandev.state){ + case WAN_CONNECTED: + poll_active(card); + break; + + case WAN_CONNECTING: + poll_connecting(card); + break; + + case WAN_DISCONNECTED: +#if 0 + poll_disconnected(card); +#endif + break; + } + +wpx_poll_exit: + clear_bit(POLL_CRIT,&card->wandev.critical); + return; +} + +static void trigger_x25_poll(sdla_t *card) +{ + wan_schedule_task(&card->u.x.x25_poll_task); +} + +/*==================================================================== + * Handle physical link establishment phase. + * o if connection timed out, disconnect the link. + *===================================================================*/ + +static void poll_connecting (sdla_t* card) +{ + TX25Status status; + card->hw_iface.peek(card->hw, card->flags_off, &status, sizeof(status)); + + if (status.ghdlc_status & X25_HDLC_ABM){ + + trigger_intr_exec (card, TMR_INT_ENABLED_POLL_CONNECT_ON); + + }else if ((jiffies - card->state_tick) > CONNECT_TIMEOUT){ + + trigger_intr_exec (card, TMR_INT_ENABLED_POLL_CONNECT_OFF); + + } +} + +#if 0 +/*==================================================================== + * Handle physical link disconnected phase. + * o if hold-down timeout has expired and there are open interfaces, + * connect link. + *===================================================================*/ + +static void poll_disconnected (sdla_t* card) +{ + netdevice_t *dev; + x25_channel_t *chan; + + + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + if (dev == NULL) + return; + + if ((chan=dev->priv) == NULL) + return; + + if (card->open_cnt && (jiffies - card->state_tick) > HOLD_DOWN_TIME){ + trigger_intr_exec(card, TMR_INT_ENABLED_POLL_DISCONNECT); + } +} +#endif + +/*==================================================================== + * Handle active link phase. + * o fetch X.25 asynchronous events. + * o kick off transmission on all interfaces. + *===================================================================*/ + +static void poll_active (sdla_t* card) +{ + TX25Status status; + netdevice_t *dev; + x25_channel_t *chan; + + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + if (!dev || !wan_netif_priv(dev)) + return; + chan = wan_netif_priv(dev); + card->hw_iface.peek(card->hw, card->flags_off, &status, sizeof(status)); + if (!(status.ghdlc_status & X25_HDLC_ABM)){ + + if (jiffies-chan->disc_delay < HZ){ + return; + } + + trigger_intr_exec (card, TMR_INT_ENABLED_POLL_CONNECT_OFF); + } +} + +static void trigger_intr_exec(sdla_t *card, unsigned char TYPE) +{ + TX25Status status; + card->hw_iface.peek(card->hw, card->flags_off, &status, sizeof(status)); + + card->u.x.timer_int_enabled |= TYPE; + if (TYPE == TMR_INT_ENABLED_CMD_EXEC){ + status.imask |= INTR_ON_TX_FRAME; + card->hw_iface.poke(card->hw, card->flags_off, &status, sizeof(status)); + } +} + +/*==================================================================== + * SDLA Firmware-Specific Functions + * + * Almost all X.25 commands can unexpetedly fail due to so called 'X.25 + * asynchronous events' such as restart, interrupt, incoming call request, + * call clear request, etc. They can't be ignored and have to be delt with + * immediately. To tackle with this problem we execute each interface + * command in a loop until good return code is received or maximum number + * of retries is reached. Each interface command returns non-zero return + * code, an asynchronous event/error handler x25_error() is called. + *====================================================================*/ + +/*==================================================================== + * Read X.25 firmware version. + * Put code version as ASCII string in str. + *===================================================================*/ + +static int x25_get_version (sdla_t* card, char* str) +{ + wan_mbox_t* mbox = &card->wan_mbox; + int retry = MAX_CMD_RETRY; + int err; + + do + { + memset(&mbox->wan_command, 0, sizeof(TX25Cmd)); + mbox->wan_command = X25_READ_CODE_VERSION; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mbox); + } while (err && x25_error(card, err, X25_READ_CODE_VERSION, 0) && retry--); + + if (!err && str) + { + int len = mbox->wan_data_len; + + memcpy(str, mbox->wan_data, len); + str[len] = '\0'; + } + return err; +} + +/*==================================================================== + * Configure adapter for HDLC only. + *===================================================================*/ + +static int hdlc_configure (sdla_t* card, TX25Config* conf) +{ + wan_mbox_t* mbox = &card->wan_mbox; + int retry = MAX_CMD_RETRY; + int err; + + do{ + memset(&mbox->wan_command, 0, sizeof(TX25Cmd)); + memcpy(mbox->wan_data, (void*)conf, sizeof(TX25Config)); + mbox->wan_data_len = sizeof(TX25Config); + mbox->wan_command = X25_HDLC_SET_CONFIG; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mbox); + } while (err && x25_error(card, err, X25_SET_CONFIGURATION, 0) && retry--); + + return err; +} + + +/*==================================================================== + * Get communications error statistics. + *====================================================================*/ + +static int x25_get_err_stats (sdla_t* card) +{ + wan_mbox_t* mbox = &card->wan_mbox; + int retry = MAX_CMD_RETRY; + int err; + + do + { + memset(&mbox->wan_command, 0, sizeof(TX25Cmd)); + mbox->wan_command = X25_HDLC_READ_COMM_ERR; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mbox); + } while (err && x25_error(card, err, X25_HDLC_READ_COMM_ERR, 0) && retry--); + + if (!err) + { + THdlcCommErr* stats = (void*)mbox->wan_data; + + card->wandev.stats.rx_over_errors = stats->rxOverrun; + card->wandev.stats.rx_crc_errors = stats->rxBadCrc; + card->wandev.stats.rx_missed_errors = stats->rxAborted; + card->wandev.stats.tx_aborted_errors = stats->txAborted; + } + return err; +} + +/*==================================================================== + * Get protocol statistics. + *===================================================================*/ + +static int x25_get_stats (sdla_t* card) +{ + wan_mbox_t* mbox = &card->wan_mbox; + int retry = MAX_CMD_RETRY; + int err; + + do + { + memset(&mbox->wan_command, 0, sizeof(TX25Cmd)); + mbox->wan_command = X25_READ_STATISTICS; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mbox); + } while (err && x25_error(card, err, X25_READ_STATISTICS, 0) && retry--) ; + + if (!err) + { + TX25Stats* stats = (void*)mbox->wan_data; + + card->wandev.stats.rx_packets = stats->rxData; + card->wandev.stats.tx_packets = stats->txData; + memcpy(&X25Stats, mbox->wan_data, mbox->wan_data_len); + } + return err; +} + +/*==================================================================== + * Close HDLC link. + *===================================================================*/ + +static int x25_close_hdlc (sdla_t* card) +{ + wan_mbox_t* mbox = &card->wan_mbox; + int retry = MAX_CMD_RETRY; + int err; + + do + { + memset(&mbox->wan_command, 0, sizeof(TX25Cmd)); + mbox->wan_command = X25_HDLC_LINK_CLOSE; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mbox); + } while (err && x25_error(card, err, X25_HDLC_LINK_CLOSE, 0) && retry--); + + return err; +} + + +/*==================================================================== + * Open HDLC link. + *===================================================================*/ + +static int x25_open_hdlc (sdla_t* card) +{ + wan_mbox_t* mbox = &card->wan_mbox; + int retry = MAX_CMD_RETRY; + int err; + + do + { + memset(&mbox->wan_command, 0, sizeof(TX25Cmd)); + mbox->wan_command = X25_HDLC_LINK_OPEN; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mbox); + } while (err && x25_error(card, err, X25_HDLC_LINK_OPEN, 0) && retry--); + + return err; +} + +/*===================================================================== + * Setup HDLC link. + *====================================================================*/ +static int x25_setup_hdlc (sdla_t* card) +{ + wan_mbox_t* mbox = &card->wan_mbox; + int retry = MAX_CMD_RETRY; + int err; + + do + { + memset(&mbox->wan_command, 0, sizeof(TX25Cmd)); + mbox->wan_command = X25_HDLC_LINK_SETUP; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mbox); + } while (err && x25_error(card, err, X25_HDLC_LINK_SETUP, 0) && retry--); + + return err; +} + +/*==================================================================== + * Set interrupt mode. + *===================================================================*/ + +static int x25_set_intr_mode (sdla_t* card, int mode) +{ + wan_mbox_t* mbox = &card->wan_mbox; + int retry = MAX_CMD_RETRY; + int err; + + do + { + memset(&mbox->wan_command, 0, sizeof(TX25Cmd)); + mbox->wan_data[0] = mode; + mbox->wan_data[1] = card->wandev.irq; + mbox->wan_data[2] = 2; + mbox->wan_data_len = 3; + mbox->wan_command = X25_SET_INTERRUPT_MODE; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mbox); + } while (err && x25_error(card, err, X25_SET_INTERRUPT_MODE, 0) && retry--); + + return err; +} + +/*==================================================================== + * Read X.25 channel configuration. + *===================================================================*/ +#if 0 +static int x25_get_chan_conf (sdla_t* card, x25_channel_t* chan) +{ + wan_mbox_t* mbox = &card->wan_mbox; + int retry = MAX_CMD_RETRY; + int lcn = chan->common.lcn; + int err; + + do{ + memset(&mbox->wan_command, 0, sizeof(TX25Cmd)); + mbox->wan_x25_lcn = lcn; + mbox->wan_command = X25_READ_CHANNEL_CONFIG; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mbox); + } while (err && x25_error(card, err, X25_READ_CHANNEL_CONFIG, lcn) && retry--); + + return err; +} +#endif +/*==================================================================== + * Accept X.25 call. + *====================================================================*/ +#if 0 +static int x25_accept_call (sdla_t* card, int lcn, int qdm) +{ + wan_mbox_t* mbox = &card->wan_mbox; + int retry = MAX_CMD_RETRY; + int err; + + do + { + memset(&mbox->wan_command, 0, sizeof(TX25Cmd)); + mbox->wan_x25_lcn = lcn; + mbox->wan_x25_qdm = qdm; + mbox->wan_command = X25_ACCEPT_CALL; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mbox); + } while (err && x25_error(card, err, X25_ACCEPT_CALL, lcn) && retry--); + + return err; +} +#endif +/*==================================================================== +======= + * Clear X.25 call. + *====================================================================*/ + +static int x25_clear_call (sdla_t* card, int lcn, int cause, int diagn) +{ + wan_mbox_t* mbox = &card->wan_mbox; + int retry = MAX_CMD_RETRY; + int err; + + do + { + memset(&mbox->wan_command, 0, sizeof(TX25Cmd)); + mbox->wan_x25_lcn = lcn; + mbox->wan_x25_cause = cause; + mbox->wan_x25_diagn = diagn; + mbox->wan_command = X25_CLEAR_CALL; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mbox); + + } while (err && x25_error(card, err, X25_CLEAR_CALL, lcn) && retry--); + + return err; +} + +/*==================================================================== + * Send X.25 data packet. + *====================================================================*/ + +static int x25_send (sdla_t* card, int lcn, int qdm, int len, void* buf) +{ + wan_mbox_t* mbox = &card->wan_mbox; + int err; + unsigned char cmd; + + cmd = X25_HDLC_WRITE; + + memset(&mbox->wan_command, 0, sizeof(TX25Cmd)); + memcpy(mbox->wan_data, buf, len); + mbox->wan_data_len = (unsigned short)len; + mbox->wan_x25_lcn = (unsigned short)lcn; + + if (card->u.x.LAPB_hdlc){ + mbox->wan_x25_pf = (unsigned char)qdm; + }else{ + mbox->wan_x25_qdm = (unsigned char)qdm; + } + + mbox->wan_command = cmd; + + /* The P6-PCI caching used to be a bug on old + * S514 prototype boards. This has been fixed, + * however the check below is a sanity check */ + if (mbox->wan_opp_flag){ + printk(KERN_INFO "\n"); + printk(KERN_INFO "%s: Critical Error: P6-PCI Cache bug!\n", + card->devname); + printk(KERN_INFO "%s: Please contact Sangoma Tech Support!\n\n", + card->devname); + } + err = card->hw_iface.cmd(card->hw, card->mbox_off, mbox); + + if (err){ + x25_error(card, err, cmd , lcn); + } + + /* If buffers are busy the return code for LAPB HDLC is + * 1. The above functions are looking for return code + * of X25RES_NOT_READY if busy. */ + if (card->u.x.LAPB_hdlc && err == 1){ + err = X25RES_NOT_READY; + } + + return err; +} + +/*==================================================================== + * Fetch X.25 asynchronous events. + *===================================================================*/ + +static int x25_fetch_events (sdla_t* card) +{ + TX25Status status; + wan_mbox_t* mbox = &card->wan_mbox; + int err = 0; + + card->hw_iface.peek(card->hw, card->flags_off, &status, sizeof(status)); + if (status.hdlc_status & 0x20) + { + memset(&mbox->wan_command, 0, sizeof(TX25Cmd)); + mbox->wan_command = X25_IS_DATA_AVAILABLE; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mbox); + if (err) x25_error(card, err, X25_IS_DATA_AVAILABLE, 0); + } + return err; +} + +/*==================================================================== + * X.25 asynchronous event/error handler. + * This routine is called each time interface command returns + * non-zero return code to handle X.25 asynchronous events and + * common errors. Return non-zero to repeat command or zero to + * cancel it. + * + * Notes: + * 1. This function may be called recursively, as handling some of the + * asynchronous events (e.g. call request) requires execution of the + * interface command(s) that, in turn, may also return asynchronous + * events. To avoid re-entrancy problems we copy mailbox to dynamically + * allocated memory before processing events. + *====================================================================*/ + +static int x25_error (sdla_t* card, int err, int cmd, int lcn) +{ + netdevice_t *dev; + int retry = 1; + /* FIXME: CRITICAL NO MAILBOX */ +// unsigned dlen = ((wan_mbox_t*)card->mbox)->wan_data_len; + unsigned dlen = ((wan_mbox_t*)&card->wan_mbox)->wan_data_len; + wan_mbox_t* mb; + + mb = kmalloc(sizeof(wan_mbox_t) + dlen, GFP_ATOMIC); + if (mb == NULL) + { + printk(KERN_INFO "%s: x25_error() out of memory!\n", + card->devname); + return 0; + } + memcpy(mb, &card->wan_mbox, sizeof(wan_mbox_t) + dlen); + + switch (err){ + + case X25RES_ASYNC_PACKET: /* X.25 asynchronous packet was received */ + + mb->wan_data[dlen] = '\0'; + + switch (mb->wan_x25_pktType & 0x7F){ + + case ASE_CALL_RQST: /* incoming call */ + retry = incoming_call(card, cmd, lcn, mb); + break; + + case ASE_CALL_ACCEPTED: /* connected */ + retry = call_accepted(card, cmd, lcn, mb); + break; + + case ASE_CLEAR_RQST: /* call clear request */ + retry = call_cleared(card, cmd, lcn, mb); + x25_clear_cmd_update(card, lcn, mb); + break; + + case ASE_RESET_RQST: /* reset request */ + printk(KERN_INFO "%s: X.25 reset request on LCN %d! " + "Cause:0x%02X Diagn:0x%02X\n", + card->devname, mb->wan_x25_lcn, mb->wan_x25_cause, + mb->wan_x25_diagn); + api_oob_event (card,mb); + break; + + case ASE_RESTART_RQST: /* restart request */ + retry = restart_event(card, cmd, lcn, mb); + break; + + default: + printk(KERN_INFO "%s: X.25 event 0x%02X on LCN %d! " + "Cause:0x%02X Diagn:0x%02X\n", + card->devname, mb->wan_x25_pktType, + mb->wan_x25_lcn, mb->wan_x25_cause, mb->wan_x25_diagn); + api_oob_event (card,mb); + } + break; + + case X25RES_PROTO_VIOLATION: /* X.25 protocol violation indication */ + + /* Bug Fix: Mar 14 2000 + * The Protocol violation error conditions were + * not handeled previously */ + + switch (mb->wan_x25_pktType & 0x7F){ + + case PVE_CLEAR_RQST: /* Clear request */ + retry = call_cleared(card, cmd, lcn, mb); + break; + + case PVE_RESET_RQST: /* Reset request */ + printk(KERN_INFO "%s: X.25 reset request on LCN %d! " + "Cause:0x%02X Diagn:0x%02X\n", + card->devname, mb->wan_x25_lcn, mb->wan_x25_cause, + mb->wan_x25_diagn); + api_oob_event (card,mb); + break; + + case PVE_RESTART_RQST: /* Restart request */ + retry = restart_event(card, cmd, lcn, mb); + break; + + default : + printk(KERN_INFO + "%s: X.25 protocol violation on LCN %d! " + "Packet:0x%02X Cause:0x%02X Diagn:0x%02X\n", + card->devname, mb->wan_x25_lcn, + mb->wan_x25_pktType & 0x7F, mb->wan_x25_cause, mb->wan_x25_diagn); + api_oob_event(card,mb); + } + break; + + case 0x42: /* X.25 timeout */ + retry = timeout_event(card, cmd, lcn, mb); + break; + + case 0x43: /* X.25 retry limit exceeded */ + printk(KERN_INFO + "%s: exceeded X.25 retry limit on LCN %d! " + "Packet:0x%02X Diagn:0x%02X\n", card->devname, + mb->wan_x25_lcn, mb->wan_x25_pktType, mb->wan_x25_diagn); + break; + + case 0x08: /* modem failure */ +#ifndef MODEM_NOT_LOG + printk(KERN_INFO "%s: modem failure!\n", card->devname); +#endif + api_oob_event(card,mb); + break; + + case 0x09: /* N2 retry limit */ + printk(KERN_INFO "%s: exceeded HDLC retry limit!\n", + card->devname); + api_oob_event(card,mb); + break; + + case 0x06: /* unnumbered frame was received while in ABM */ + printk(KERN_INFO "%s: received Unnumbered frame 0x%02X!\n", + card->devname, mb->wan_data[0]); + api_oob_event(card,mb); + break; + + case CMD_TIMEOUT: + printk(KERN_INFO "%s: command 0x%02X timed out!\n", + card->devname, cmd); + retry = 0; /* abort command */ + break; + + case X25RES_NOT_READY: + retry = 1; + break; + + case X25RES_LINK_NOT_IN_ABM: + retry = 0; + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + set_chan_state(dev, WAN_DISCONNECTED); + break; + + case 0x01: + if (card->u.x.LAPB_hdlc) + break; + + if (mb->wan_command == 0x16) + break; + /* I use the goto statement here so if + * somebody inserts code between the + * case and default, we will not have + * ghost problems */ + goto dflt_2; + + default: +dflt_2: + printk(KERN_INFO "%s: command 0x%02X returned 0x%02X! Lcn %i\n", + card->devname, cmd, err, mb->wan_x25_lcn) + ; + retry = 0; /* abort command */ + } + kfree(mb); + return retry; +} + +/*==================================================================== + * X.25 Asynchronous Event Handlers + * These functions are called by the x25_error() and should return 0, if + * the command resulting in the asynchronous event must be aborted. + *====================================================================*/ + + + +/*==================================================================== + *Handle X.25 incoming call request. + * RFC 1356 establishes the following rules: + * 1. The first octet in the Call User Data (CUD) field of the call + * request packet contains NLPID identifying protocol encapsulation + * 2. Calls MUST NOT be accepted unless router supports requested + * protocol encapsulation. + * 3. A diagnostic code 249 defined by ISO/IEC 8208 may be used + * when clearing a call because protocol encapsulation is not + * supported. + * 4. If an incoming call is received while a call request is + * pending (i.e. call collision has occured), the incoming call + * shall be rejected and call request shall be retried. + *====================================================================*/ + +static int incoming_call (sdla_t* card, int cmd, int lcn, wan_mbox_t* mb) +{ + DEBUG_EVENT("%s: Unsupported incoming call!\n",card->devname); + + return 1; +} + + +/*==================================================================== + * Handle accepted call. + *====================================================================*/ + +static int call_accepted (sdla_t* card, int cmd, int lcn, wan_mbox_t* mb) +{ + DEBUG_EVENT("%s: Unsupported call accepted!\n",card->devname); + return 1; +} + +/*==================================================================== + * Handle cleared call. + *====================================================================*/ + +static int call_cleared (sdla_t* card, int cmd, int lcn, wan_mbox_t* mb) +{ + DEBUG_EVENT("%s: Unsupported call accepted!\n",card->devname); + return 1; +} + +/*==================================================================== + * Handle X.25 restart event. + *====================================================================*/ + +static int restart_event (sdla_t* card, int cmd, int lcn, wan_mbox_t* mb) +{ + struct wan_dev_le *devle; + netdevice_t* dev; + x25_channel_t *chan; + unsigned char old_state; + + printk(KERN_INFO + "%s: X.25 restart request! Cause:0x%02X Diagn:0x%02X\n", + card->devname, mb->wan_x25_cause, mb->wan_x25_diagn); + + /* down all logical channels */ + WAN_LIST_FOREACH(devle, &card->wandev.dev_head, dev_link){ + dev = WAN_DEVLE2DEV(devle); + if (!dev || !wan_netif_priv(dev)) + continue; + chan = wan_netif_priv(dev); + old_state = chan->common.state; + + if (chan->common.usedby == API){ + send_oob_msg(card,dev,mb); + } + + set_chan_state(dev, WAN_DISCONNECTED); + } + + if (card->sk){ + wanpipe_api_listen_rx(NULL,card->sk); + sock_put(card->sk); + card->sk=NULL; + } + + return (cmd == X25_WRITE) ? 0 : 1; +} + +/*==================================================================== + * Handle timeout event. + *====================================================================*/ + +static int timeout_event (sdla_t* card, int cmd, int lcn, wan_mbox_t* mb) +{ + unsigned new_lcn = mb->wan_x25_lcn; + + if (mb->wan_x25_pktType == 0x05) /* call request time out */ + { + netdevice_t* dev = find_channel(card,new_lcn); + + printk(KERN_INFO "%s: X.25 call timed timeout on LCN %d!\n", + card->devname, new_lcn); + + if (dev){ + set_chan_state(dev, WAN_DISCONNECTED); + } + }else{ + printk(KERN_INFO "%s: X.25 packet 0x%02X timeout on LCN %d!\n", + card->devname, mb->wan_x25_pktType, new_lcn); + } + return 1; +} + +/* + * Miscellaneous + */ + +/*==================================================================== + * Establish physical connection. + * o open HDLC and raise DTR + * + * Return: 0 connection established + * 1 connection is in progress + * <0 error + *===================================================================*/ + +static int connect (sdla_t* card) +{ + TX25Status status; + + if (x25_open_hdlc(card) || x25_setup_hdlc(card)){ + DEBUG_EVENT("Connect: FAILED\n"); + return -EIO; + } + + wanpipe_set_state(card, WAN_CONNECTING); + + x25_set_intr_mode(card, INTR_ON_TIMER); + status.imask &= ~INTR_ON_TIMER; + card->hw_iface.poke(card->hw, card->flags_off, &status, sizeof(status)); + + return 1; +} + +/* + * Tear down physical connection. + * o close HDLC link + * o drop DTR + * + * Return: 0 + * <0 error + */ + +static int disconnect (sdla_t* card) +{ + wanpipe_set_state(card, WAN_DISCONNECTED); + x25_set_intr_mode(card, INTR_ON_TIMER); /* disable all interrupt except timer */ + x25_close_hdlc(card); /* close HDLC link */ + //x25_set_dtr(card, 0); /* drop DTR */ + return 0; +} + +/* + * Disconnect logical channel. + * o if SVC then clear X.25 call + */ + +static int chan_disc (netdevice_t* dev) +{ + x25_channel_t* chan = dev->priv; + + if (chan->common.svc){ + x25_clear_call(chan->card, chan->common.lcn, 0, 0); + + /* For API we disconnect on clear + * confirmation. + */ + if (chan->common.usedby == API) + return 0; + } + + set_chan_state(dev, WAN_DISCONNECTED); + + return 0; +} + +/* + * Set logical channel state. + */ + +static void set_chan_state (netdevice_t* dev, int state) +{ + x25_channel_t* chan = dev->priv; + sdla_t* card = chan->card; + + if (chan->common.state != state) + { + switch (state) + { + case WAN_CONNECTED: + if (card->u.x.logging){ + printk (KERN_INFO + "%s: interface %s connected !\n", + card->devname, dev->name); + } + *(unsigned short*)dev->dev_addr = htons(chan->common.lcn); + chan->i_timeout_sofar = jiffies; + + /* LAPB is PVC Based */ + if (card->u.x.LAPB_hdlc){ + chan->common.svc=0; + } + + if (is_queue_stopped(dev)){ + if (chan->common.usedby == API){ + start_net_queue(dev); + wan_wakeup_api(chan); + }else{ + wake_net_dev(dev); + } + } + + break; + + case WAN_CONNECTING: + if (card->u.x.logging){ + printk (KERN_INFO + "%s: interface %s connecting ...\n", + card->devname, dev->name); + } + break; + + case WAN_DISCONNECTED: + if (card->u.x.logging){ + printk (KERN_INFO + "%s: interface %s disconnected!\n", + card->devname, dev->name); + } + + atomic_set(&chan->common.disconnect,0); + + atomic_set(&chan->common.command,0); + break; + + case WAN_DISCONNECTING: + if (card->u.x.logging){ + printk(KERN_INFO "\n"); + printk (KERN_INFO + "%s: interface %s disconnecting ...\n", + card->devname, dev->name); + } + atomic_set(&chan->common.disconnect,0); + break; + } + chan->common.state = state; + + if (chan->common.usedby == API){ + wan_update_api_state(chan); + } + + } + chan->state_tick = jiffies; +} + +/* + * Send packet on a logical channel. + * When this function is called, tx_skb field of the channel data + * space points to the transmit socket buffer. When transmission + * is complete, release socket buffer and reset 'tbusy' flag. + * + * Return: 0 - transmission complete + * 1 - busy + * + * Notes: + * 1. If packet length is greater than MTU for this channel, we'll fragment + * the packet into 'complete sequence' using M-bit. + * 2. When transmission is complete, an event notification should be issued + * to the router. + */ + +static int chan_send (netdevice_t* dev, void* buff, unsigned data_len, unsigned char tx_intr) +{ + x25_channel_t* chan = dev->priv; + sdla_t* card = chan->card; + unsigned len=0, qdm=0, res=0, orig_len = 0; + void *data; + int err; + u8 status; + + /* Check to see if channel is ready */ +#if 1 + card->hw_iface.peek(card->hw, card->u.x.hdlc_buf_status_off, &status, 1); + if (!(status & 0x80)){ + return 1; + } +#endif + + if (chan->common.usedby == API){ + /* Remove the API Header */ + x25api_hdr_t *api_data = (x25api_hdr_t *)buff; + + /* Set the qdm bits from the packet header + * User has the option to set the qdm bits + */ + qdm = api_data->qdm; + + orig_len = len = data_len - sizeof(x25api_hdr_t); + data = (unsigned char*)buff + sizeof(x25api_hdr_t); + }else{ + data = buff; + orig_len = len = data_len; + } + + /* Pass only first three bits of the qdm byte to the send + * routine. In case user sets any other bit which might + * cause errors. + */ + + err=x25_send(card, chan->common.lcn, (qdm&0x07), len, data); + switch(err){ + case 0x00: /* success */ + chan->i_timeout_sofar = jiffies; + +#if defined(LINUX_2_4)||defined(LINUX_2_6) + dev->trans_start=jiffies; +#endif + + ++chan->ifstats.tx_packets; + chan->ifstats.tx_bytes += len; + res=0; + break; + + case 0x33: /* Tx busy */ + DEBUG_TX("%s: Send: Big Error should have tx: storring %s\n", + card->devname,dev->name); + res=1; + break; + + default: /* failure */ + ++chan->ifstats.tx_errors; + DEBUG_EVENT("%s: Send: Failure to send 0x%X, retry later...\n", + card->devname,err); + res=1; + break; + } + return res; +} + + +/* + * Parse X.25 call request data and fill x25_call_info_t structure. + */ + +static void parse_call_info (unsigned char* str, x25_call_info_t* info) +{ + memset(info, 0, sizeof(x25_call_info_t)); + for (; *str; ++str) + { + int i; + unsigned char ch; + + if (*str == '-') switch (str[1]) { + + /* Take minus 2 off the maximum size so that + * last byte is 0. This way we can use string + * manipulaton functions on call information. + */ + + case 'd': /* destination address */ + for (i = 0; i < (MAX_X25_ADDR_SIZE-2); ++i){ + ch = str[2+i]; + if (isspace(ch)) break; + info->dest[i] = ch; + } + break; + + case 's': /* source address */ + for (i = 0; i < (MAX_X25_ADDR_SIZE-2); ++i){ + ch = str[2+i]; + if (isspace(ch)) break; + info->src[i] = ch; + } + break; + + case 'u': /* user data */ + for (i = 0; i < (MAX_X25_DATA_SIZE-2); ++i){ + ch = str[2+i]; + if (isspace(ch)) break; + info->user[i] = ch; + } + info->nuser = i; + break; + + case 'f': /* facilities */ + for (i = 0; i < (MAX_X25_FACL_SIZE-2); ++i){ + ch = str[2+i]; + if (isspace(ch)) break; + info->facil[i] = ch; + } + info->nfacil = i; + break; + } + } +} + +/* + * Convert line speed in bps to a number used by S502 code. + */ + +static unsigned char bps_to_speed_code (unsigned long bps) +{ + unsigned char number; + + if (bps <= 1200) number = 0x01; + else if (bps <= 2400) number = 0x02; + else if (bps <= 4800) number = 0x03; + else if (bps <= 9600) number = 0x04; + else if (bps <= 19200) number = 0x05; + else if (bps <= 38400) number = 0x06; + else if (bps <= 45000) number = 0x07; + else if (bps <= 56000) number = 0x08; + else if (bps <= 64000) number = 0x09; + else if (bps <= 74000) number = 0x0A; + else if (bps <= 112000) number = 0x0B; + else if (bps <= 128000) number = 0x0C; + else number = 0x0D; + + return number; +} + +static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number, unsigned short proto) +{ + int i; + + if( proto == ETH_P_IPX) { + /* It's an IPX packet */ + if(!enable_IPX) { + /* Return 1 so we don't pass it up the stack. */ + return 1; + } + } else { + /* It's not IPX so pass it up the stack.*/ + return 0; + } + + if( sendpacket[16] == 0x90 && + sendpacket[17] == 0x04) + { + /* It's IPXWAN */ + + if( sendpacket[2] == 0x02 && + sendpacket[34] == 0x00) + { + /* It's a timer request packet */ + printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n",devname); + + /* Go through the routing options and answer no to every + * option except Unnumbered RIP/SAP + */ + for(i = 41; sendpacket[i] == 0x00; i += 5) + { + /* 0x02 is the option for Unnumbered RIP/SAP */ + if( sendpacket[i + 4] != 0x02) + { + sendpacket[i + 1] = 0; + } + } + + /* Skip over the extended Node ID option */ + if( sendpacket[i] == 0x04 ) + { + i += 8; + } + + /* We also want to turn off all header compression opt. */ + for(; sendpacket[i] == 0x80 ;) + { + sendpacket[i + 1] = 0; + i += (sendpacket[i + 2] << 8) + (sendpacket[i + 3]) + 4; + } + + /* Set the packet type to timer response */ + sendpacket[34] = 0x01; + + printk(KERN_INFO "%s: Sending IPXWAN Timer Response\n",devname); + } + else if( sendpacket[34] == 0x02 ) + { + /* This is an information request packet */ + printk(KERN_INFO "%s: Received IPXWAN Information Request packet\n",devname); + + /* Set the packet type to information response */ + sendpacket[34] = 0x03; + + /* Set the router name */ + sendpacket[51] = 'X'; + sendpacket[52] = 'T'; + sendpacket[53] = 'P'; + sendpacket[54] = 'I'; + sendpacket[55] = 'P'; + sendpacket[56] = 'E'; + sendpacket[57] = '-'; + sendpacket[58] = CVHexToAscii(network_number >> 28); + sendpacket[59] = CVHexToAscii((network_number & 0x0F000000)>> 24); + sendpacket[60] = CVHexToAscii((network_number & 0x00F00000)>> 20); + sendpacket[61] = CVHexToAscii((network_number & 0x000F0000)>> 16); + sendpacket[62] = CVHexToAscii((network_number & 0x0000F000)>> 12); + sendpacket[63] = CVHexToAscii((network_number & 0x00000F00)>> 8); + sendpacket[64] = CVHexToAscii((network_number & 0x000000F0)>> 4); + sendpacket[65] = CVHexToAscii(network_number & 0x0000000F); + for(i = 66; i < 99; i+= 1) + { + sendpacket[i] = 0; + } + + printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n",devname); + } + else + { + printk(KERN_INFO "%s: Unknown IPXWAN packet!\n",devname); + return 0; + } + + /* Set the WNodeID to our network address */ + sendpacket[35] = (unsigned char)(network_number >> 24); + sendpacket[36] = (unsigned char)((network_number & 0x00FF0000) >> 16); + sendpacket[37] = (unsigned char)((network_number & 0x0000FF00) >> 8); + sendpacket[38] = (unsigned char)(network_number & 0x000000FF); + + return 1; + } else { + /*If we get here its an IPX-data packet, so it'll get passed up the stack. + */ + /* switch the network numbers */ + switch_net_numbers(sendpacket, network_number, 1); + return 0; + } +} + +/* + * If incoming is 0 (outgoing)- if the net numbers is ours make it 0 + * if incoming is 1 - if the net number is 0 make it ours + */ + +static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming) +{ + unsigned long pnetwork_number; + + pnetwork_number = (unsigned long)((sendpacket[6] << 24) + + (sendpacket[7] << 16) + (sendpacket[8] << 8) + + sendpacket[9]); + + + if (!incoming) { + /*If the destination network number is ours, make it 0 */ + if( pnetwork_number == network_number) { + sendpacket[6] = sendpacket[7] = sendpacket[8] = + sendpacket[9] = 0x00; + } + } else { + /* If the incoming network is 0, make it ours */ + if( pnetwork_number == 0) { + sendpacket[6] = (unsigned char)(network_number >> 24); + sendpacket[7] = (unsigned char)((network_number & + 0x00FF0000) >> 16); + sendpacket[8] = (unsigned char)((network_number & + 0x0000FF00) >> 8); + sendpacket[9] = (unsigned char)(network_number & + 0x000000FF); + } + } + + + pnetwork_number = (unsigned long)((sendpacket[18] << 24) + + (sendpacket[19] << 16) + (sendpacket[20] << 8) + + sendpacket[21]); + + + if( !incoming ) { + /* If the source network is ours, make it 0 */ + if( pnetwork_number == network_number) { + sendpacket[18] = sendpacket[19] = sendpacket[20] = + sendpacket[21] = 0x00; + } + } else { + /* If the source network is 0, make it ours */ + if( pnetwork_number == 0 ) { + sendpacket[18] = (unsigned char)(network_number >> 24); + sendpacket[19] = (unsigned char)((network_number & + 0x00FF0000) >> 16); + sendpacket[20] = (unsigned char)((network_number & + 0x0000FF00) >> 8); + sendpacket[21] = (unsigned char)(network_number & + 0x000000FF); + } + } +} /* switch_net_numbers */ + + + + +/********************* X25API SPECIFIC FUNCTIONS ****************/ + + +/*=============================================================== + * find_channel + * + * Manages the lcn to device map. It increases performance + * because it eliminates the need to search through the link + * list for a device which is bounded to a specific lcn. + * + *===============================================================*/ + + +netdevice_t * find_channel(sdla_t *card, unsigned lcn) +{ + return WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); +} + + +/*=============================================================== + * x25api_bh + * + * + *==============================================================*/ + +static void x25api_bh (unsigned long data) +{ + x25_channel_t* chan = (x25_channel_t*)data; + struct sk_buff *skb; + int len; + + while ((skb=wan_api_dequeue_skb(chan))){ + + len=skb->len; + if (chan->common.usedby == API){ + if (wan_api_rx(chan,skb) == 0){ + ++chan->rx_intr_stat.rx_intr_bfr_passed_to_stack; + ++chan->ifstats.rx_packets; + chan->ifstats.rx_bytes += len; + }else{ + ++chan->ifstats.rx_dropped; + ++chan->rx_intr_stat.rx_intr_bfr_not_passed_to_stack; + wan_skb_free(skb); + } + } + } + + WAN_TASKLET_END((&chan->common.bh_task)); + + return; +} + +/*=============================================================== + * tx_intr_cmd_exec + * + * Called by TX interrupt to execute a command + *===============================================================*/ + +static int tx_intr_cmd_exec (sdla_t* card) +{ + + netdevice_t *dev; + volatile x25_channel_t *chan=NULL; + u8 status; + int bad_cmd=0,err=0; + // FIXME: CRITICAL NO MAILBOX + wan_mbox_t *mbox=&card->wan_mbox; + + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + if (!dev){ + return 0; + } + + chan = dev->priv; + if (!chan){ + return 0; + } + + card->hw_iface.peek(card->hw, card->u.x.hdlc_buf_status_off, &status, 1); + if (!(status & 0x80)){ + DEBUG_EVENT("%s: Tx intr hdlc buf status 0x%x: BUSY\n", + card->devname, status); + return 1; + } + + DEBUG_EVENT("TX INTR Cmd %x\n",atomic_read(&chan->common.command)); + + if (atomic_read(&chan->common.command)){ + + err = execute_delayed_cmd(card, dev, + bad_cmd); + + chan->x25_api_event.hdr.qdm = mbox->wan_x25_qdm; + chan->x25_api_event.hdr.cause = mbox->wan_x25_cause; + chan->x25_api_event.hdr.diagn = mbox->wan_x25_diagn; + chan->x25_api_event.hdr.pktType = mbox->wan_x25_pktType&0x7F; + chan->x25_api_event.hdr.length = 0; + chan->x25_api_event.hdr.result = 0; + chan->x25_api_event.hdr.lcn = mbox->wan_x25_lcn; + chan->x25_api_event.hdr.mtu = card->u.x.x25_conf.defPktSize; + chan->x25_api_event.hdr.mru = card->u.x.x25_conf.defPktSize; + + atomic_set(&chan->cmd_rc,err); + + switch (err){ + + default: + + /* Return the result to the socket without + * delay. NO_WAIT Command */ + atomic_set(&chan->common.command,0); + break; + + case -EAGAIN: + + /* If command could not be executed for + * some reason (i.e return code 0x33 busy) + * set the more_to_exec bit which will + * indicate that this command must be exectued + * again during next timer interrupt + */ + chan->cmd_timeout=jiffies; + return 1; + } + } + + return 0; +} + +/*=============================================================== + * execute_delayed_cmd + * + * Execute an API command which was passed down from the + * sock. Sock is very limited in which commands it can + * execute. Wait and No Wait commands are supported. + * Place Call, Clear Call and Reset wait commands, where + * Accept Call is a no_wait command. + * + *===============================================================*/ +static int execute_delayed_cmd (sdla_t* card, netdevice_t *dev, char bad_cmd) +{ + wan_mbox_t* mbox = &card->wan_mbox; + int err; + x25_channel_t *chan=dev->priv; + + /* If channel is pvc, instead of place call + * run x25_channel configuration. If running LAPB HDLC + * enable communications. + */ + + if (atomic_read(&chan->common.command) == X25_PLACE_CALL){ + connect(card); + set_chan_state(dev,WAN_CONNECTING); + return 0; + }else{ + TX25LinkStatus *status; + TX25Status flags; + + memset(&mbox->wan_command, 0, sizeof(TX25Cmd)); + mbox->wan_command = X25_HDLC_LINK_STATUS; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mbox); + if (err){ + x25_error(card, err, X25_HDLC_LINK_STATUS, 0); + } + + status = (TX25LinkStatus *)mbox->wan_data; + + if (status->txQueued){ + DEBUG_TX("LAPB: Tx Queued busy! %d\n", + status->txQueued); + return -EAGAIN; + } + + if (flags.ghdlc_status & X25_HDLC_ABM){ + DEBUG_TX("LAPB: HDLC Down ! TxQ=%d HDLC_Status=%d\n", + status->txQueued, + flags->ghdlc_status); + hdlc_link_down(card); + chan->disc_delay = jiffies; + } + + DEBUG_EVENT("%s: Link Disconnecting ...\n",card->devname); + + return 0; + } +} + +/*=============================================================== + * send_oob_msg + * + * Construct an NEM Message and pass it up the connected + * sock. If the sock is not bounded discard the NEM. + * + *===============================================================*/ + +static int send_oob_msg (sdla_t *card, netdevice_t *dev, wan_mbox_t *mbox) +{ + unsigned char *buf; + int len = sizeof(x25api_hdr_t)+mbox->wan_data_len; + x25api_hdr_t *x25_api_hdr; + x25_channel_t *chan=dev->priv; + struct sk_buff *skb; + int err=0; + if (chan->common.usedby != API) + return -ENODEV; + + if (!chan->common.sk){ + return -ENODEV; + } + + if (len > sizeof(x25api_t)){ + DEBUG_EVENT("%s: %s: oob len > x25api_t!\n", + card->devname,__FUNCTION__); + return -EINVAL; + } + + if (alloc_and_init_skb_buf(card,&skb,len)){ + return -ENOMEM; + } + + buf = skb_put(skb,sizeof(x25api_hdr_t)); + if (!buf){ + wan_skb_free(skb); + return -ENOMEM; + } + + x25_api_hdr = (x25api_hdr_t *)buf; + + x25_api_hdr->qdm = mbox->wan_x25_qdm; + x25_api_hdr->cause = mbox->wan_x25_cause; + x25_api_hdr->diagn = mbox->wan_x25_diagn; + x25_api_hdr->pktType = mbox->wan_x25_pktType&0x7F; + x25_api_hdr->length = len; + x25_api_hdr->result = 0; + x25_api_hdr->lcn = mbox->wan_x25_lcn; + x25_api_hdr->mtu = card->u.x.x25_conf.defPktSize; + x25_api_hdr->mru = card->u.x.x25_conf.defPktSize; + + if (mbox->wan_data_len > 0 && mbox->wan_data_len <= X25_CALL_STR_SZ){ + buf = skb_put(skb,mbox->wan_data_len); + if (!buf){ + wan_skb_free(skb); + return -ENOMEM; + } + memcpy(buf,mbox->wan_data,mbox->wan_data_len); + } + + memcpy(&chan->x25_api_event,skb->data,skb->len); + + skb->pkt_type = WAN_PACKET_ERR; + skb->protocol=htons(ETH_P_X25); + + if (chan->common.sk){ + err=wanpipe_api_sock_rx(skb,chan->common.dev,chan->common.sk); + if (err != 0 ){ + if (err == -EINVAL){ + printk(KERN_INFO "%s:Major Error in Socket Above: OOB!!!\n", + chan->common.dev->name); + __sock_put(chan->common.sk); + clear_bit(LCN_SK_ID,&chan->common.used); + chan->common.sk = NULL; + } + wan_skb_free(skb); + + err=0; + } + }else{ + printk(KERN_INFO "%s: Error: No dev for OOB\n",chan->common.dev->name); + err=0; + wan_skb_free(skb); + } + + return err; +} + +/*=============================================================== + * alloc_and_init_skb_buf + * + * Allocate and initialize an skb buffer. + * + *===============================================================*/ + +static int alloc_and_init_skb_buf (sdla_t *card, struct sk_buff **skb, int len) +{ + struct sk_buff *new_skb = *skb; + + new_skb = dev_alloc_skb(len + X25_HRDHDR_SZ); + if (new_skb == NULL){ + printk(KERN_INFO "%s: no socket buffers available!\n", + card->devname); + return 1; + } + + if (skb_tailroom(new_skb) < len){ + /* No room for the packet. Call off the whole thing! */ + wan_dev_kfree_skb(new_skb, FREE_READ); + printk(KERN_INFO "%s: Listen: unexpectedly long packet sequence\n" + ,card->devname); + *skb = NULL; + return 1; + } + + *skb = new_skb; + return 0; + +} + +/*=============================================================== + * api_oob_event + * + * Send an OOB event up to the sock + * + *===============================================================*/ + +static void api_oob_event (sdla_t *card,wan_mbox_t *mbox) +{ + netdevice_t *dev = find_channel(card,mbox->wan_x25_lcn); + x25_channel_t *chan; + + if (!dev) + return; + + chan=dev->priv; + + if (chan->common.usedby == API){ + send_oob_msg(card,dev,mbox); + } +} + + + + + +static int hdlc_link_down (sdla_t *card) +{ + wan_mbox_t* mbox = &card->wan_mbox; + int retry = 5; + int err=0; + + do { + memset(mbox,0,sizeof(wan_mbox_t)); + mbox->wan_command = X25_HDLC_LINK_DISC; + mbox->wan_data_len = 1; + mbox->wan_x25_pf = 1; + mbox->wan_data[0]=0; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mbox); + + } while (err && x25_error(card, err, X25_HDLC_LINK_DISC, 0) && retry--); + + if (err){ + DEBUG_EVENT("%s: Hdlc Link Down Failed 0x%x\n", + card->devname,err); + } + + return err; +} + + +/*************************** XPIPEMON FUNCTIONS **************************/ + +/*============================================================================== + * Process UDP call of type XPIPE + */ + +static int process_udp_mgmt_pkt(sdla_t *card,netdevice_t *local_dev) +{ + int c_retry = MAX_CMD_RETRY; + unsigned int len; + struct sk_buff *new_skb; + wan_mbox_t *mbox = &card->wan_mbox; + int err; + int udp_mgmt_req_valid = 1; + netdevice_t *dev; + x25_channel_t *chan; + unsigned short lcn; + struct timeval tv; + wan_udp_pkt_t *wan_udp_pkt = (wan_udp_pkt_t *)&card->u.x.udp_pkt_data; + + if (local_dev){ + dev = local_dev; + }else{ + dev = card->u.x.udp_dev; + } + + if (!dev){ + atomic_set(&card->u.x.udp_pkt_len,0); + return 0; + } + + chan = dev->priv; + lcn = chan->common.lcn; + + switch(wan_udp_pkt->wan_udp_command) { + + /* XPIPE_ENABLE_TRACE */ + case XPIPE_ENABLE_TRACING: + + /* XPIPE_GET_TRACE_INFO */ + case XPIPE_GET_TRACE_INFO: + + /* SET FT1 MODE */ + case XPIPE_SET_FT1_MODE: + + if(card->u.x.udp_pkt_src == UDP_PKT_FRM_NETWORK) { + ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_direction_err; + udp_mgmt_req_valid = 0; + break; + } + + /* XPIPE_FT1_READ_STATUS */ + case XPIPE_FT1_READ_STATUS: + + /* FT1 MONITOR STATUS */ + case XPIPE_FT1_STATUS_CTRL: + ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_adptr_type_err; + udp_mgmt_req_valid = 0; + break; + default: + break; + } + + if(!udp_mgmt_req_valid) { + /* set length to 0 */ + wan_udp_pkt->wan_udp_data_len = 0; + /* set return code */ + wan_udp_pkt->wan_udp_return_code = 0xCD; + + } else { + + switch (wan_udp_pkt->wan_udp_command) { + + + case XPIPE_FLUSH_DRIVER_STATS: + init_x25_channel_struct(chan); + init_global_statistics(card); + mbox->wan_data_len = 0; + break; + + + case XPIPE_DRIVER_STAT_IFSEND: + memcpy(wan_udp_pkt->wan_udp_data, &chan->if_send_stat, sizeof(if_send_stat_t)); + mbox->wan_data_len = sizeof(if_send_stat_t); + wan_udp_pkt->wan_udp_data_len = mbox->wan_data_len; + break; + + case XPIPE_DRIVER_STAT_INTR: + memcpy(&wan_udp_pkt->wan_udp_data[0], &card->statistics, sizeof(global_stats_t)); + memcpy(&wan_udp_pkt->wan_udp_data[sizeof(global_stats_t)], + &chan->rx_intr_stat, sizeof(rx_intr_stat_t)); + + mbox->wan_data_len = sizeof(global_stats_t) + + sizeof(rx_intr_stat_t); + wan_udp_pkt->wan_udp_data_len = mbox->wan_data_len; + break; + + case XPIPE_DRIVER_STAT_GEN: + memcpy(wan_udp_pkt->wan_udp_data, + &chan->pipe_mgmt_stat.UDP_PIPE_mgmt_kmalloc_err, + sizeof(pipe_mgmt_stat_t)); + + memcpy(&wan_udp_pkt->wan_udp_data[sizeof(pipe_mgmt_stat_t)], + &card->statistics, sizeof(global_stats_t)); + + wan_udp_pkt->wan_udp_return_code = 0; + wan_udp_pkt->wan_udp_data_len = sizeof(global_stats_t)+ + sizeof(rx_intr_stat_t); + mbox->wan_data_len = wan_udp_pkt->wan_udp_data_len; + break; + + case XPIPE_ROUTER_UP_TIME: + do_gettimeofday(&tv); + chan->router_up_time = tv.tv_sec - chan->router_start_time; + *(unsigned long *)&wan_udp_pkt->wan_udp_data = chan->router_up_time; + wan_udp_pkt->wan_udp_data_len = mbox->wan_data_len = 4; + wan_udp_pkt->wan_udp_return_code = 0; + break; + + case WAN_GET_PROTOCOL: + wan_udp_pkt->wan_udp_data[0] = WANCONFIG_X25; + wan_udp_pkt->wan_udp_return_code = CMD_OK; + mbox->wan_data_len = wan_udp_pkt->wan_udp_data_len = 1; + break; + + case WAN_GET_PLATFORM: + wan_udp_pkt->wan_udp_data[0] = WAN_LINUX_PLATFORM; + wan_udp_pkt->wan_udp_return_code = CMD_OK; + mbox->wan_data_len = wan_udp_pkt->wan_udp_data_len = 1; + break; + + default : + + switch (wan_udp_pkt->wan_udp_command){ + case X25_READ_CONFIGURATION: + wan_udp_pkt->wan_udp_command=X25_HDLC_READ_CONFIG; + break; + } + + do { + memcpy(&mbox->wan_command, &wan_udp_pkt->wan_udp_command, sizeof(TX25Cmd)); + if(mbox->wan_data_len){ + memcpy(&mbox->wan_data, + (char *)wan_udp_pkt->wan_udp_data, + mbox->wan_data_len); + } + err = card->hw_iface.cmd(card->hw, card->mbox_off, mbox); + } while (err && x25_error(card, err, mbox->wan_command, 0) && c_retry--); + + + if ( err == CMD_OK || + (err == 1 && + (mbox->wan_command == 0x06 || + mbox->wan_command == 0x16) ) ){ + + ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_adptr_cmnd_OK; + } else { + ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_adptr_cmnd_timeout; + } + + /* copy the result back to our buffer */ + memcpy(&wan_udp_pkt->wan_udp_command, &mbox->wan_command, sizeof(TX25Cmd)); + + if(mbox->wan_data_len) { + memcpy(&wan_udp_pkt->wan_udp_data, &mbox->wan_data, mbox->wan_data_len); + } + break; + + } //switch + + } + + if (local_dev){ + return 1; + } + + /* Fill UDP TTL */ + + wan_udp_pkt->wan_ip_ttl = card->wandev.ttl; + + len = reply_udp((u8*)&card->u.x.udp_pkt_data, mbox->wan_data_len); + + if(card->u.x.udp_pkt_src == UDP_PKT_FRM_NETWORK) { + + err = x25_send(card, lcn, 0, len, (u8*)&card->u.x.udp_pkt_data); + if (!err) + ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_adptr_send_passed; + else + ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_adptr_send_failed; + + } else { + + /* Allocate socket buffer */ + if((new_skb = dev_alloc_skb(len)) != NULL) { + void *buf; + + /* copy data into new_skb */ + buf = skb_put(new_skb, len); + memcpy(buf, (u8*)&card->u.x.udp_pkt_data, len); + + /* Decapsulate packet and pass it up the protocol + stack */ + new_skb->dev = dev; + + if (chan->common.usedby == API) + new_skb->protocol = htons(X25_PROT); + else + new_skb->protocol = htons(ETH_P_IP); + + new_skb->mac.raw = new_skb->data; + + netif_rx(new_skb); + ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_passed_to_stack; + + } else { + ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_no_socket; + printk(KERN_INFO + "%s: UDP mgmt cmnd, no socket buffers available!\n", + card->devname); + } + } + + atomic_set(&card->u.x.udp_pkt_len,0); + return 1; +} + + +/*============================================================================ + * Reply to UDP Management system. + * Return nothing. + */ + +static int reply_udp( unsigned char *data, unsigned int mbox_len ) +{ + unsigned short len, udp_length, temp, ip_length; + unsigned long ip_temp; + int even_bound = 0; + wan_udp_pkt_t *wan_udp_pkt = (wan_udp_pkt_t *)data; + + /* Set length of packet */ + len = //sizeof(fr_encap_hdr_t)+ + sizeof(struct iphdr)+ + sizeof(struct udphdr)+ + sizeof(wan_mgmt_t)+ + sizeof(wan_cmd_t)+ + mbox_len; + + + /* fill in UDP reply */ + wan_udp_pkt->wan_udp_request_reply = UDPMGMT_REPLY; + + /* fill in UDP length */ + udp_length = sizeof(struct udphdr)+ + sizeof(wan_mgmt_t)+ + sizeof(wan_cmd_t)+ + mbox_len; + + + /* put it on an even boundary */ + if ( udp_length & 0x0001 ) { + udp_length += 1; + len += 1; + even_bound = 1; + } + + temp = (udp_length<<8)|(udp_length>>8); + wan_udp_pkt->wan_udp_len = temp; + + /* swap UDP ports */ + temp = wan_udp_pkt->wan_udp_sport; + wan_udp_pkt->wan_udp_sport = + wan_udp_pkt->wan_udp_dport; + wan_udp_pkt->wan_udp_dport = temp; + + + + /* add UDP pseudo header */ + temp = 0x1100; + *((unsigned short *) + (wan_udp_pkt->wan_udp_data+mbox_len+even_bound)) = temp; + temp = (udp_length<<8)|(udp_length>>8); + *((unsigned short *) + (wan_udp_pkt->wan_udp_data+mbox_len+even_bound+2)) = temp; + + /* calculate UDP checksum */ + wan_udp_pkt->wan_udp_sum = 0; + + wan_udp_pkt->wan_udp_sum = + calc_checksum(&data[UDP_OFFSET/*+sizeof(fr_encap_hdr_t)*/], + udp_length+UDP_OFFSET); + + /* fill in IP length */ + ip_length = udp_length + sizeof(struct iphdr); + temp = (ip_length<<8)|(ip_length>>8); + wan_udp_pkt->wan_ip_len = temp; + + /* swap IP addresses */ + ip_temp = wan_udp_pkt->wan_ip_src; + wan_udp_pkt->wan_ip_src = + wan_udp_pkt->wan_ip_dst; + wan_udp_pkt->wan_ip_dst = ip_temp; + + + /* fill in IP checksum */ + wan_udp_pkt->wan_ip_sum = 0; + wan_udp_pkt->wan_ip_sum = + calc_checksum(&data[0], + sizeof(struct iphdr)); + + return len; +} /* reply_udp */ + + +unsigned short calc_checksum (char *data, int len) +{ + unsigned short temp; + unsigned long sum=0; + int i; + + for( i = 0; i > 16 ) { + sum = (sum & 0xffffUL) + (sum >> 16); + } + + temp = (unsigned short)sum; + temp = ~temp; + + if( temp == 0 ) + temp = 0xffff; + + return temp; +} + +/*============================================================================= + * Initial the ppp_private_area structure. + */ +static void init_x25_channel_struct( x25_channel_t *chan ) +{ + memset(&chan->if_send_stat.if_send_entry,0,sizeof(if_send_stat_t)); + memset(&chan->rx_intr_stat.rx_intr_no_socket,0,sizeof(rx_intr_stat_t)); + memset(&chan->pipe_mgmt_stat.UDP_PIPE_mgmt_kmalloc_err,0,sizeof(pipe_mgmt_stat_t)); +} + +/*============================================================================ + * Initialize Global Statistics + */ +static void init_global_statistics( sdla_t *card ) +{ + memset(&card->statistics.isr_entry,0,sizeof(global_stats_t)); +} + + +/*=============================================================== + * SMP Support + * ==============================================================*/ + +static void S508_S514_lock(sdla_t *card, unsigned long *smp_flags) +{ + spin_lock_irqsave(&card->wandev.lock, *smp_flags); +} +static void S508_S514_unlock(sdla_t *card, unsigned long *smp_flags) +{ + spin_unlock_irqrestore(&card->wandev.lock, *smp_flags); +} + +/*=============================================================== + * x25_timer_routine + * + * A more efficient polling routine. Each half a second + * queue a polling task. We want to do the polling in a + * task not timer, because timer runs in interrupt time. + * + * FIXME Polling should be rethinked. + *==============================================================*/ + +static void x25_timer_routine(unsigned long data) +{ + sdla_t *card = (sdla_t*)data; + netdevice_t *dev; + + DEBUG_TEST("%s: X25 TIMER ROUTINE \n",card->devname); + + ++card->statistics.poll_entry; + + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + if (!dev){ + printk(KERN_INFO "%s: Stopping the X25 Poll Timer: No Dev.\n", + card->devname); + return; + } + + if (test_bit(PERI_CRIT,&card->wandev.critical)){ + printk(KERN_INFO "%s: Stopping the X25 Poll Timer: Shutting down.\n", + card->devname); + return; + } + + if (!test_and_set_bit(POLL_CRIT,&card->wandev.critical)){ + trigger_x25_poll(card); + } + + if ((card->u.x.timer_int_enabled & ~TMR_INT_ENABLED_CMD_EXEC)){ + unsigned long smp_flags; + + spin_lock_irqsave(&card->wandev.lock, smp_flags); + timer_intr (card); + spin_unlock_irqrestore(&card->wandev.lock, smp_flags); + + if ((card->u.x.timer_int_enabled & ~TMR_INT_ENABLED_CMD_EXEC)){ + del_timer(&card->u.x.x25_timer); + card->u.x.x25_timer.expires=jiffies+(HZ/50); + add_timer(&card->u.x.x25_timer); + return; + } + } + + del_timer(&card->u.x.x25_timer); + card->u.x.x25_timer.expires=jiffies+(HZ>>1); + add_timer(&card->u.x.x25_timer); + return; +} + +void disable_comm_shutdown(sdla_t *card) +{ + wan_mbox_t* mbox = &card->wan_mbox; + int err; + + /* Turn of interrutps */ + mbox->wan_data[0] = 0; + mbox->wan_data[1] = card->wandev.irq; //ALEX_TODAY card->hw.irq; + mbox->wan_data[2] = 2; + mbox->wan_data_len = 3; + mbox->wan_command = X25_SET_INTERRUPT_MODE; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mbox); + if (err) + printk(KERN_INFO "INTERRUPT OFF FAIED %x\n",err); + + /* Bring down HDLC */ + mbox->wan_command = X25_HDLC_LINK_CLOSE; + mbox->wan_data_len = 0; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mbox); + if (err) + printk(KERN_INFO "LINK CLOSED FAILED %x\n",err); + + + /* Brind down DTR */ + mbox->wan_data[0] = 0; + mbox->wan_data[2] = 0; + mbox->wan_data[1] = 0x01; + mbox->wan_data_len = 3; + mbox->wan_command = X25_SET_GLOBAL_VARS; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mbox); + if (err) + printk(KERN_INFO "DTR DOWN FAILED %x\n",err); + +} + +static void x25_clear_cmd_update(sdla_t* card, unsigned lcn, wan_mbox_t* mb) +{ + netdevice_t* dev = find_channel(card, lcn); + x25_channel_t* chan = NULL; + x25_call_info_t info; + struct timeval tv; + + if (dev == NULL || dev->priv == NULL) + return; + chan=dev->priv; + do_gettimeofday(&tv); + chan->chan_clear_time = tv.tv_sec; + chan->chan_clear_cause = mb->wan_x25_cause; + chan->chan_clear_diagn = mb->wan_x25_diagn; + + if (mb->wan_data_len){ + parse_call_info(mb->wan_data, &info); + memcpy(chan->cleared_called_addr, info.src, MAX_X25_ADDR_SIZE); + memcpy(chan->cleared_calling_addr, info.dest, MAX_X25_ADDR_SIZE); + memcpy(chan->cleared_facil, info.facil, MAX_X25_FACL_SIZE); + } + return; +} + +#if 0 +/* + ******************************************************************** + * Proc FS function + */ +#define PROC_CFG_FRM "%-15s| %-12s| %-5u| %-9s| %-13s| %-13s|\n" +#define PROC_STAT_FRM "%-15s| %-12s| %-5u| %-14s|\n" +static char x25_config_hdr[] = + "Interface name | Device name | LCN | Src Addr | Accept DAddr | Accept UData |\n"; +static char x25_status_hdr[] = + "Interface name | Device name | LCN | Status |\n"; + +static int x25_get_config_info(void* priv, char* buf, int cnt, int len, int offs, int* stop_cnt) +{ + x25_channel_t* chan = (x25_channel_t*)priv; + sdla_t* card = chan->card; + int size = 0; + + if (chan == NULL) + return cnt; + if ((offs == 0 && cnt == 0) || (offs && offs == *stop_cnt)){ + PROC_ADD_LINE(cnt, (buf, &cnt, len, offs, stop_cnt, &size, "%s", x25_config_hdr)); + } + + PROC_ADD_LINE(cnt, (buf, &cnt, len, offs, stop_cnt, &size, + PROC_CFG_FRM, chan->name, card->devname, chan->ch_idx, + chan->x25_src_addr, chan->accept_dest_addr, chan->accept_usr_data)); + return cnt; +} + +static int x25_get_status_info(void* priv, char* buf, int cnt, int len, int offs, int* stop_cnt) +{ + x25_channel_t* chan = (x25_channel_t*)priv; + sdla_t* card = chan->card; + int size = 0; + + if (chan == NULL) + return cnt; + if ((offs == 0 && cnt == 0) || (offs && offs == *stop_cnt)){ + PROC_ADD_LINE(cnt, (buf, &cnt, len, offs, stop_cnt, &size, "%s", x25_status_hdr)); + } + + PROC_ADD_LINE(cnt, (buf, &cnt, len, offs, stop_cnt, &size, + PROC_STAT_FRM, chan->name, card->devname, + chan->ch_idx, STATE_DECODE(chan->common.state))); + return cnt; +} + +#define PROC_DEV_FR_SS_FRM "%-20s| %-12s|%-20s| %-12s|\n" +#define PROC_DEV_FR_SD_FRM "%-20s| %-12s|%-20s| %-12d|\n" +#define PROC_DEV_FR_DD_FRM "%-20s| %-12d|%-20s| %-12d|\n" +#define PROC_DEV_FR_XD_FRM "%-20s| 0x%-10X|%-20s| %-12d|\n" +#define PROC_DEV_SEPARATE "===================================" +#define PROC_DEV_TITLE " Parameters | Value |" + +#if defined(LINUX_2_4)||defined(LINUX_2_6) +static int x25_get_dev_config_info(char* buf, char** start, off_t offs, int len) +#else +static int x25_get_dev_config_info(char* buf, char** start, off_t offs, int len, int dummy) +#endif +{ + int cnt = 0; + wan_device_t* wandev = (void*)start; + sdla_t* card = NULL; + wan_x25_conf_t* x25_conf = NULL; + int size = 0; + PROC_ADD_DECL(stop_cnt); + + if (wandev == NULL || wandev->private == NULL) + return cnt; + + PROC_ADD_INIT(offs, stop_cnt); + card = (sdla_t*)wandev->private; + x25_conf = &card->u.x.x25_conf; + + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_DEV_SEPARATE PROC_DEV_SEPARATE "\n")); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, "Configuration for %s device\n", wandev->name)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_DEV_SEPARATE PROC_DEV_SEPARATE "\n")); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_DEV_TITLE PROC_DEV_TITLE "\n")); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_DEV_SEPARATE PROC_DEV_SEPARATE "\n")); + + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_DEV_FR_SS_FRM, + "Interface", INT_DECODE(wandev->interface), + "CALL_SETUP_LOG", CFG_DECODE(x25_conf->logging))); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_DEV_FR_SS_FRM, + "Clocking", CLK_DECODE(wandev->clocking), + "OOB_ON_MODEM", CFG_DECODE(x25_conf->oob_on_modem))); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_DEV_FR_DD_FRM, + "BaudRate",wandev->bps, + "T1", x25_conf->t1)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_DEV_FR_DD_FRM, + "MTU", wandev->mtu, + "T2", x25_conf->t2)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_DEV_FR_DD_FRM, + "TTL", wandev->ttl, + "T4", x25_conf->t4)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_DEV_FR_DD_FRM, + "UDP Port", wandev->udp_port, + "N2", x25_conf->n2)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_DEV_FR_SD_FRM, + "Station", X25_STATION_DECODE(wandev->station), + "T10_T20", x25_conf->t10_t20)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_DEV_FR_DD_FRM, + "LowestPVC", x25_conf->lo_pvc, + "T11_T21", x25_conf->t11_t21)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_DEV_FR_DD_FRM, + "HighestPVC", x25_conf->hi_pvc, + "T12_T22", x25_conf->t12_t22)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_DEV_FR_DD_FRM, + "LowestSVC", x25_conf->lo_svc, + "T13_T23", x25_conf->t13_t23)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_DEV_FR_DD_FRM, + "HighestSVC", x25_conf->hi_svc, + "T16_T26", x25_conf->t16_t26)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_DEV_FR_DD_FRM, + "HdlcWindow", x25_conf->hdlc_window, + "T28", x25_conf->t28)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_DEV_FR_DD_FRM, + "PacketWindow", x25_conf->pkt_window, + "R10_R20", x25_conf->r10_r20)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_DEV_FR_DD_FRM, + "CCITTCompat", x25_conf->ccitt_compat, + "R12_R22", x25_conf->r12_r22)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_DEV_FR_XD_FRM, + "X25Config", x25_conf->x25_conf_opt, + "R13_R23", x25_conf->r13_r23)); + + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_DEV_SEPARATE PROC_DEV_SEPARATE "\n")); + + PROC_ADD_RET(cnt, offs, stop_cnt); + +} + +static int x25_set_dev_config(struct file *file, + const char *buffer, + unsigned long count, + void *data) +{ + int cnt = 0; + wan_device_t* wandev = (void*)data; + sdla_t* card = NULL; + + if (wandev == NULL) + return cnt; + + card = (sdla_t*)wandev->private; + + printk(KERN_INFO "%s: New device config (%s)\n", + wandev->name, buffer); + /* Parse string */ + + return count; +} + +/* SNMP + ****************************************************************************** + * x25_snmp_data() + * + * Description: Save snmp request and parameters in private structure, enable + * TIMER interrupt, put current process in sleep. + * Arguments: + * Returns: + ****************************************************************************** + */ +#define X25ADMNINDEX 3 +#define X25ADMNINTERFACEMODE 4 +#define X25ADMNMAXACTIVECIRCUITS 5 +#define X25ADMNPACKETSEQUENCING 6 +#define X25ADMNRESTARTTIMER 7 +#define X25ADMNCALLTIMER 8 +#define X25ADMNRESETTIMER 9 +#define X25ADMNCLEARTIMER 10 +#define X25ADMNWINDOWTIMER 11 +#define X25ADMNDATARXMTTIMER 12 +#define X25ADMNINTERRUPTTIMER 13 +#define X25ADMNREJECTTIMER 14 +#define X25ADMNREGISTRATIONREQUESTTIMER 15 +#define X25ADMNMINIMUMRECALLTIMER 16 +#define X25ADMNRESTARTCOUNT 17 +#define X25ADMNRESETCOUNT 18 +#define X25ADMNCLEARCOUNT 19 +#define X25ADMNDATARXMTCOUNT 20 +#define X25ADMNREJECTCOUNT 21 +#define X25ADMNREGISTRATIONREQUESTCOUNT 22 +#define X25ADMNNUMBERPVCS 23 +#define X25ADMNDEFCALLPARAMID 24 +#define X25ADMNLOCALADDRESS 25 +#define X25ADMNPROTOCOLVERSIONSUPPORTED 26 +#define X25OPERINDEX 29 +#define X25OPERINTERFACEMODE 30 +#define X25OPERMAXACTIVECIRCUITS 31 +#define X25OPERPACKETSEQUENCING 32 +#define X25OPERRESTARTTIMER 33 +#define X25OPERCALLTIMER 34 +#define X25OPERRESETTIMER 35 +#define X25OPERCLEARTIMER 36 +#define X25OPERWINDOWTIMER 37 +#define X25OPERDATARXMTTIMER 38 +#define X25OPERINTERRUPTTIMER 39 +#define X25OPERREJECTTIMER 40 +#define X25OPERREGISTRATIONREQUESTTIMER 41 +#define X25OPERMINIMUMRECALLTIMER 42 +#define X25OPERRESTARTCOUNT 43 +#define X25OPERRESETCOUNT 44 +#define X25OPERCLEARCOUNT 45 +#define X25OPERDATARXMTCOUNT 46 +#define X25OPERREJECTCOUNT 47 +#define X25OPERREGISTRATIONREQUESTCOUNT 48 +#define X25OPERNUMBERPVCS 49 +#define X25OPERDEFCALLPARAMID 50 +#define X25OPERLOCALADDRESS 51 +#define X25OPERDATALINKID 52 +#define X25OPERPROTOCOLVERSIONSUPPORTED 53 +#define X25STATINDEX 56 +#define X25STATINCALLS 57 +#define X25STATINCALLREFUSALS 58 +#define X25STATINPROVIDERINITIATEDCLEARS 59 +#define X25STATINREMOTELYINITIATEDRESETS 60 +#define X25STATINPROVIDERINITIATEDRESETS 61 +#define X25STATINRESTARTS 62 +#define X25STATINDATAPACKETS 63 +#define X25STATINACCUSEDOFPROTOCOLERRORS 64 +#define X25STATININTERRUPTS 65 +#define X25STATOUTCALLATTEMPTS 66 +#define X25STATOUTCALLFAILURES 67 +#define X25STATOUTINTERRUPTS 68 +#define X25STATOUTDATAPACKETS 69 +#define X25STATOUTGOINGCIRCUITS 70 +#define X25STATINCOMINGCIRCUITS 71 +#define X25STATTWOWAYCIRCUITS 72 +#define X25STATRESTARTTIMEOUTS 73 +#define X25STATCALLTIMEOUTS 74 +#define X25STATRESETTIMEOUTS 75 +#define X25STATCLEARTIMEOUTS 76 +#define X25STATDATARXMTTIMEOUTS 77 +#define X25STATINTERRUPTTIMEOUTS 78 +#define X25STATRETRYCOUNTEXCEEDEDS 79 +#define X25STATCLEARCOUNTEXCEEDEDS 80 +#define X25CHANNELINDEX 83 +#define X25CHANNELLIC 84 +#define X25CHANNELHIC 85 +#define X25CHANNELLTC 86 +#define X25CHANNELHTC 87 +#define X25CHANNELLOC 88 +#define X25CHANNELHOC 89 +#define X25CIRCUITINDEX 92 +#define X25CIRCUITCHANNEL 93 +#define X25CIRCUITSTATUS 94 +#define X25CIRCUITESTABLISHTIME 95 +#define X25CIRCUITDIRECTION 96 +#define X25CIRCUITINOCTETS 97 +#define X25CIRCUITINPDUS 98 +#define X25CIRCUITINREMOTELYINITIATEDRESETS 99 +#define X25CIRCUITINPROVIDERINITIATEDRESETS 100 +#define X25CIRCUITININTERRUPTS 101 +#define X25CIRCUITOUTOCTETS 102 +#define X25CIRCUITOUTPDUS 103 +#define X25CIRCUITOUTINTERRUPTS 104 +#define X25CIRCUITDATARETRANSMISSIONTIMEOUTS 105 +#define X25CIRCUITRESETTIMEOUTS 106 +#define X25CIRCUITINTERRUPTTIMEOUTS 107 +#define X25CIRCUITCALLPARAMID 108 +#define X25CIRCUITCALLEDDTEADDRESS 109 +#define X25CIRCUITCALLINGDTEADDRESS 110 +#define X25CIRCUITORIGINALLYCALLEDADDRESS 111 +#define X25CIRCUITDESCR 112 +#define X25CLEAREDCIRCUITENTRIESREQUESTED 113 +#define X25CLEAREDCIRCUITENTRIESGRANTED 114 +#define X25CLEAREDCIRCUITINDEX 117 +#define X25CLEAREDCIRCUITPLEINDEX 118 +#define X25CLEAREDCIRCUITTIMEESTABLISHED 119 +#define X25CLEAREDCIRCUITTIMECLEARED 120 +#define X25CLEAREDCIRCUITCHANNEL 121 +#define X25CLEAREDCIRCUITCLEARINGCAUSE 122 +#define X25CLEAREDCIRCUITDIAGNOSTICCODE 123 +#define X25CLEAREDCIRCUITINPDUS 124 +#define X25CLEAREDCIRCUITOUTPDUS 125 +#define X25CLEAREDCIRCUITCALLEDADDRESS 126 +#define X25CLEAREDCIRCUITCALLINGADDRESS 127 +#define X25CLEAREDCIRCUITCLEARFACILITIES 128 +#define X25CALLPARMINDEX 131 +#define X25CALLPARMSTATUS 132 +#define X25CALLPARMREFCOUNT 133 +#define X25CALLPARMINPACKETSIZE 134 +#define X25CALLPARMOUTPACKETSIZE 135 +#define X25CALLPARMINWINDOWSIZE 136 +#define X25CALLPARMOUTWINDOWSIZE 137 +#define X25CALLPARMACCEPTREVERSECHARGING 138 +#define X25CALLPARMPROPOSEREVERSECHARGING 139 +#define X25CALLPARMFASTSELECT 140 +#define X25CALLPARMINTHRUPUTCLASSIZE 141 +#define X25CALLPARMOUTTHRUPUTCLASSIZE 142 +#define X25CALLPARMCUG 143 +#define X25CALLPARMCUGOA 144 +#define X25CALLPARMBCUG 145 +#define X25CALLPARMNUI 146 +#define X25CALLPARMCHARGINGINFO 147 +#define X25CALLPARMRPOA 148 +#define X25CALLPARMTRNSTDLY 149 +#define X25CALLPARMCALLINGEXT 150 +#define X25CALLPARMCALLEDEXT 151 +#define X25CALLPARMINMINTHUPUTCLS 152 +#define X25CALLPARMOUTMINTHUPUTCLS 153 +#define X25CALLPARMENDTRNSDLY 154 +#define X25CALLPARMPRIORITY 155 +#define X25CALLPARMPROTECTION 156 +#define X25CALLPARMEXPTDATA 157 +#define X25CALLPARMUSERDATA 158 +#define X25CALLPARMCALLINGNETWORKFACILITIES 159 +#define X25CALLPARMCALLEDNETWORKFACILITIES 160 + +static int x25_snmp_data(sdla_t* card, netdevice_t *dev, void* data) +{ + x25_channel_t* chan = NULL; + wanpipe_snmp_t* snmp; + + if (dev == NULL || dev->priv == NULL) + return -EFAULT; + chan = (x25_channel_t*)dev->priv; + /* Update device statistics */ + if (card->wandev.update) { + int rslt = 0; + rslt = card->wandev.update(&card->wandev); + if(rslt) { + return (rslt) ? (-EBUSY) : (-EINVAL); + } + } + + snmp = (wanpipe_snmp_t*)data; + + switch(snmp->snmp_magic){ + /********** X.25 Administration Table *********/ + case X25ADMNINDEX: + break; + + case X25ADMNINTERFACEMODE: + snmp->snmp_val = + (card->wandev.station == WANOPT_DTE) ? SNMP_X25_DTE: + (card->wandev.station == WANOPT_DCE) ? SNMP_X25_DCE:SNMP_X25_DXE; + break; + + case X25ADMNMAXACTIVECIRCUITS: + snmp->snmp_val = card->u.x.num_of_ch; + break; + + case X25ADMNPACKETSEQUENCING: + snmp->snmp_val = SNMP_X25_MODULO8; + break; + + case X25ADMNRESTARTTIMER: + snmp->snmp_val = card->u.x.x25_adm_conf.t10_t20; + break; + + case X25ADMNCALLTIMER: + snmp->snmp_val = card->u.x.x25_adm_conf.t11_t21; + break; + + case X25ADMNRESETTIMER: + snmp->snmp_val = card->u.x.x25_adm_conf.t12_t22; + break; + + case X25ADMNCLEARTIMER: + snmp->snmp_val = card->u.x.x25_adm_conf.t13_t23; + break; + + case X25ADMNWINDOWTIMER: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25ADMNDATARXMTTIMER: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25ADMNINTERRUPTTIMER: + snmp->snmp_val = card->u.x.x25_adm_conf.t16_t26; + break; + + case X25ADMNREJECTTIMER: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25ADMNREGISTRATIONREQUESTTIMER: + snmp->snmp_val = card->u.x.x25_adm_conf.t28; + break; + + case X25ADMNMINIMUMRECALLTIMER: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25ADMNRESTARTCOUNT: + snmp->snmp_val = card->u.x.x25_adm_conf.r10_r20; + break; + + case X25ADMNRESETCOUNT: + snmp->snmp_val = card->u.x.x25_adm_conf.r12_r22; + break; + + case X25ADMNCLEARCOUNT: + snmp->snmp_val = card->u.x.x25_adm_conf.r13_r23; + break; + + case X25ADMNDATARXMTCOUNT: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25ADMNREJECTCOUNT: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25ADMNREGISTRATIONREQUESTCOUNT: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25ADMNNUMBERPVCS: + snmp->snmp_val = card->u.x.x25_adm_conf.hi_pvc; + break; + + case X25ADMNDEFCALLPARAMID: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25ADMNLOCALADDRESS: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25ADMNPROTOCOLVERSIONSUPPORTED: /* FIXME */ + snmp->snmp_val = 0; + break; + + /********** X.25 Operational Table *********/ + case X25OPERINDEX: + break; + + case X25OPERINTERFACEMODE: + snmp->snmp_val = (card->wandev.station == WANOPT_DTE) ? SNMP_X25_DTE: + (card->wandev.station == WANOPT_DCE) ? SNMP_X25_DCE:SNMP_X25_DXE; + break; + + case X25OPERMAXACTIVECIRCUITS: + snmp->snmp_val = card->u.x.num_of_ch; + break; + + case X25OPERPACKETSEQUENCING: + snmp->snmp_val = SNMP_X25_MODULO8; + break; + + case X25OPERRESTARTTIMER: + snmp->snmp_val = card->u.x.x25_conf.t10_t20; + break; + + case X25OPERCALLTIMER: + snmp->snmp_val = card->u.x.x25_conf.t11_t21; + break; + + case X25OPERRESETTIMER: + snmp->snmp_val = card->u.x.x25_conf.t12_t22; + break; + + case X25OPERCLEARTIMER: + snmp->snmp_val = card->u.x.x25_conf.t13_t23; + break; + + case X25OPERWINDOWTIMER: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25OPERDATARXMTTIMER: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25OPERINTERRUPTTIMER: + snmp->snmp_val = card->u.x.x25_conf.t16_t26; + break; + + case X25OPERREJECTTIMER: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25OPERREGISTRATIONREQUESTTIMER: + snmp->snmp_val = card->u.x.x25_conf.t28; + break; + + case X25OPERMINIMUMRECALLTIMER: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25OPERRESTARTCOUNT: + snmp->snmp_val = card->u.x.x25_conf.r10_r20; + break; + + case X25OPERRESETCOUNT: + snmp->snmp_val = card->u.x.x25_conf.r12_r22; + break; + + case X25OPERCLEARCOUNT: + snmp->snmp_val = card->u.x.x25_conf.r13_r23; + break; + + case X25OPERDATARXMTCOUNT: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25OPERREJECTCOUNT: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25OPERREGISTRATIONREQUESTCOUNT: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25OPERNUMBERPVCS: + snmp->snmp_val = card->u.x.x25_conf.hi_pvc; + break; + + case X25OPERDEFCALLPARAMID: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25OPERLOCALADDRESS: /* FIXME */ + strcpy((void*)snmp->snmp_data, "N/A"); + break; + + case X25OPERDATALINKID: /* FIXME */ + strcpy((void*)snmp->snmp_data, "N/A"); + break; + + case X25OPERPROTOCOLVERSIONSUPPORTED: /* FIXME */ + strcpy((void*)snmp->snmp_data, "N/A"); + break; + + + + /********** X.25 Statistics Table *********/ + case X25STATINDEX: + break; + + case X25STATINCALLS: + snmp->snmp_val = X25Stats.rxCallRequest; + break; + + case X25STATINCALLREFUSALS: + snmp->snmp_val = X25Stats.txClearRqst; + break; + + case X25STATINPROVIDERINITIATEDCLEARS: + snmp->snmp_val = (card->wandev.station == WANOPT_DTE) ? + X25Stats.rxClearRqst: + X25Stats.txClearRqst; + break; + + case X25STATINREMOTELYINITIATEDRESETS: + snmp->snmp_val = (card->wandev.station == WANOPT_DTE) ? + X25Stats.txResetRqst: + X25Stats.rxResetRqst; + break; + + case X25STATINPROVIDERINITIATEDRESETS: + snmp->snmp_val = (card->wandev.station == WANOPT_DTE) ? + X25Stats.rxResetRqst: + X25Stats.txResetRqst; + break; + + case X25STATINRESTARTS: + snmp->snmp_val = X25Stats.rxRestartRqst; + break; + + case X25STATINDATAPACKETS: + snmp->snmp_val = X25Stats.rxData; + break; + + case X25STATINACCUSEDOFPROTOCOLERRORS: + snmp->snmp_val = X25Stats.rxClearRqst+X25Stats.rxResetRqst+ + X25Stats.rxRestartRqst+X25Stats.rxDiagnostic; + break; + + case X25STATININTERRUPTS: + snmp->snmp_val = X25Stats.rxInterrupt; + break; + + case X25STATOUTCALLATTEMPTS: + snmp->snmp_val = X25Stats.txCallRequest; + break; + + case X25STATOUTCALLFAILURES: + snmp->snmp_val = X25Stats.rxClearRqst; + break; + + case X25STATOUTINTERRUPTS: + snmp->snmp_val = X25Stats.txInterrupt; + break; + + case X25STATOUTDATAPACKETS: + snmp->snmp_val = X25Stats.txData; + break; + + case X25STATOUTGOINGCIRCUITS: + snmp->snmp_val = X25Stats.txCallRequest-X25Stats.rxClearRqst; + break; + + case X25STATINCOMINGCIRCUITS: + snmp->snmp_val = X25Stats.rxCallRequest-X25Stats.txClearRqst; + break; + + case X25STATTWOWAYCIRCUITS: + snmp->snmp_val = X25Stats.txCallRequest-X25Stats.rxClearRqst; + break; + + case X25STATRESTARTTIMEOUTS: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25STATCALLTIMEOUTS: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25STATRESETTIMEOUTS: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25STATCLEARTIMEOUTS: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25STATDATARXMTTIMEOUTS: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25STATINTERRUPTTIMEOUTS: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25STATRETRYCOUNTEXCEEDEDS: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25STATCLEARCOUNTEXCEEDEDS: /* FIXME */ + snmp->snmp_val = 0; + break; + + /********** X.25 Channel Table *********/ + case X25CHANNELINDEX: + break; + + case X25CHANNELLIC: + snmp->snmp_val = card->u.x.x25_conf.lo_svc; + break; + + case X25CHANNELHIC: + snmp->snmp_val = card->u.x.x25_conf.hi_svc; + break; + + case X25CHANNELLTC: + snmp->snmp_val = card->u.x.x25_conf.lo_svc; + break; + + case X25CHANNELHTC: + snmp->snmp_val = card->u.x.x25_conf.hi_svc; + break; + + case X25CHANNELLOC: + snmp->snmp_val = card->u.x.x25_conf.lo_svc; + break; + + case X25CHANNELHOC: + snmp->snmp_val = card->u.x.x25_conf.hi_svc; + break; + + /********** X.25 Per Circuits Information Table *********/ + case X25CIRCUITINDEX: + break; + + case X25CIRCUITCHANNEL: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25CIRCUITSTATUS: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25CIRCUITESTABLISHTIME: + snmp->snmp_val = chan->chan_establ_time; + break; + + case X25CIRCUITDIRECTION: + snmp->snmp_val = chan->chan_direct; + break; + + case X25CIRCUITINOCTETS: + snmp->snmp_val = chan->ifstats.rx_bytes; + break; + + case X25CIRCUITINPDUS: + snmp->snmp_val = chan->ifstats.rx_packets; + break; + + case X25CIRCUITINREMOTELYINITIATEDRESETS: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25CIRCUITINPROVIDERINITIATEDRESETS: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25CIRCUITININTERRUPTS: + snmp->snmp_val = X25Stats.rxInterrupt; + break; + + case X25CIRCUITOUTOCTETS: + snmp->snmp_val = chan->ifstats.tx_bytes; + break; + + case X25CIRCUITOUTPDUS: + snmp->snmp_val = chan->ifstats.tx_packets; + break; + + case X25CIRCUITOUTINTERRUPTS: + snmp->snmp_val = X25Stats.txInterrupt; + break; + + case X25CIRCUITDATARETRANSMISSIONTIMEOUTS: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25CIRCUITRESETTIMEOUTS: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25CIRCUITINTERRUPTTIMEOUTS: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25CIRCUITCALLPARAMID: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25CIRCUITCALLEDDTEADDRESS: /* FIXME */ + strcpy((void*)snmp->snmp_data, + (chan->chan_direct == SNMP_X25_INCOMING) ? chan->accept_src_addr : "N/A"); + break; + + case X25CIRCUITCALLINGDTEADDRESS: /* FIXME */ + strcpy((void*)snmp->snmp_data, + (chan->chan_direct == SNMP_X25_INCOMING) ? chan->accept_dest_addr : "N/A"); + break; + + case X25CIRCUITORIGINALLYCALLEDADDRESS: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25CIRCUITDESCR: /* FIXME */ + strcpy((void*)snmp->snmp_data, "N/A"); + break; + + + case X25CLEAREDCIRCUITENTRIESREQUESTED: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25CLEAREDCIRCUITENTRIESGRANTED: /* FIXME */ + snmp->snmp_val = 0; + break; + + /********** X.25 The Cleared Circuit Table *********/ + case X25CLEAREDCIRCUITINDEX: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25CLEAREDCIRCUITPLEINDEX: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25CLEAREDCIRCUITTIMEESTABLISHED: + snmp->snmp_val = chan->chan_establ_time; + break; + + case X25CLEAREDCIRCUITTIMECLEARED: + snmp->snmp_val = chan->chan_clear_time; + break; + + case X25CLEAREDCIRCUITCHANNEL: + snmp->snmp_val = chan->ch_idx; + break; + + case X25CLEAREDCIRCUITCLEARINGCAUSE: + snmp->snmp_val = chan->chan_clear_cause; + break; + + case X25CLEAREDCIRCUITDIAGNOSTICCODE: + snmp->snmp_val = chan->chan_clear_diagn; + break; + + case X25CLEAREDCIRCUITINPDUS: + snmp->snmp_val = chan->ifstats.rx_packets; + break; + + case X25CLEAREDCIRCUITOUTPDUS: + snmp->snmp_val = chan->ifstats.tx_packets; + break; + + case X25CLEAREDCIRCUITCALLEDADDRESS: + strcpy((void*)snmp->snmp_data, + (chan->cleared_called_addr[0] != '\0') ? + chan->cleared_called_addr : "N/A"); + break; + + case X25CLEAREDCIRCUITCALLINGADDRESS: + strcpy((void*)snmp->snmp_data, + (chan->cleared_calling_addr[0] != '\0') ? + chan->cleared_calling_addr : "N/A"); + break; + + case X25CLEAREDCIRCUITCLEARFACILITIES: + strcpy((void*)snmp->snmp_data, + (chan->cleared_facil[0] != '\0') ? chan->cleared_facil : "N/A"); + break; + + + + /********** X.25 The Call Parameter Table *********/ + case X25CALLPARMINDEX: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25CALLPARMSTATUS: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25CALLPARMREFCOUNT: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25CALLPARMINPACKETSIZE: + snmp->snmp_val = 0; // default size + break; + + case X25CALLPARMOUTPACKETSIZE: + snmp->snmp_val = 0; // default size + break; + + case X25CALLPARMINWINDOWSIZE: + snmp->snmp_val = (card->u.x.x25_conf.pkt_window != X25_PACKET_WINDOW) ? + card->u.x.x25_conf.pkt_window : 0; + break; + + case X25CALLPARMOUTWINDOWSIZE: + snmp->snmp_val = (card->u.x.x25_conf.pkt_window != X25_PACKET_WINDOW) ? + card->u.x.x25_conf.pkt_window : 0; + break; + + case X25CALLPARMACCEPTREVERSECHARGING: /* FIXME */ + snmp->snmp_val = SNMP_X25_ARC_DEFAULT; + break; + + case X25CALLPARMPROPOSEREVERSECHARGING: /* FIXME */ + snmp->snmp_val = SNMP_X25_PRC_DEFAULT; + break; + + case X25CALLPARMFASTSELECT: /* FIXME */ + snmp->snmp_val = SNMP_X25_FS_DEFAULT; + break; + + case X25CALLPARMINTHRUPUTCLASSIZE: /* FIXME */ + snmp->snmp_val = SNMP_X25_THRUCLASS_TCDEF; + break; + + case X25CALLPARMOUTTHRUPUTCLASSIZE: /* FIXME */ + snmp->snmp_val = SNMP_X25_THRUCLASS_TCDEF; + break; + + case X25CALLPARMCUG: /* FIXME */ + strcpy((void*)snmp->snmp_data, "N/A"); + break; + + case X25CALLPARMCUGOA: /* FIXME */ + strcpy((void*)snmp->snmp_data, "N/A"); + break; + + case X25CALLPARMBCUG: /* FIXME */ + strcpy((void*)snmp->snmp_data, "N/A"); + break; + + case X25CALLPARMNUI: /* FIXME */ + strcpy((void*)snmp->snmp_data, "N/A"); + break; + + case X25CALLPARMCHARGINGINFO: /* FIXME */ + snmp->snmp_val = SNMP_X25_CHARGINGINFO_DEF; + break; + + case X25CALLPARMRPOA: /* FIXME */ + strcpy((void*)snmp->snmp_data, "N/A"); + break; + + case X25CALLPARMTRNSTDLY: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25CALLPARMCALLINGEXT: /* FIXME */ + strcpy((void*)snmp->snmp_data, "N/A"); + break; + + case X25CALLPARMCALLEDEXT: /* FIXME */ + strcpy((void*)snmp->snmp_data, "N/A"); + break; + + case X25CALLPARMINMINTHUPUTCLS: /* FIXME */ + snmp->snmp_val = SNMP_X25_THRUCLASS_TCDEF; + break; + + case X25CALLPARMOUTMINTHUPUTCLS: /* FIXME */ + snmp->snmp_val = SNMP_X25_THRUCLASS_TCDEF; + break; + + case X25CALLPARMENDTRNSDLY: /* FIXME */ + strcpy((void*)snmp->snmp_data, "N/A"); + break; + + case X25CALLPARMPRIORITY: /* FIXME */ + strcpy((void*)snmp->snmp_data, "N/A"); + break; + + case X25CALLPARMPROTECTION: /* FIXME */ + strcpy((void*)snmp->snmp_data, "N/A"); + break; + + case X25CALLPARMEXPTDATA: /* FIXME */ + snmp->snmp_val = SNMP_X25_EXPTDATA_DEFULT; + break; + + case X25CALLPARMUSERDATA: + strcpy((void*)snmp->snmp_data, chan->accept_usr_data); + break; + + case X25CALLPARMCALLINGNETWORKFACILITIES: /* FIXME */ + strcpy((void*)snmp->snmp_data, "N/A"); + break; + + case X25CALLPARMCALLEDNETWORKFACILITIES: /* FIXME */ + strcpy((void*)snmp->snmp_data, "N/A"); + break; + + default: + return -EAFNOSUPPORT; + } + + return 0; + +} + +#define PROC_IF_X25_S_FRM "%-40s %-14s\n" +#define PROC_IF_X25_D_FRM "%-40s %-14d\n" +#define PROC_IF_X25_L_FRM "%-40s %-14ld\n" +#define PROC_IF_SEPARATE "====================================================\n" + +#if defined(LINUX_2_4)||defined(LINUX_2_6) +static int x25_get_if_info(char* buf, char** start, off_t offs, int len) +#else +static int x25_get_if_info(char* buf, char** start, off_t offs, int len, int dummy) +#endif +{ + int cnt = 0; + netdevice_t* dev = (void*)start; + x25_channel_t* chan = (x25_channel_t*)dev->priv; + sdla_t* card = chan->card; + int size = 0; + PROC_ADD_DECL(stop_cnt); + + PROC_ADD_INIT(offs, stop_cnt); + /* Update device statistics (only at the first call) */ + if (!offs && card->wandev.update) { + int rslt = 0; + rslt = card->wandev.update(&card->wandev); + if(rslt) { + switch (rslt) { + case -EAGAIN: + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, + "Device is busy!\n")); + break; + + default: + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, + "Device is not configured!\n")); + break; + } + goto get_if_info_end; + } + } + + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, + "********** X.25 Administration Table *********\n")); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25AdmnInterfaceMode", + (card->wandev.station == WANOPT_DTE) ? SNMP_X25_DTE: + (card->wandev.station == WANOPT_DCE) ? SNMP_X25_DCE:SNMP_X25_DXE)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25AdmnMaxActiveCircuits", card->u.x.num_of_ch)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25AdmnPacketSequencing", SNMP_X25_MODULO8)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25AdmnRestartTimer", card->u.x.x25_adm_conf.t10_t20)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25AdmnCallTimer", card->u.x.x25_adm_conf.t11_t21)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25AdmnResetTimer", card->u.x.x25_adm_conf.t12_t22)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25AdmnClearTimer", card->u.x.x25_adm_conf.t13_t23)); + // FIXME + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25AdmnWindowTimer", 0)); + // FIXME + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25AdmnDataRxmtTimer", 0)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25AdmnInterruptTimer", card->u.x.x25_adm_conf.t16_t26)); + // FIXME + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25AdmnRejectTimer", 0)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25AdmnRegistrationRequestTimer", card->u.x.x25_adm_conf.t28)); + // FIXME + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25AdmnMinimumRecallTimer", 0)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25AdmnRestartCount", card->u.x.x25_adm_conf.r10_r20)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25AdmnResetCount", card->u.x.x25_adm_conf.r12_r22)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25AdmnClearCount", card->u.x.x25_adm_conf.r13_r23)); + // FIXME + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25AdmnDataRxmtCount", 0)); + // FIXME + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25AdmnRejectCount", 0)); + // FIXME + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25AdmnRegistrationRequestCount", 0)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25AdmnNumberPVCs", card->u.x.x25_adm_conf.hi_pvc)); + // FIXME + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25AdmnDefCallParamId", 0)); + // FIXME + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_S_FRM, + "x25AdmnLocalAddress", "N/A")); + // FIXME + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_S_FRM, + "x25AdmnProtocolVersionSupported", "N/A")); + + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt,&size, + "********** X.25 Operational Table *********\n")); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25OperInterfaceMode", + (card->wandev.station == WANOPT_DTE) ? SNMP_X25_DTE: + (card->wandev.station == WANOPT_DCE) ? SNMP_X25_DCE:SNMP_X25_DXE)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25OperMaxActiveCircuits", card->u.x.num_of_ch)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25OperPacketSequencing", SNMP_X25_MODULO8)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25OperRestartTimer", card->u.x.x25_conf.t10_t20)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25OperCallTimer", card->u.x.x25_conf.t11_t21)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25OperResetTimer", card->u.x.x25_conf.t12_t22)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25OperClearTimer", card->u.x.x25_conf.t13_t23)); + // FIXME + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25OperWindowTimer", 0)); + // FIXME + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25OperDataRxmtTimer", 0)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25OperInterruptTimer", card->u.x.x25_conf.t16_t26)); + // FIXME + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25OperRejectTimer", 0)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25OperRegistrationRequestTimer", card->u.x.x25_conf.t28)); + // FIXME + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25OperMinimumRecallTimer", 0)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25OperRestartCount", card->u.x.x25_conf.r10_r20)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25OperResetCount", card->u.x.x25_conf.r12_r22)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25OperClearCount", card->u.x.x25_conf.r13_r23)); + // FIXME + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25OperDataRxmtCount", 0)); + // FIXME + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25OperRejectCount", 0)); + // FIXME + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25OperRegistrationRequestCount", 0)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25OperNumberPVCs", card->u.x.x25_conf.hi_pvc)); + // FIXME + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25OperDefCallParamId", 0)); + // FIXME + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_S_FRM, + "x25OperLocalAddress", "N/A")); + // FIXME + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_S_FRM, + "x25OperDataLinkId", "N/A")); + // FIXME + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_S_FRM, + "x25OperProtocolVersionSupported", "N/A")); + + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, + "********** X.25 Statistics Table *********\n")); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25StatInCalls", X25Stats.rxCallRequest)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25StatInCallRefusals", X25Stats.txClearRqst)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25StatInProviderInitiatedClears", + (card->wandev.station == WANOPT_DTE) ? + X25Stats.rxClearRqst: + X25Stats.txClearRqst)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25StatInRemotelyInitiatedResets", + (card->wandev.station == WANOPT_DTE) ? + X25Stats.txResetRqst: + X25Stats.rxResetRqst)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25StatInProviderInitiatedResets", + (card->wandev.station == WANOPT_DTE) ? + X25Stats.rxResetRqst: + X25Stats.txResetRqst)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25StatInRestarts", X25Stats.rxRestartRqst)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25StatInDataPackets", X25Stats.rxData)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25StatInAccusedOfProtocolErrors", + X25Stats.rxClearRqst+X25Stats.rxResetRqst+ + X25Stats.rxRestartRqst+X25Stats.rxDiagnostic)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25StatInInterrupts", X25Stats.rxInterrupt)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25StatOutCallAttempts", X25Stats.txCallRequest)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25StatOutCallFailures", X25Stats.rxClearRqst)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25StatOutInterrupts", X25Stats.txInterrupt)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25StatOutDataPackets", X25Stats.txData)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25StatOutgoingCircuits", + X25Stats.txCallRequest-X25Stats.rxClearRqst)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25StatIncomingCircuits", + X25Stats.rxCallRequest-X25Stats.txClearRqst)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25StatTwowayCircuits", + X25Stats.txCallRequest-X25Stats.rxClearRqst)); + // FIXME + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25StatRestartTimeouts", 0)); + // FIXME + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25StatCallTimeouts", 0)); + // FIXME + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25StatResetTimeouts", 0)); + // FIXME + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25StatClearTimeouts", 0)); + // FIXME + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25StatDataRxmtTimeouts", 0)); + // FIXME + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25StatInterruptTimeouts", 0)); + // FIXME + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25StatRetryCountExceededs", 0)); + // FIXME + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25StatClearCountExceededs", 0)); + + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, + "********** X.25 Channel Table *********\n")); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25ChannelLIC", card->u.x.x25_conf.lo_svc)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25ChannelHIC", card->u.x.x25_conf.hi_svc)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25ChannelLTC", card->u.x.x25_conf.lo_svc)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25ChannelHTC", card->u.x.x25_conf.hi_svc)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25ChannelLOC", card->u.x.x25_conf.lo_svc)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25ChannelHOC", card->u.x.x25_conf.hi_svc)); + + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, + "********** X.25 Per Circuits Information Table *********\n")); + // FIXME + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25CircuitChannel", 0)); + // FIXME + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25CircuitStatus", 0)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_L_FRM, + "x25CircuitEstablishTime", chan->chan_establ_time)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25CircuitDirection", chan->chan_direct)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_L_FRM, + "x25CircuitInOctets", chan->ifstats.rx_bytes)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_L_FRM, + "x25CircuitInPdus", chan->ifstats.rx_packets)); + // FIXME + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25CircuitInRemotelyInitiatedResets", 0)); + // FIXME + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25CircuitInProviderInitiatedResets", 0)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25CircuitInInterrupts", X25Stats.rxInterrupt)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_L_FRM, + "x25CircuitOutOctets", chan->ifstats.tx_bytes)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_L_FRM, + "x25CircuitOutPdus", chan->ifstats.tx_packets)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25CircuitOutInterrupts", X25Stats.txInterrupt)); + // FIXME + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25CircuitDataRetransmissionTimeouts", 0)); + // FIXME + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25CircuitResetTimeouts", 0)); + // FIXME + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25CircuitInterruptTimeouts", 0)); + // FIXME + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25CircuitCallParamId", 0)); + // FIXME + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_S_FRM, + "x25CircuitCalledDteAddress", + (chan->chan_direct == SNMP_X25_INCOMING) ? chan->accept_src_addr : "N/A")); + // FIXME + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_S_FRM, + "x25CircuitCallingDteAddress", + (chan->chan_direct == SNMP_X25_INCOMING) ? chan->accept_dest_addr : "N/A")); + // FIXME + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25CircuitOriginallyCalledAddress", 0)); + // FIXME + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_S_FRM, + "x25CircuitDescr", "N/A")); + + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, + "********** X.25 The Cleared Circuit Table *********\n")); + // FIXME + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25ClearedCircuitEntriesRequested", 0)); + // FIXME + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25ClearedCircuitEntriesGranted", 0)); + // FIXME + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25ClearedCircuitIndex", 0)); + // FIXME + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25ClearedCircuitPleIndex", 0)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_L_FRM, + "x25ClearedCircuitTimeEstablished", chan->chan_establ_time)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_L_FRM, + "x25ClearedCircuitTimeCleared", chan->chan_clear_time)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25ClearedCircuitChannel", chan->ch_idx)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25ClearedCircuitClearingCause", chan->chan_clear_cause)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25ClearedCircuitDiagnosticCode", chan->chan_clear_diagn)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_L_FRM, + "x25ClearedCircuitInPdus", chan->ifstats.rx_packets)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_L_FRM, + "x25ClearedCircuitOutPdus", chan->ifstats.tx_packets)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_S_FRM, + "x25ClearedCircuitCalledAddress", + (chan->cleared_called_addr[0] != '\0') ? + chan->cleared_called_addr : "N/A")); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_S_FRM, + "x25ClearedCircuitCallingAddress", + (chan->cleared_calling_addr[0] != '\0') ? + chan->cleared_calling_addr : "N/A")); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_S_FRM, + "x25ClearedCircuitClearFacilities", + (chan->cleared_facil[0] != '\0') ? chan->cleared_facil : "N/A")); + + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, + "********** X.25 The Call Parameter Table *********\n")); + // FIXME + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25CallParmIndex", 0)); + // FIXME + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25CallParmStatus", 0)); + // FIXME + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25CallParmRefCount", 0)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25CallParmInPacketSize", 0)); // default size + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25CallParmOutPacketSize", 0)); // default size + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25CallParmInWindowSize", + (card->u.x.x25_conf.pkt_window != X25_PACKET_WINDOW) ? + card->u.x.x25_conf.pkt_window : 0)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25CallParmOutWindowSize", + (card->u.x.x25_conf.pkt_window != X25_PACKET_WINDOW) ? + card->u.x.x25_conf.pkt_window : 0)); + // FIXME + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25CallParmAcceptReverseCharging", SNMP_X25_ARC_DEFAULT)); + // FIXME + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25CallParmProposeReverseCharging", SNMP_X25_PRC_DEFAULT)); + // FIXME + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25CallParmFastSelect", SNMP_X25_FS_DEFAULT)); + // FIXME + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25CallParmInThruPutClasSize", SNMP_X25_THRUCLASS_TCDEF)); + // FIXME + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25CallParmOutThruPutClasSize", SNMP_X25_THRUCLASS_TCDEF)); + // FIXME + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_S_FRM, + "x25CallParmCug", "N/A")); + // FIXME + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_S_FRM, + "x25CallParmCugoa", "N/A")); + // FIXME + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_S_FRM, + "x25CallParmBcug", "N/A")); + // FIXME + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_S_FRM, + "x25CallParmNui", "N/A")); + // FIXME + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25CallParmChargingInfo", SNMP_X25_CHARGINGINFO_DEF)); + // FIXME + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_S_FRM, + "x25CallParmRpoa", "N/A")); + // FIXME + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25CallParmTrnstDly", 0)); + // FIXME + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_S_FRM, + "x25CallParmCallingExt", "N/A")); + // FIXME + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_S_FRM, + "x25CallParmCalledExt", "N/A")); + // FIXME + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25CallParmInMinThuPutCls", SNMP_X25_THRUCLASS_TCDEF)); + // FIXME + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25CallParmOutMinThuPutCls", SNMP_X25_THRUCLASS_TCDEF)); + // FIXME + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_S_FRM, + "x25CallParmEndTrnsDly", "N/A")); + // FIXME + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_S_FRM, + "x25CallParmPriority", "N/A")); + // FIXME + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_S_FRM, + "x25CallParmProtection", "N/A")); + // FIXME + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_D_FRM, + "x25CallParmExptData", SNMP_X25_EXPTDATA_DEFULT)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_S_FRM, + "x25CallParmUserData", chan->accept_usr_data)); + // FIXME + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_S_FRM, + "x25CallParmCallingNetworkFacilities", "N/A")); + // FIXME + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_IF_X25_S_FRM, + "x25CallParmCalledNetworkFacilities", "N/A")); + +get_if_info_end: + PROC_ADD_RET(cnt, offs, stop_cnt); + +} + + +static int x25_set_if_info(struct file *file, + const char *buffer, + unsigned long count, + void *data) +{ + netdevice_t* dev = (void*)data; + x25_channel_t* chan = NULL; + sdla_t* card = NULL; + + if (dev == NULL || dev->priv == NULL) + return count; + chan = (x25_channel_t*)dev->priv; + if (chan->card == NULL) + return count; + card = chan->card; + + printk(KERN_INFO "%s: New interface config (%s)\n", + chan->name, buffer); + /* Parse string */ + + return count; +} + +#endif + +static int test_chan_command_busy(sdla_t *card,x25_channel_t *chan) +{ + if (atomic_read(&chan->common.command)){ + DEBUG_EVENT("%s: Chan Command busy %x\n", + card->devname, + atomic_read(&chan->common.command)); + return -EBUSY; + } + + return 0; +} + + +static int wait_for_cmd_rc(sdla_t *card, x25_channel_t *chan) +{ + chan->cmd_timeout=jiffies; + + while((jiffies-chan->cmd_timeout) < HZ){ + if (!atomic_read(&chan->common.command)){ + return atomic_read(&chan->cmd_rc); + } + schedule(); + } + DEBUG_EVENT("%s: !!!!!!!! CRITICAL ERROR !!!!!!! Command %x Timed out !\n", + card->devname,atomic_read(&chan->common.command)); + + atomic_set(&chan->common.command,0); + return -EFAULT; +} + +static int delay_cmd(sdla_t *card, x25_channel_t *chan, int delay) +{ + unsigned long timeout=jiffies; + + while((jiffies-timeout) < delay){ + schedule(); + } + return 0; +} + +/****** End *****************************************************************/ diff -Nur linux.org/drivers/net/wan/sdla_adsl.c linux-2.6.17/drivers/net/wan/sdla_adsl.c --- linux.org/drivers/net/wan/sdla_adsl.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/drivers/net/wan/sdla_adsl.c 2006-08-30 10:07:16.000000000 +0000 @@ -0,0 +1,2020 @@ +/***************************************************************************** +* sdla_adsl.c WANPIPE(tm) Multiprotocol WAN Link Driver. ADSL module. +* +* Authors: Nenad Corbic +* Alex Feldman +# include +# include +# include +# include +# include +# include +# include +# include +#elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) +# include +# include +# include +# include +# include +# include +# include +#else +# error "Unsupported Operating System!" +#endif + +/* +************************************************************************** +** D E F I N E S ** +************************************************************************** +*/ +#define MAX_TRACE_QUEUE 100 +#define MAX_TRACE_BUFFER (MAX_LGTH_UDP_MGNT_PKT - \ + sizeof(iphdr_t) - \ + sizeof(udphdr_t) - \ + sizeof(wan_mgmt_t) - \ + sizeof(wan_trace_info_t) - \ + sizeof(wan_cmd_t)) + +/* +************************************************************************** +** M A C R O S ** +************************************************************************** +*/ +#define MAX(a,b) (((a)>(b))?(a):(b)) + + +#if defined(__LINUX__) +# define ETHER_IOCTL(ifp, cmd, data) -EOPNOTSUPP +#endif + +#if defined(__LINUX__) +# define LIST_FIRST_MCLIST(dev) dev->mc_list +# define LIST_NEXT_MCLIST(mclist) mclist->next +#elif defined(__FreeBSD__) +# define LIST_FIRST_MCLIST(dev) LIST_FIRST(&dev->if_multiaddrs) +# define LIST_NEXT_MCLIST(mclist) mclist->ifma_link.le_next +#elif defined(__OpenBSD__) +# define LIST_FIRST_MCLIST(dev) NULL +# define LIST_NEXT_MCLIST(mclist) NULL +#elif defined(__NetBSD__) +# define LIST_FIRST_MCLIST(dev) NULL +# define LIST_NEXT_MCLIST(mclist) NULL +#else +# error "Undefined LIST_FIRST_MCLIST/LIST_NEXT_MCLIST macros!" +#endif + +enum { + TX_BUSY_SET +}; + +/* +************************************************************************** +** G L O B A L V A R I A B L E S ** +************************************************************************** +*/ +#define WAN_ADSL_VCIVPI_MAX_LEN 100 +wan_adsl_vcivpi_t adsl_vcivpi_list[WAN_ADSL_VCIVPI_MAX_LEN]; +int adsl_vcivpi_num = 0; + +/* +************************************************************************** +** F U N C T I O N P R O T O T Y P E S ** +************************************************************************** +*/ + +#if defined(__LINUX__) +static int adsl_open(netdevice_t*); +static int adsl_close(netdevice_t*); +static int adsl_output(struct sk_buff *skb, struct net_device *dev); +static int adsl_ioctl(netdevice_t* ifp, struct ifreq *ifr, int command); +static void adsl_tx_timeout (netdevice_t *dev); +static void adsl_multicast(netdevice_t* dev); +static struct net_device_stats* adsl_stats(netdevice_t* dev); +static int wanpipe_attach_sppp(sdla_t *card, netdevice_t *dev, wanif_conf_t *conf); +#else +static void adsl_watchdog (netdevice_t*); +static void adsl_tx (netdevice_t *); +static void adsl_sppp_tx (netdevice_t *); +static int adsl_output (struct ifnet *,struct mbuf *,struct sockaddr *,struct rtentry *); +static int adsl_ioctl(struct ifnet*, u_long, caddr_t); +# if defined(__FreeBSD__) +static void adsl_init(void* priv); +# elif defined(__NetBSD__) +static int adsl_init(netdevice_t* dev); +# endif +#endif + +static void wpa_isr (sdla_t*); +static void disable_comm(sdla_t* card); +static int process_udp_mgmt_pkt(sdla_t*, netdevice_t*, adsl_private_area_t*, int); +static int new_if (wan_device_t*, netdevice_t*, wanif_conf_t*); +static int del_if (wan_device_t*, netdevice_t*); +static int process_udp_cmd(netdevice_t*,wan_udp_hdr_t*); +void process_bh(void *); +int adsl_trace_queue_len(void *trace_ptr); + + + +/* +************************************************************************** +** P U B L I C P R O T O T Y P E S ** +************************************************************************** +*/ + +/*============================================================================ + * DSL Hardware initialization routine. + * + * This routine is called by the main WANPIPE module during setup. At this + * point adapter is completely initialized and firmware is running. + * + * Return: 0 o.k. + * < 0 failure. + */ +int wp_adsl_init (sdla_t* card, wandev_conf_t* conf) +{ + DEBUG_EVENT("%s: Initializing S518 ADSL card...\n", + card->devname); + + card->isr = &wpa_isr; + card->poll = NULL; + card->exec = NULL; + card->wandev.update = NULL; /*&update; */ + card->wandev.new_if = &new_if; + card->wandev.del_if = &del_if; + card->wandev.udp_port = conf->udp_port; + card->wandev.new_if_cnt = 0; + + card->wandev.ttl = conf->ttl; + card->wandev.interface = conf->interface; + + conf->u.adsl.tty_minor = conf->tty_minor; + + switch (conf->u.adsl.EncapMode){ + case RFC_MODE_ROUTED_IP_LLC: + case RFC_MODE_ROUTED_IP_VC: + if (conf->mtu > 9188){ + conf->mtu = 9188; + } + break; + + default: + if (conf->mtu > 1500){ + conf->mtu = 1500; + } + break; + } + conf->u.adsl.mtu = conf->mtu; + card->wandev.mtu = conf->mtu; + + card->u.adsl.adapter = adsl_create(&conf->u.adsl, + card, + card->devname); + if (card->u.adsl.adapter == NULL){ + return -EINVAL; + } + + card->u.adsl.EncapMode = conf->u.adsl.EncapMode; + card->wandev.station = conf->u.adsl.EncapMode; + +#if 0 + if (adsl_wan_interface_type(card->u.adsl.adapter)){ + int err=adsl_wan_init(card->u.adsl.adapter); + if (err){ + adsl_disable_comm(card->u.adsl.adapter); + return err; + } +#if !defined(LINUX_2_6) + MOD_INC_USE_COUNT; +#endif + } +#endif + +#if defined(__LINUX__) + card->disable_comm = &disable_comm; +#else + if (adsl_wan_interface_type(card->u.adsl.adapter)){ + card->disable_comm = &disable_comm; + } +#endif + + card->wandev.state = WAN_CONNECTING; + return 0; +} + +/*============================================================================ + * Handle transmit timeout event from netif watchdog + */ +#if defined(__NetBSD__) || defined (__FreeBSD__) || defined (__OpenBSD__) +static void adsl_watchdog(netdevice_t* dev) +{ + adsl_private_area_t* dsl = NULL; + sdla_t* card = NULL; + + WAN_ASSERT1(dev == NULL); + dsl = wan_netif_priv(dev); + WAN_ASSERT1(dsl == NULL); + card = dsl->common.card; + DEBUG_TIMER("%s: Watchdog function called\n", + wan_netif_name(dev)); + + process_udp_mgmt_pkt(card, dev, dsl,0); + +} +#endif + + +/*============================================================================ + * Create new logical channel. + * This routine is called by the router when ROUTER_IFNEW IOCTL is being + * handled. + * o parse media- and hardware-specific configuration + * o make sure that a new channel can be created + * o allocate resources, if necessary + * o prepare network device structure for registaration. + * + * Return: 0 o.k. + * < 0 Failure (channel will not be created) + */ +static int new_if (wan_device_t* wandev, netdevice_t* ifp, wanif_conf_t* conf) +{ + sdla_t* card = wandev->private; + adsl_private_area_t* adsl = NULL; + + if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) { + DEBUG_EVENT("%s: Invalid interface name!\n", + card->devname); + return -EINVAL; + } + + if (adsl_wan_interface_type(card->u.adsl.adapter)){ + return -EINVAL; + } + + /* (FreeBSD/OpenBSD only) + * Verify that SPPP is enabled in the kernel. + */ + if (!WAN_SPPP_ENABLED){ + if (card->u.adsl.EncapMode == RFC_MODE_PPP_VC || + card->u.adsl.EncapMode == RFC_MODE_PPP_LLC){ + DEBUG_EVENT("%s: Please verify that SPPP is enabled in your kernel!\n", + card->devname); + return -EINVAL; + } + } + + /* allocate and initialize private data */ + adsl = wan_malloc(sizeof(adsl_private_area_t)); + if (adsl == NULL){ + DEBUG_EVENT("%s: Failed allocating private data...\n", + card->devname); + return -ENOMEM; + } + + memset(adsl,0,sizeof(adsl_private_area_t)); + + DEBUG_EVENT("%s: Configuring Interface: %s\n", + card->devname, conf->name); + + /* prepare network device data space for registration */ + memcpy(adsl->if_name, conf->name, strlen(conf->name)); + if (wan_netif_init(ifp, adsl->if_name)){ + DEBUG_EVENT("%s: Failed to initialize network interface!\n", + conf->name); + wan_free(adsl); + return -ENOMEM; + } +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) + ifp->if_softc = adsl; + ifp->if_output = adsl_output; + ifp->if_start = adsl_tx; + ifp->if_watchdog = adsl_watchdog; + ifp->if_ioctl = adsl_ioctl; +# if defined(__NetBSD__) || defined (__FreeBSD__) + ifp->if_init = adsl_init; +# endif + ifp->if_snd.ifq_len = 0; +#elif defined(__LINUX__) + + INIT_WORK((&adsl->common.wanpipe_task),process_bh,ifp); + + ifp->priv = adsl; + ifp->irq = card->wandev.irq; + card->hw_iface.getcfg(card->hw, SDLA_MEMBASE, &ifp->mem_start); + card->hw_iface.getcfg(card->hw, SDLA_MEMEND, &ifp->mem_end); + + ifp->open = &adsl_open; + ifp->stop = &adsl_close; + ifp->hard_start_xmit = &adsl_output; + ifp->get_stats = &adsl_stats; + ifp->set_multicast_list = &adsl_multicast; + ifp->tx_timeout = &adsl_tx_timeout; + ifp->watchdog_timeo = (1*HZ); + + ifp->do_ioctl = adsl_ioctl; +#endif + + adsl->common.card = card; + adsl->pAdapter = adsl_new_if(card->u.adsl.adapter, adsl->macAddr, ifp); + + if (adsl->pAdapter == NULL){ + DEBUG_EVENT("%s: Failed ADSL interface initialization\n", + card->devname); + del_if(wandev, ifp); + return -EINVAL; + } + + + if(strcmp(conf->usedby, "STACK") == 0) { + adsl->common.usedby = STACK; + DEBUG_EVENT( "%s:%s: Running in Stack mode.\n", + card->devname,adsl->if_name); + + card->u.adsl.EncapMode=RFC_MODE_STACK_VC; + + }else{ + adsl->common.usedby = WANPIPE; + DEBUG_EVENT( "%s:%s: Running in Wanpipe mode.\n", + card->devname,adsl->if_name); + } + + /*TASK_INIT(&adsl->tq_atm_task, 0, &adsl_atm_tasklet, adsl->pAdapter); + */ + switch (card->u.adsl.EncapMode){ + + case RFC_MODE_BRIDGED_ETH_LLC: + case RFC_MODE_BRIDGED_ETH_VC: + DEBUG_EVENT("%s: Configuring %s as Ethernet\n", + card->devname, wan_netif_name(ifp)); +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) + ifp->if_flags |= (IFF_DRV_RUNNING|IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST); + /* if_type,if_addrlen, if_hdrlen, if_mtu inialize + * in ether_ifattach + */ +# if !defined(__NetBSD__) + bcopy(adsl->macAddr, + WAN_IFP2ENADDR(ifp)/*(WAN_IFP2AC(ifp))->ac_enaddr*/, + 6); +# endif + bcopy(adsl->macAddr, wandev->macAddr, ETHER_ADDR_LEN); +#else + ether_setup(ifp); + memcpy(ifp->dev_addr, adsl->macAddr, 6); +#endif + break; + + case RFC_MODE_ROUTED_IP_LLC: + case RFC_MODE_ROUTED_IP_VC: + DEBUG_EVENT("%s: Configuring %s as Raw IP\n", + card->devname, wan_netif_name(ifp)); + + /* Drop down to STACK_VC: Standard if config */ + + case RFC_MODE_STACK_VC: + +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) + ifp->if_mtu = card->wandev.mtu; /* ETHERMTU */ + ifp->if_type = IFT_OTHER; + ifp->if_flags |= (IFF_POINTOPOINT|IFF_DRV_RUNNING); + /*ifp->if_flags |= IFF_NOARP;*/ + ifp->if_hdrlen = 0; +#else + ifp->type = ARPHRD_PPP; + ifp->flags |= IFF_POINTOPOINT; + ifp->flags |= IFF_NOARP; + ifp->mtu = card->wandev.mtu; + ifp->hard_header_len=0; /* ETH_HLEN;*/ + ifp->addr_len=0; /* ETH_ALEN;*/ + ifp->tx_queue_len = 100; +#endif + break; + + case RFC_MODE_PPP_VC: + case RFC_MODE_PPP_LLC: + DEBUG_EVENT("%s: Attaching SPPP protocol \n", card->devname); +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) + WAN_SPPP_ATTACH(ifp); + ifp->if_start = adsl_sppp_tx; +#else + ifp->type = ARPHRD_PPP; + ifp->flags |= IFF_POINTOPOINT; + ifp->flags |= IFF_NOARP; + ifp->mtu = card->wandev.mtu; + ifp->hard_header_len=0; + ifp->addr_len=0; + { + int err=wanpipe_attach_sppp(card,ifp,conf); + if (err != 0){ + del_if(wandev,ifp); + return err; + } + } + ifp->tx_queue_len = 100; + + ifp->open = &adsl_open; + ifp->stop = &adsl_close; + ifp->hard_start_xmit = &adsl_output; + ifp->get_stats = &adsl_stats; + ifp->set_multicast_list = &adsl_multicast; + ifp->tx_timeout = &adsl_tx_timeout; + ifp->watchdog_timeo = (1*HZ); + ifp->do_ioctl = adsl_ioctl; +#endif + break; + + default: + DEBUG_EVENT("%s: Error invalid EncapMode %i\n", + card->devname,card->u.adsl.EncapMode); + del_if(wandev,ifp); + return -EINVAL; + } + + + wan_getcurrenttime(&adsl->router_start_time, NULL); + return 0; +} + +static int del_if (wan_device_t* wandev, netdevice_t* ifp) +{ + sdla_t* card = wandev->private; + adsl_private_area_t* adsl = wan_netif_priv(ifp); + + WAN_ASSERT(adsl == NULL); + + DEBUG_EVENT("%s: Deleting Interface %s\n", + card->devname, wan_netif_name(ifp)); + + if (adsl->pAdapter != NULL){ + adsl_del_if(adsl->pAdapter); + + /* Disable communication */ + DEBUG_EVENT("%s: Disabling ADSL communications...\n", + card->devname); + adsl_disable_comm(adsl->pAdapter); + } + card->u.adsl.adapter = NULL; + adsl->pAdapter = NULL; + + /* Initialize interrupt handler pointer */ + card->isr = NULL; + + /* Initialize network interface */ + if (card->u.adsl.EncapMode == RFC_MODE_PPP_VC || + card->u.adsl.EncapMode == RFC_MODE_PPP_LLC){ + + DEBUG_EVENT("%s: Detaching SPPP protocol \n", card->devname); + +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) + WAN_SPPP_FLUSH(ifp); + WAN_SPPP_DETACH(ifp); +#else + if (adsl->common.prot_ptr){ + wp_sppp_detach(ifp); + + ifp->do_ioctl = NULL; + ifp->hard_header = NULL; + ifp->rebuild_header = NULL; + + kfree(adsl->common.prot_ptr); + adsl->common.prot_ptr= NULL; + } +#endif + } + +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) +#if 0 + ifp->if_output = NULL; + ifp->if_start = NULL; + ifp->if_ioctl = NULL; + ifp->if_watchdog= NULL; +# if defined(__NetBSD__) || defined(__FreeBSD__) + ifp->if_init = NULL; +# endif + ifp->if_flags &= ~(IFF_UP | IFF_DRV_RUNNING | IFF_DRV_OACTIVE); + if (ifp->if_softc){ + wan_free(ifp->if_softc); + ifp->if_softc = NULL; + } +#endif +#else + ifp->irq = 0; + ifp->mem_start = 0; + ifp->mem_end = 0; + /* Private structure will be free later */ + wan_netif_del(ifp); +#endif + + return 0; +} + +/*+F************************************************************************* + * Function: + * adsl_init + * + * Description: + *-F*************************************************************************/ +#if defined(__FreeBSD__) +static void adsl_init(void* priv){ return; } +#elif defined(__NetBSD__) +static int adsl_init(netdevice_t* dev){return 0; } +#endif + +/*+F************************************************************************* + * Function: + * adsl_vcivpi_update + * + * Description: + *-F*************************************************************************/ +void adsl_vcivpi_update(sdla_t* card, wandev_conf_t* conf) +{ + wan_adsl_conf_t* adsl_conf = &conf->u.adsl; + int x = 0; + + for(x = 0; x < adsl_vcivpi_num; x++){ + adsl_conf->vcivpi_list[x].vci = adsl_vcivpi_list[x].vci; + adsl_conf->vcivpi_list[x].vpi = adsl_vcivpi_list[x].vpi; + } + + adsl_conf->vcivpi_num = adsl_vcivpi_num; +} + +/*+F************************************************************************* + * Function: + * disable_comm + * + * Description: + * Called by the LAN subsystem when the ethernet interface is + * configured make ready to accept data (ifconfig up). + *-F*************************************************************************/ +static void disable_comm(sdla_t* card) +{ + char wan; + + if (!card->u.adsl.adapter) + return; + + wan = adsl_wan_interface_type(card->u.adsl.adapter); + + adsl_disable_comm(card->u.adsl.adapter); + card->u.adsl.adapter = NULL; + + if (wan){ +#if !defined(LINUX_2_6) + MOD_DEC_USE_COUNT; +#endif + } +} + +#if defined(__LINUX__) +/*+F************************************************************************* + * Function: + * adsl_tx_timeout + * + * Description: + * Handle transmit timeout event from netif watchdog + *-F*************************************************************************/ +static void adsl_tx_timeout (netdevice_t *dev) +{ + adsl_private_area_t* adsl = wan_netif_priv(dev); + sdla_t* card = adsl->common.card; + + /* If our device stays busy for at least 5 seconds then we will + * kick start the device by making dev->tbusy = 0. We expect + * that our device never stays busy more than 5 seconds. So this + * is only used as a last resort. + */ +#if defined(__LINUX__) + dev->trans_start = SYSTEM_TICKS; +#endif + card->wandev.stats.collisions++; + + adsl_timeout(card->u.adsl.adapter); + + WAN_NETIF_WAKE_QUEUE(dev); +} + +/*+F************************************************************************* + * Function: + * adsl_open + * + * Description: + * Called by the LAN subsystem when the ethernet interface is configured + * make ready to accept data (ifconfig up). + *-F*************************************************************************/ +static int adsl_open(netdevice_t* ifp) +{ + int status = 0; +#if defined (__LINUX__) + adsl_private_area_t* adsl = wan_netif_priv(ifp); +#endif + +#if defined (__LINUX__) + if (adsl->common.prot_ptr){ + if (wp_sppp_open(ifp)){ + return -EIO; + } + } +#endif + + /* Start Tx queuing */ + WAN_NETDEVICE_START(ifp); + WAN_NETIF_START_QUEUE(ifp); + + if (adsl->common.usedby == STACK){ + /* Force the lip to connect state + * since there is no state change + * mechanism for an interface + * FIXME: This is temporary */ + wanpipe_lip_connect(adsl,0); + } + +#if !defined(LINUX_2_6) + MOD_INC_USE_COUNT; +#endif + return status; +} + +/*+F************************************************************************* + * Function: + * adsl_close + * + * Description: + * Called by the LAN subsystem when the ethernet interface is disabled + * (ifconfig down). + *-F*************************************************************************/ +int adsl_close(netdevice_t* ifp) +{ + int status = 0; +#if defined (__LINUX__) + adsl_private_area_t* adsl = wan_netif_priv(ifp); +#endif + +#if defined (__LINUX__) + if (adsl->common.prot_ptr){ + if (wp_sppp_close(ifp)){ + return -EIO; + } + } +#endif + + /* Stop Tx queuing */ + WAN_NETIF_STOP_QUEUE(ifp); + WAN_NETDEVICE_STOP(ifp); +#if !defined(LINUX_2_6) + MOD_DEC_USE_COUNT; +#endif + return status; +} +#endif + +/*+F************************************************************************* + * Function: + * wpa_isr + * + * Description: + *-F*************************************************************************/ +static void wpa_isr (sdla_t* card) +{ + if (!card->u.adsl.adapter){ + DEBUG_CFG("wpa_isr: No adapter ptr!\n"); + return; + } + /*WAN_ASSERT1(card->u.adsl.adapter == NULL);*/ + adsl_isr((void*)card->u.adsl.adapter); +} + +/*+F************************************************************************* + * Function: + * adsl_lan_rx + * + * Description: + * A new LAN receive packet is available. Create a SKB for the data, and + * give it to the operating system. + *-F*************************************************************************/ + +void +adsl_lan_rx( + void* dev_id, + void* pHeader, + unsigned long headerSize, + unsigned char* rx_data, + int rx_len + ) +{ + netdevice_t* dev = (netdevice_t*)dev_id; + sdla_t* card = NULL; + adsl_private_area_t* adsl = (adsl_private_area_t*)wan_netif_priv(dev); + netskb_t* rx_skb = NULL; + u_int32_t len; + unsigned char hdr[2] = { 0xFF, 0x03 }; +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) + struct ether_header* eh; +#endif +#if defined(__NetBSD__) || defined(__OpenBSD__) || (defined(__FreeBSD__) && __FreeBSD_version < 501000) +#ifndef __LINUX__ + wan_smp_flag_t s; +#endif +#endif + + WAN_ASSERT1(dev == NULL); + WAN_ASSERT1(adsl == NULL); + card = (sdla_t*)adsl->common.card; + DEBUG_RX("(RX INTR) pHeader, (%p)\n", pHeader); + DEBUG_RX("(RX INTR) headerSize, %ld\n", headerSize); + DEBUG_RX("(RX INTR) rx_len, %d\n", rx_len); + + len = headerSize + rx_len; + if (len == 0) return; + + rx_skb = wan_skb_alloc(len+4); + if (rx_skb == NULL){ + DEBUG_EVENT("%s: Failed allocate memory for RX packet!\n", + wan_netif_name(dev)); + return; + } + wan_skb_reserve(rx_skb, 2); + wan_skb_set_dev(rx_skb, dev); + +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) + eh = (struct ether_header*)wan_skb_data(rx_skb); +#endif + if (card->u.adsl.EncapMode == RFC_MODE_PPP_VC || + card->u.adsl.EncapMode == RFC_MODE_PPP_LLC || + card->u.adsl.EncapMode == RFC_MODE_STACK_VC){ + if (rx_data[0] != hdr[0] || rx_data[1] != hdr[1]){ + wan_skb_copyback(rx_skb, + wan_skb_len(rx_skb), + 2, + (caddr_t)hdr); + } + } + + if (pHeader && headerSize){ + wan_skb_copyback(rx_skb, + wan_skb_len(rx_skb), + headerSize, + (caddr_t)pHeader); + } + + wan_skb_copyback(rx_skb, wan_skb_len(rx_skb), len, (caddr_t)rx_data); + +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) +# if defined(__FreeBSD__) && (__FreeBSD_version < 500000) + wan_bpf_report(dev, rx_skb, 0); +# elif defined(__NetBSD__) || defined(__OpenBSD__) + wan_bpf_report(dev, rx_skb, 0); +# endif + + card->wandev.stats.rx_packets ++; + card->wandev.stats.rx_bytes += wan_skb_len(rx_skb); + + switch(card->u.adsl.EncapMode){ + + case RFC_MODE_STACK_VC: + if (wanpipe_lip_rx(adsl,rx_skb) != 0){ + card->wandev.stats.rx_packets--; + card->wandev.stats.rx_bytes -= wan_skb_len(rx_skb); + wan_skb_free(rx_skb); + } + break; + + case RFC_MODE_PPP_VC: + case RFC_MODE_PPP_LLC: + WAN_SPPP_INPUT(dev, rx_skb); + break; + case RFC_MODE_ROUTED_IP_LLC: + case RFC_MODE_ROUTED_IP_VC: +#if (__FreeBSD_version >= 501000) + wan_bpf_report(dev, rx_skb, 0); + netisr_queue(NETISR_IP, rx_skb); +#else + wan_spin_lock_irq(NULL, &s); + schednetisr(NETISR_IP); + if (IF_QFULL(&ipintrq)){ + DEBUG_RX("%s: IP queue is full, drop packet!\n", + card->devname); + /* oh, no - IP queue is full - well - we'll + ** try again later + */ + card->wandev.stats.rx_packets--; + card->wandev.stats.rx_bytes -= wan_skb_len(rx_skb); + + IF_DROP(&ipintrq); + wan_skb_free(rx_skb); + wan_spin_unlock_irq(NULL, &s); + break; + } + + /* ok enqueue the packet */ + IF_ENQUEUE(&ipintrq, rx_skb); + wan_spin_unlock_irq(NULL, &s); +#endif + break; + case RFC_MODE_BRIDGED_ETH_LLC: + case RFC_MODE_BRIDGED_ETH_VC: +# if defined(__NetBSD__) || defined(__FreeBSD__) && (__FreeBSD_version > 500000) + dev->if_input(dev, rx_skb); +# else + wan_skb_pull(rx_skb, sizeof(struct ether_header)); + ether_input(dev, eh, rx_skb); +# endif + break; + } + +#else /* LINUX */ + + card->wandev.stats.rx_packets ++; + card->wandev.stats.rx_bytes += wan_skb_len(rx_skb); + + switch (card->u.adsl.EncapMode){ + + case RFC_MODE_STACK_VC: + if (wanpipe_lip_rx(adsl,rx_skb) != 0){ + card->wandev.stats.rx_packets--; + card->wandev.stats.rx_bytes -= wan_skb_len(rx_skb); + wan_skb_free(rx_skb); + } + break; + + case RFC_MODE_BRIDGED_ETH_LLC: + case RFC_MODE_BRIDGED_ETH_VC: + rx_skb->protocol = eth_type_trans(rx_skb, rx_skb->dev); + netif_rx(rx_skb); + break; + + case RFC_MODE_ROUTED_IP_LLC: + case RFC_MODE_ROUTED_IP_VC: + rx_skb->protocol = htons(ETH_P_IP); + rx_skb->mac.raw = rx_skb->data; + netif_rx(rx_skb); + break; + + case RFC_MODE_PPP_VC: + case RFC_MODE_PPP_LLC: + rx_skb->protocol = htons(ETH_P_WAN_PPP); + rx_skb->dev = dev; + rx_skb->mac.raw = rx_skb->data; + wp_sppp_input(rx_skb->dev,rx_skb); + break; + } + +#endif + + + adsl_rx_complete(adsl->pAdapter); +} + +/*+F************************************************************************* + * Function: + * adsl_output + * + * Description: + * Handle a LAN interface buffer (SKB) transmit request. Allocate an NDIS + * buffer, copy the data into the NDIS packet, and give it to the RFC layer. + *-F*************************************************************************/ +#if defined(__LINUX__) +int adsl_output(netskb_t* skb, netdevice_t* dev) +#else +static int +adsl_output(netdevice_t* dev, netskb_t* skb, struct sockaddr* dst, struct rtentry* rt0) +#endif +{ + sdla_t* card = NULL; + adsl_private_area_t* adsl = wan_netif_priv(dev); + int status = 0; +#if defined(__LINUX__) + unsigned long smp_flags; +#endif +#if defined(ALTQ) + WAN_PKTATTR_DECL(pktattr); +#endif + + + if (!skb){ + WAN_NETIF_START_QUEUE(dev); + return 0; + } + + if (!adsl){ + DEBUG_EVENT("%s: Error: TxLan: No private adapter !\n", + wan_netif_name(dev)); +#if defined(__LINUX__) + wan_skb_free(skb); +#endif + WAN_NETIF_START_QUEUE(dev); + return 0; + } + card = (sdla_t*)adsl->common.card; + + switch (card->u.adsl.EncapMode){ + + case RFC_MODE_PPP_VC: + case RFC_MODE_PPP_LLC: + case RFC_MODE_STACK_VC: + + if (wan_skb_len(skb) <= 2){ + DEBUG_EVENT("%s: Error: TxLan: PPP pkt len <= 2!\n", + wan_netif_name(dev)); + wan_skb_print(skb); + wan_skb_free(skb); + WAN_NETIF_START_QUEUE(dev); + card->wandev.stats.tx_errors++; + return 0; + } + wan_skb_pull(skb,2); + break; + } + + if (adsl_can_tx(adsl->pAdapter)){ + wan_skb_free(skb); + WAN_NETIF_START_QUEUE(dev); + card->wandev.stats.tx_carrier_errors++; +#if defined(__LINUX__) + dev->trans_start = SYSTEM_TICKS; + return 0; +#else + return -EINVAL; +#endif + } + + DEBUG_TX("%s: TxLan %d bytes...\n", + card->devname, wan_skb_len(skb)); + + +#if 0 + DBG_ASSERT(skb->len < GSI_LAN_NDIS_BUFFER_SIZE); + + { + int r; + printk(KERN_INFO "TX RAW : %i: ",skb->len); + //memcpy(skb->data,tmp_frame,sizeof(tmp_frame)); + for (r=0;rlen;r++){ + printk("%02X ",skb->data[r]); + } + printk("\n"); + } +#endif + +#if defined(__LINUX__) + dev->trans_start = SYSTEM_TICKS; + status = adsl_send(adsl->pAdapter, skb, 0); + wan_spin_lock_irq(&card->wandev.lock,&smp_flags); + if (status == 1){ + WAN_NETIF_STOP_QUEUE(dev); + wan_set_bit(TX_BUSY_SET,&card->wandev.critical); + status = 1; + }else{ + if (status == 2){ + card->wandev.stats.rx_dropped++; + } + wan_skb_free(skb); + WAN_NETIF_START_QUEUE(dev); + status = 0; + } + wan_spin_unlock_irq(&card->wandev.lock,&smp_flags); +#else + if (dst->sa_family != AF_INET){ + DEBUG_EVENT("%s: Protocol family is not supported!\n", + card->devname); + wan_skb_free(skb); + return -EAFNOSUPPORT; + } + + if (card->wandev.state != WAN_CONNECTED){ + DEBUG_TX("%s: Device is not connected!\n", card->devname); + wan_skb_free(skb); + return -EINVAL; + } + + switch (card->u.adsl.EncapMode){ + case RFC_MODE_ROUTED_IP_LLC: + case RFC_MODE_ROUTED_IP_VC: + /* classify the packet before prepanding link-headers */ + WAN_IFQ_CLASSIFY(&dev->if_snd, skb, dst->sa_family, &pktattr); + WAN_IFQ_ENQUEUE(&dev->if_snd, skb, &pktattr, status); + if (status){ + DEBUG_TX("%s: Send queue is full!\n", + card->devname); + wan_skb_free(skb); + break; + } + + if ((dev->if_flags & IFF_DRV_OACTIVE) == 0){ + adsl_tx(dev); + } + + break; + default: +# if defined(__NetBSD__) + status = dev->if_output(dev, skb, dst, rt0); +# else + status = ether_output(dev, skb, dst, rt0); +# endif + break; + } +#endif + return status; +} + +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) +/*+F************************************************************************* + * Function: + * adsl_sppp_tx + * + * Description: + * Handle a LAN interface buffer (SKB) transmit request. Allocate an NDIS + * buffer, copy the data into the NDIS packet, and give it to the RFC layer. + *-F*************************************************************************/ +void adsl_sppp_tx (netdevice_t *ifp) +{ + netskb_t* tx_mbuf = NULL; + adsl_private_area_t* adsl = wan_netif_priv(ifp); + + WAN_ASSERT1(ifp == NULL); + WAN_ASSERT1(adsl == NULL); + if (adsl_can_tx(adsl->pAdapter)){ + return; + } + + while((tx_mbuf = WAN_SPPP_DEQUEUE(ifp)) != NULL){ +#if 0 + if (wan_skb_check(tx_mbuf)){ +#endif + if (wan_skb2buffer((void**)&tx_mbuf)){ + DEBUG_EVENT("%s: Failed to correct mbuf list!\n", + wan_netif_name(ifp)); + wan_skb_free(tx_mbuf); + continue; + } +#if 0 + } +#endif + DEBUG_TX("%s: TxLan %d bytes...\n", + wan_netif_name(ifp), + wan_skb_len(tx_mbuf)); + wan_bpf_report(ifp, tx_mbuf, 0); + wan_skb_pull(tx_mbuf, 2); + if (adsl_send(adsl->pAdapter, tx_mbuf, 0)){ + DEBUG_TX("%s: TX failed to send %d bytes!\n", + wan_netif_name(ifp), + wan_skb_len(tx_mbuf)); + ifp->if_iqdrops++; + } + + if (tx_mbuf){ + wan_skb_free(tx_mbuf); + } + } + + return; +} + +/*+F************************************************************************* + * Function: + * adsl_tx + * + * Description: + * Handle a LAN interface buffer (SKB) transmit request. Allocate an NDIS + * buffer, copy the data into the NDIS packet, and give it to the RFC layer. + *-F*************************************************************************/ +void adsl_tx (netdevice_t *ifp) +{ + netskb_t* tx_mbuf = NULL; + adsl_private_area_t* adsl = wan_netif_priv(ifp); +#if 0 + sdla_t* card = NULL; +#endif + + WAN_ASSERT1(ifp == NULL); + WAN_ASSERT1(adsl == NULL); + WAN_ASSERT1(adsl->common.card == NULL); + +#if defined(NETGRAPH) +#if 0 + card = adsl->card; + while(!WAN_IFQ_IS_EMPTY(&card->xmitq_hipri)){ + WAN_IFQ_POLL(&card->xmitq_hipri, tx_mbuf); + if (tx_mbuf == NULL) break; + DEBUG_TX("%s: TxLan %d bytes...\n", + wan_netif_name(ifp), wan_skb_len(tx_mbuf)); + if (adsl_send(adsl->pAdapter, tx_mbuf, 0)){ + DEBUG_TX("%s: TX failed to send %d bytes!\n", + wan_netif_name(ifp), wan_skb_len(tx_mbuf)); + } + + WAN_IFQ_DEQUEUE(&card->xmitq_hipri, tx_mbuf); + if (tx_mbuf){ + wan_skb_free(tx_mbuf); + } + } +#endif +#endif + while(!WAN_IFQ_IS_EMPTY(&ifp->if_snd)){ + + WAN_IFQ_DEQUEUE(&ifp->if_snd, tx_mbuf); + if (tx_mbuf == NULL) break; + +#if 0 + if (wan_skb_check(tx_mbuf)){ +#endif + if (wan_skb2buffer((void**)&tx_mbuf)){ + DEBUG_EVENT("%s: Failed to correct mbuf list!\n", + wan_netif_name(ifp)); + wan_skb_free(tx_mbuf); + continue; + } +#if 0 + } +#endif + + DEBUG_TX("%s: TxLan %d bytes...\n", + wan_netif_name(ifp), + wan_skb_len(tx_mbuf)); + if (adsl_send(adsl->pAdapter, tx_mbuf, 0)){ + DEBUG_TX("%s: TX failed to send %d bytes!\n", + wan_netif_name(ifp), + wan_skb_len(tx_mbuf)); + ifp->if_iqdrops++; + } + + wan_bpf_report(ifp, tx_mbuf, 0); + + if (tx_mbuf){ + wan_skb_free(tx_mbuf); + } + } + return; +} +#endif + +/*+F************************************************************************* + * Function: + * aadsl_tx_complete + * + * Description: + *-F*************************************************************************/ +void adsl_tx_complete(void* dev_id, int length, int txStatus) +{ + netdevice_t* ifp = (netdevice_t*)dev_id; + adsl_private_area_t* adsl; + sdla_t* card = NULL; + + WAN_ASSERT1(ifp == NULL); + + adsl = wan_netif_priv(ifp); + WAN_ASSERT1(adsl == NULL); + + card = (sdla_t*)adsl->common.card; + WAN_ASSERT1(card == NULL); + + if (txStatus == 0){ + DEBUG_TX("%s: TxLan tx successful.\n", + wan_netif_name(ifp)); +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) + ifp->if_opackets++; + ifp->if_obytes += length; +#endif + card->wandev.stats.tx_packets ++; + card->wandev.stats.tx_bytes += length; + }else{ + DEBUG_TX("%s: TxLan tx failure.\n", + wan_netif_name(ifp)); +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) + ifp->if_oerrors++; +#endif + } + +#if defined(__LINUX__) + ifp->trans_start = SYSTEM_TICKS; +#endif + + if (WAN_NETIF_QUEUE_STOPPED(ifp) || + wan_test_bit(TX_BUSY_SET,&card->wandev.critical)){ + + wan_clear_bit(TX_BUSY_SET,&card->wandev.critical); + DEBUG_TX("%s: adsl_tx_complete, waking dev %s\n", + card->devname, wan_netif_name(ifp)); + WAN_NETIF_WAKE_QUEUE(ifp); + + if (adsl->common.usedby == STACK){ + wanpipe_lip_kick(adsl,0); + } + } + return ; +} + +#if defined(__LINUX__) +/*+F************************************************************************* + * Function: + * adsl_multicast + * + * Description: + * Handle the LAN subsystem multicast, broadcast, and promiscous updates. + * These values can be modified by using the ifconfig command or other + * applications like network sniffers. + *-F*************************************************************************/ +static void adsl_multicast(netdevice_t* dev) +{ + adsl_private_area_t* adsl = wan_netif_priv(dev); + short flags = wan_netif_flags(dev); + int mcount = wan_netif_mcount(dev); + char* mcaddrs = NULL; + + WAN_ASSERT1(adsl == NULL); + + DEBUG_TX("%s: IF Flags: %s%s%s%s!\n", + adsl->if_name, + (flags & IFF_BROADCAST) ? "Broadcast " : "", + (flags & IFF_PROMISC) ? "Promiscous " : "", + (flags & IFF_MULTICAST) ? "Multicast " : "", + (flags & IFF_ALLMULTI) ? "All-Multicast" : ""); + + DEBUG_TX("%s: HwAddr: %02x:%02x:%02x:%02x:%02x:%02x\n", + adsl->if_name, + adsl->macAddr[0], adsl->macAddr[1], + adsl->macAddr[2], adsl->macAddr[3], + adsl->macAddr[4], adsl->macAddr[5]); + + if ((flags & IFF_MULTICAST) && mcount != 0){ +#if !defined(__OpenBSD__) +# if defined(__FreeBSD__) + struct ifmultiaddr* mclist = NULL; +# else + struct dev_mc_list* mclist = NULL; +# endif + int x = 0; + + mcaddrs = wan_malloc(mcount * 6); + for (mclist = LIST_FIRST_MCLIST(dev); + mclist != NULL; + x++, mclist = LIST_NEXT_MCLIST(mclist)){ +# if defined(__FreeBSD__) + memcpy(&(mcaddrs[x * 6]), (void*)mclist->ifma_addr, 6); +# else + memcpy(&(mcaddrs[x * 6]), mclist->dmi_addr, 6); +# endif + } +#endif + } + + /*adsl_lan_multicast(adsl->pAdapter, flags, mcaddrs, mcount); + */ + + if (mcaddrs){ + wan_free(mcaddrs); + } + return; +} + + +/*+F************************************************************************* + * Function: + * GpLanStats + * + * Description: + * Return the current LAN device statistics. + * + * Note: For 2.6 kernels we are not allowed to return NULL + *-F*************************************************************************/ +static struct net_device_stats gstats; +static struct net_device_stats* adsl_stats(netdevice_t* dev) +{ + sdla_t* card = NULL; + adsl_private_area_t* adsl = wan_netif_priv(dev); + + if (adsl == NULL){ + return &gstats; + } + + card = (sdla_t*)adsl->common.card; + + if (card == NULL){ + return &gstats; + } + + return &card->wandev.stats; +} +#endif + +/*+F************************************************************************* + * Function: + * adsl_tracing_enabled + * + * Description: + * + * + *-F*************************************************************************/ +int adsl_tracing_enabled(void *trace_ptr) +{ + adsl_trace_info_t *trace_info = (adsl_trace_info_t*)trace_ptr; + + WAN_ASSERT(trace_info == NULL); + if (wan_test_bit(0,&trace_info->tracing_enabled)){ + + if ((SYSTEM_TICKS - trace_info->trace_timeout) > MAX_TRACE_TIMEOUT){ + DEBUG_EVENT("wanpipe: Disabling trace, timeout!\n"); + wan_clear_bit(0,&trace_info->tracing_enabled); + wan_clear_bit(1,&trace_info->tracing_enabled); + return -EINVAL; + } + + if (adsl_trace_queue_len(trace_info) < trace_info->max_trace_queue){ + if (wan_test_bit(1,&trace_info->tracing_enabled)){ + return 1; + }else if (wan_test_bit(2,&trace_info->tracing_enabled)){ + return 2; + }else{ + return 0; + } + } + + DEBUG_UDP("wanpipe: Too many packet in trace queue %d (max=%d)!\n", + adsl_trace_queue_len(trace_info), + trace_info->max_trace_queue); + return -ENOBUFS; + } + return -EINVAL; +} + +void* adsl_trace_info_alloc(void) +{ + return wan_malloc(sizeof(adsl_trace_info_t)); +} + +void adsl_trace_info_init(void *trace_ptr) +{ + adsl_trace_info_t* trace = (adsl_trace_info_t *)trace_ptr; + wan_skb_queue_t* trace_queue = NULL; + + trace_queue = &trace->trace_queue; + WAN_IFQ_INIT(trace_queue, MAX_TRACE_QUEUE); + trace->trace_timeout = SYSTEM_TICKS; + trace->tracing_enabled = 0; + trace->max_trace_queue = MAX_TRACE_QUEUE; +} + +int adsl_trace_purge (void *trace_ptr) +{ + adsl_trace_info_t* trace = (adsl_trace_info_t *)trace_ptr; + wan_skb_queue_t* trace_queue = NULL; + + WAN_ASSERT(trace == NULL); + trace_queue = &trace->trace_queue; + WAN_IFQ_PURGE(trace_queue); + return 0; +} + +int adsl_trace_enqueue(void *trace_ptr, void *skb_ptr) +{ + adsl_trace_info_t* trace = (adsl_trace_info_t *)trace_ptr; + wan_skb_queue_t* trace_queue = NULL; + netskb_t* skb = (netskb_t*)skb_ptr; + int err = 0; + + WAN_ASSERT(trace == NULL); + trace_queue = &trace->trace_queue; + WAN_IFQ_ENQUEUE(trace_queue, skb, NULL, err); + return err; +} + +int adsl_trace_queue_len(void *trace_ptr) +{ + adsl_trace_info_t* trace = (adsl_trace_info_t *)trace_ptr; + wan_skb_queue_t* trace_queue = NULL; + + WAN_ASSERT(trace == NULL); + trace_queue = &trace->trace_queue; + return WAN_IFQ_LEN(trace_queue); +} + +/*+F************************************************************************* + * Function: + * adsl_ioctl + * + * Description: + * + * + *-F*************************************************************************/ +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) +static int adsl_ioctl(netdevice_t* ifp, u_long command, caddr_t data) +#else +static int adsl_ioctl(netdevice_t* ifp, struct ifreq *ifr, int command) +#endif +{ +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) + struct ifreq* ifr = (struct ifreq*)data; + struct ifmediareq* ifmr = (struct ifmediareq*)data; + struct ifaddr* ifa = (struct ifaddr *)data; + # if defined(__FreeBSD__) + struct ifstat* ifs = (struct ifstat *)data; +# endif +#endif + adsl_private_area_t* adsl = wan_netif_priv(ifp); + sdla_t* card = (sdla_t*)adsl->common.card; + wan_udp_pkt_t* wan_udp_pkt = NULL; + int error = 0; + +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) + wan_smp_flag_t s; + wan_spin_lock_irq(NULL, &s); +#endif + + switch (command){ + + case SIOC_WANPIPE_PIPEMON: + DEBUG_IOCTL("%s - ioctl(WANPIPE_PIPEMON) called.\n", card->devname); + if (wan_atomic_read(&adsl->udp_pkt_len) != 0){ + error = -EBUSY; + goto adsl_ioctl_done; + } + + wan_atomic_set(&adsl->udp_pkt_len,sizeof(wan_udp_hdr_t)); + + /* For performance reasons test the critical + * here before spin lock */ + if (wan_test_bit(0,&card->in_isr)){ + wan_atomic_set(&adsl->udp_pkt_len,0); + error = -EBUSY; + goto adsl_ioctl_done; + } + + wan_udp_pkt=(wan_udp_pkt_t*)&adsl->udp_pkt_data[0]; + if (WAN_COPY_FROM_USER(&wan_udp_pkt->wan_udp_hdr,ifr->ifr_data,sizeof(wan_udp_hdr_t))){ + DEBUG_EVENT("%s: Error: Failed to copy memory from USER space!\n", + card->devname); + wan_atomic_set(&adsl->udp_pkt_len,0); + error = -EFAULT; + goto adsl_ioctl_done; + } + + error = process_udp_cmd(ifp, &wan_udp_pkt->wan_udp_hdr); + + /* This area will still be critical to other + * PIPEMON commands due to udp_pkt_len + * thus we can release the irq */ + + if (wan_atomic_read(&adsl->udp_pkt_len) > sizeof(wan_udp_pkt_t)){ + DEBUG_EVENT("%s: Error: Pipemon buf too big on the way up! %i\n", + card->devname,wan_atomic_read(&adsl->udp_pkt_len)); + wan_atomic_set(&adsl->udp_pkt_len,0); + error = -EINVAL; + goto adsl_ioctl_done; + } + + if (WAN_COPY_TO_USER(ifr->ifr_data,&wan_udp_pkt->wan_udp_hdr,sizeof(wan_udp_hdr_t))){ + DEBUG_EVENT("%s: Error: Failed to copy memory to USER space!\n", + card->devname); + wan_atomic_set(&adsl->udp_pkt_len,0); + error = -EFAULT; + goto adsl_ioctl_done; + } + + wan_atomic_set(&adsl->udp_pkt_len,0); + break; + +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) + case SIOCGIFMEDIA: + switch (card->u.adsl.EncapMode){ + case RFC_MODE_BRIDGED_ETH_LLC: + case RFC_MODE_BRIDGED_ETH_VC: + ifmr->ifm_current = IFM_ETHER; + break; + default: + error = -EOPNOTSUPP; + goto adsl_ioctl_done; + } + ifmr->ifm_active = ifmr->ifm_current; + ifmr->ifm_mask = 0; + ifmr->ifm_status = 0; + ifmr->ifm_count = 1; + break; + +# if defined(__FreeBSD__) + case SIOCGIFSTATUS: + sprintf(ifs->ascii + strlen(ifs->ascii), + "\tstatus: %s\n", wanpipe_get_state_string(card)); + break; +# endif + case SIOCSIFMTU: + ifp->if_mtu = ifr->ifr_mtu; + break; + + case SIOCSIFADDR: + case SIOCGIFADDR: + if (card->u.adsl.EncapMode == RFC_MODE_BRIDGED_ETH_LLC || + card->u.adsl.EncapMode == RFC_MODE_BRIDGED_ETH_VC){ + error = ETHER_IOCTL(ifp, command, data); + break; + } else if (card->u.adsl.EncapMode == RFC_MODE_ROUTED_IP_LLC || + card->u.adsl.EncapMode == RFC_MODE_ROUTED_IP_VC){ + if (ifa->ifa_addr->sa_family == AF_INET){ + break; + } + } + /* For all other modes fall through */ +#endif + + default: + if (card->u.adsl.EncapMode == RFC_MODE_PPP_VC || + card->u.adsl.EncapMode == RFC_MODE_PPP_LLC){ +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) + error = WAN_SPPP_IOCTL(ifp, command, data); +#else + error = wp_sppp_do_ioctl(ifp,ifr,command); +#endif + }else if (card->u.adsl.EncapMode == RFC_MODE_BRIDGED_ETH_LLC || + card->u.adsl.EncapMode == RFC_MODE_BRIDGED_ETH_VC){ +#if defined(__LINUX__) + error = ETHER_IOCTL(ifp, command, data); +#else + error = -EOPNOTSUPP; +#endif + }else{ + error = EINVAL; + } + break; /* NEW */ + } +adsl_ioctl_done: +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) + wan_spin_unlock_irq(NULL, &s); +#endif + /* done */ + return error; +} + +#if defined(__LINUX__) +/* FIXME update for BSD */ +void process_bh(void* dev_ptr) +{ + netdevice_t *dev = dev_ptr; + adsl_private_area_t* adsl = wan_netif_priv(dev); + sdla_t* card = adsl->common.card; + + process_udp_mgmt_pkt(card, dev, adsl,0); +} +#endif + +static int process_udp_mgmt_pkt(sdla_t* card, netdevice_t* dev, + adsl_private_area_t* adsl, int local_dev) +{ + wan_udp_pkt_t* wan_udp_pkt = NULL; + netskb_t* new_skb = NULL; + int error = 0; + int len = 0; + + wan_udp_pkt = (wan_udp_pkt_t*)adsl->udp_pkt_data; + + error = process_udp_cmd(dev, &wan_udp_pkt->wan_udp_hdr); + + wan_udp_pkt->wan_ip_ttl = card->wandev.ttl; + + if (local_dev){ + return 0; + } + + len = wan_reply_udp(card, adsl->udp_pkt_data, wan_udp_pkt->wan_udp_data_len); + + if (card->u.adsl.EncapMode == RFC_MODE_BRIDGED_ETH_LLC || + card->u.adsl.EncapMode == RFC_MODE_BRIDGED_ETH_VC){ + len += sizeof(ethhdr_t); + } + + new_skb = wan_skb_alloc(len); + if (new_skb != NULL){ + + wan_skb_set_dev(new_skb, dev); + if (card->u.adsl.EncapMode == RFC_MODE_BRIDGED_ETH_LLC || + card->u.adsl.EncapMode == RFC_MODE_BRIDGED_ETH_VC){ + unsigned short ether_type = 0x0008; + + if (adsl->udp_pkt_src == UDP_PKT_FRM_NETWORK){ + wan_skb_copyback(new_skb, + wan_skb_len(new_skb), + ETHER_ADDR_LEN, + &adsl->macAddr[0]); + wan_skb_copyback(new_skb, + wan_skb_len(new_skb), + ETHER_ADDR_LEN, + &adsl->remote_eth_addr[0]); + }else{ + wan_skb_copyback(new_skb, + wan_skb_len(new_skb), + ETHER_ADDR_LEN, + &adsl->remote_eth_addr[0]); + wan_skb_copyback(new_skb, + wan_skb_len(new_skb), + ETHER_ADDR_LEN, + &adsl->macAddr[0]); + } + wan_skb_copyback(new_skb, + wan_skb_len(new_skb), + sizeof(ether_type), + (caddr_t)ðer_type); + len -= sizeof(ethhdr_t); + } + + /* copy data into new_skb */ + wan_skb_copyback(new_skb, + wan_skb_len(new_skb), + len, + adsl->udp_pkt_data); +#if defined(__LINUX__) + if (card->u.adsl.EncapMode == RFC_MODE_BRIDGED_ETH_LLC || + card->u.adsl.EncapMode == RFC_MODE_BRIDGED_ETH_VC){ + new_skb->protocol = eth_type_trans(new_skb, new_skb->dev); + }else{ + /* Decapsulate pkt and pass it up the protocol stack */ + new_skb->protocol = htons(ETH_P_IP); + new_skb->mac.raw = new_skb->data; + } + if (adsl->udp_pkt_src == UDP_PKT_FRM_NETWORK){ + dev_queue_xmit(new_skb); + }else{ + netif_rx(new_skb); + } +#elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) + if (adsl->udp_pkt_src == UDP_PKT_FRM_NETWORK){ +#if defined(__FreeBSD__) + ether_output_frame(dev, new_skb); +#else + wan_spinlock_t s; + wan_spin_lock_irq(NULL, &s); + WAN_IFQ_ENQUEUE(&dev->if_snd, new_skb, NULL, error); + if (!error){ + dev->if_obytes += wan_skb_len(new_skb) + sizeof(ethhdr_t); + if ((dev->if_flags & IFF_DRV_OACTIVE) == 0){ + (*dev->if_start)(dev); + } + } + wan_spin_unlock_irq(NULL, &s); +#endif + }else{ +# if defined(__OpenBSD__) || defined(__FreeBSD__) && (__FreeBSD_version <= 500000) + ethhdr_t* eh = (ethhdr_t*)wan_skb_data(new_skb); +# endif + +# if defined(__FreeBSD__) && (__FreeBSD_version < 500000) + wan_bpf_report(dev, new_skb, 0); +# elif defined(__NetBSD__) || defined(__OpenBSD__) + wan_bpf_report(dev, new_skb, 0); +# endif +# if defined(__NetBSD__) || defined(__FreeBSD__) && (__FreeBSD_version > 500000) + dev->if_input(dev, new_skb); +# else + wan_skb_pull(new_skb, sizeof(ethhdr_t)); + ether_input(dev, eh, new_skb); +# endif + } +#endif + + }else{ + + DEBUG_EVENT("%s: no socket buffers available!\n", + card->devname); + } + + wan_atomic_set(&adsl->udp_pkt_len,0); + return error; +} + +/* + * + * + */ + +static int process_udp_cmd(netdevice_t* ifp, wan_udp_hdr_t* udp_hdr) +{ + netskb_t* skb = NULL; + adsl_private_area_t* adsl = wan_netif_priv(ifp); + sdla_t* card = adsl->common.card; + int buffer_length=0; + adsl_trace_info_t *trace_info = adsl_get_trace_ptr(adsl->pAdapter); + + udp_hdr->wan_udphdr_return_code=0; + if (card->u.adsl.adapter == NULL){ + return 0; + } + switch(udp_hdr->wan_udphdr_command){ + case WAN_GET_PROTOCOL: + udp_hdr->wan_udphdr_adsl_num_frames = WANCONFIG_ADSL; + udp_hdr->wan_udphdr_return_code = WAN_CMD_OK; + udp_hdr->wan_udphdr_data_len = 2; + break; + + case WAN_GET_PLATFORM: + udp_hdr->wan_udphdr_data[0] = WAN_FREEBSD_PLATFORM; + udp_hdr->wan_udphdr_return_code = WAN_CMD_OK; + udp_hdr->wan_udphdr_data_len = 1; + break; + + case ADSL_TEST_DRIVER_RESPONSE: + udp_hdr->wan_udphdr_return_code = WAN_CMD_OK; + break; + + case ADSL_READ_DRIVER_VERSION: + udp_hdr->wan_udphdr_return_code = WAN_CMD_OK; + sprintf(udp_hdr->wan_udphdr_data, "%s", WANPIPE_VERSION); + udp_hdr->wan_udphdr_data_len = strlen(udp_hdr->wan_udphdr_data); + break; + + case ADSL_ROUTER_UP_TIME: + wan_getcurrenttime(&adsl->router_up_time, NULL); + adsl->router_up_time -= adsl->router_start_time; + *(unsigned long *)&udp_hdr->wan_udphdr_data = + adsl->router_up_time; + udp_hdr->wan_udphdr_data_len = sizeof(unsigned long); + udp_hdr->wan_udphdr_return_code = WAN_CMD_OK; + break; + + case ADSL_ENABLE_TRACING: + + udp_hdr->wan_udphdr_return_code = WAN_CMD_OK; + udp_hdr->wan_udphdr_data_len = 0; + + if (!wan_test_bit(0,&trace_info->tracing_enabled)){ + + trace_info->trace_timeout = SYSTEM_TICKS; + + adsl_trace_purge(trace_info); + + if (udp_hdr->wan_udphdr_data[0] == 0){ + wan_clear_bit(1,&trace_info->tracing_enabled); + DEBUG_UDP("%s: ADSL L3 trace enabled!\n", + card->devname); + }else if (udp_hdr->wan_udphdr_data[0] == 1){ + wan_clear_bit(2,&trace_info->tracing_enabled); + wan_set_bit(1,&trace_info->tracing_enabled); + DEBUG_UDP("%s: ADSL L2 trace enabled!\n", + card->devname); + }else{ + wan_clear_bit(1,&trace_info->tracing_enabled); + wan_set_bit(2,&trace_info->tracing_enabled); + DEBUG_UDP("%s: ADSL L1 trace enabled!\n", + card->devname); + } + wan_set_bit (0,&trace_info->tracing_enabled); + + }else{ + DEBUG_EVENT("%s: Error: ADSL trace running!\n", + card->devname); + udp_hdr->wan_udphdr_return_code = 2; + } + + break; + + case ADSL_DISABLE_TRACING: + + udp_hdr->wan_udphdr_return_code = WAN_CMD_OK; + + if(wan_test_bit(0,&trace_info->tracing_enabled)) { + + wan_clear_bit(0,&trace_info->tracing_enabled); + wan_clear_bit(1,&trace_info->tracing_enabled); + wan_clear_bit(2,&trace_info->tracing_enabled); + adsl_trace_purge(trace_info); + DEBUG_UDP("%s: Disabling ADSL trace\n", + card->devname); + + }else{ + /* set return code to line trace already + disabled */ + udp_hdr->wan_udphdr_return_code = 1; + } + + break; + + case ADSL_GET_TRACE_INFO: + + if(wan_test_bit(0,&trace_info->tracing_enabled)){ + trace_info->trace_timeout = SYSTEM_TICKS; + }else{ + DEBUG_EVENT("%s: Error ADSL trace not enabled\n", + card->devname); + /* set return code */ + udp_hdr->wan_udphdr_return_code = 1; + break; + } + + buffer_length = 0; + udp_hdr->wan_udphdr_adsl_num_frames = 0; + udp_hdr->wan_udphdr_adsl_ismoredata = 0; + +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) + while (adsl_trace_queue_len(trace_info)){ + WAN_IFQ_POLL(&trace_info->trace_queue, skb); + if (skb == NULL){ + DEBUG_EVENT("%s: No more trace packets in trace queue!\n", + card->devname); + break; + } + if ((WAN_MAX_DATA_SIZE - buffer_length) < skb->m_pkthdr.len){ + /* indicate there are more frames on board & exit */ + udp_hdr->wan_udphdr_adsl_ismoredata = 0x01; + break; + } + + m_copydata(skb, + 0, + skb->m_pkthdr.len, + &udp_hdr->wan_udphdr_data[buffer_length]); + buffer_length += skb->m_pkthdr.len; + WAN_IFQ_DEQUEUE(&trace_info->trace_queue, skb); + if (skb){ + wan_skb_free(skb); + } + udp_hdr->wan_udphdr_adsl_num_frames++; + } +#elif defined(__LINUX__) + while ((skb=skb_dequeue(&trace_info->trace_queue)) != NULL){ + + if((MAX_TRACE_BUFFER - buffer_length) < wan_skb_len(skb)){ + /* indicate there are more frames on board & exit */ + udp_hdr->wan_udphdr_adsl_ismoredata = 0x01; + if (buffer_length != 0){ + skb_queue_head(&trace_info->trace_queue, skb); + }else{ + memcpy(&udp_hdr->wan_udphdr_adsl_data[buffer_length], + wan_skb_data(skb), + sizeof(wan_trace_pkt_t)); + + buffer_length = sizeof(wan_trace_pkt_t); + udp_hdr->wan_udphdr_adsl_num_frames++; + wan_skb_free(skb); + } + break; + } + + memcpy(&udp_hdr->wan_udphdr_adsl_data[buffer_length], + wan_skb_data(skb), + wan_skb_len(skb)); + + buffer_length += wan_skb_len(skb); + wan_skb_free(skb); + udp_hdr->wan_udphdr_adsl_num_frames++; + } +#endif + /* set the data length and return code */ + udp_hdr->wan_udphdr_data_len = buffer_length; + udp_hdr->wan_udphdr_return_code = WAN_CMD_OK; + break; + + default: + adsl_udp_cmd( + card->u.adsl.adapter, + udp_hdr->wan_udphdr_command, + &udp_hdr->wan_udphdr_data[0], + &udp_hdr->wan_udphdr_data_len); + udp_hdr->wan_udphdr_return_code = WAN_CMD_OK; + break; + } + + wan_atomic_set(&adsl->udp_pkt_len, + sizeof(wan_mgmt_t) + sizeof(wan_trace_info_t) + + sizeof(wan_cmd_t) + udp_hdr->wan_udphdr_data_len); + udp_hdr->wan_udphdr_request_reply = UDPMGMT_REPLY; + + return 0; +} + +#if defined (__LINUX__) +static int wanpipe_attach_sppp(sdla_t *card, netdevice_t *dev, wanif_conf_t *conf) +{ + adsl_private_area_t *adsl=dev->priv; + struct ppp_device *pppdev=NULL; + struct sppp *sp=NULL; + + pppdev=kmalloc(sizeof(struct ppp_device),GFP_KERNEL); + if (!pppdev){ + return -ENOMEM; + } + memset(pppdev,0,sizeof(struct ppp_device)); + + adsl->common.prot_ptr=(void*)pppdev; + + /* Attach PPP protocol layer to pppdev + * The wp_sppp_attach() will initilize the dev structure + * and setup ppp layer protocols. + * All we have to do is to bind in: + * if_open(), if_close(), if_send() and get_stats() functions. + */ + + pppdev->dev=dev; + + /* Get authentication info. */ + if(conf->pap == WANOPT_YES){ + pppdev->sppp.myauth.proto = PPP_PAP; + DEBUG_EVENT("%s: Enableing PAP Protocol\n", + card->devname); + }else if(conf->chap == WANOPT_YES){ + pppdev->sppp.myauth.proto = PPP_CHAP; + DEBUG_EVENT("%s: Enableing CHAP Protocol\n", + card->devname); + }else{ + pppdev->sppp.myauth.proto = 0; + DEBUG_EVENT("%s: Authentication protocols disabled\n", + card->devname); + } + + if(pppdev->sppp.myauth.proto){ + memcpy(pppdev->sppp.myauth.name, conf->userid, AUTHNAMELEN); + memcpy(pppdev->sppp.myauth.secret, conf->passwd, AUTHNAMELEN); + + DEBUG_TX("%s: %s Username=%s Passwd=*****\n", + card->devname, + (pppdev->sppp.myauth.proto==PPP_PAP)?"PAP":"CHAP", + conf->userid); + } + + pppdev->sppp.gateway = conf->gateway; + if (conf->if_down){ + pppdev->sppp.dynamic_ip = 1; + } + + sprintf(pppdev->sppp.hwdevname,"%s",card->devname); + + wp_sppp_attach(pppdev); + sp = &pppdev->sppp; + + + /* Enable PPP Debugging */ + if (conf->protocol == WANCONFIG_CHDLC){ + printk(KERN_INFO "%s: Starting Kernel CISCO HDLC protocol\n", + card->devname); + sp->pp_flags |= PP_CISCO; + conf->ignore_dcd = WANOPT_YES; + conf->ignore_cts = WANOPT_YES; + }else{ + printk(KERN_INFO "%s: Starting Kernel Sync PPP protocol\n", + card->devname); + sp->pp_flags &= ~PP_CISCO; + dev->type = ARPHRD_PPP; + } + + return 0; +} + +#endif diff -Nur linux.org/drivers/net/wan/sdla_adsl_tty.c linux-2.6.17/drivers/net/wan/sdla_adsl_tty.c --- linux.org/drivers/net/wan/sdla_adsl_tty.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/drivers/net/wan/sdla_adsl_tty.c 2006-08-30 10:07:16.000000000 +0000 @@ -0,0 +1,413 @@ +/* TTY Call backs */ + +#if defined(__LINUX__) +# include +# include +# include +# include +# include +# include +# include +# include +# define STATIC static +#elif defined(__FreeBSD__) +# include +# include +# include +# include +# define STATIC +#else +# include +# include +# include +# include +# define STATIC +# if 0 +# error "Unsupported Operating System!" +# endif +#endif + +#define ADSL_WAN_TTY_VERSION 1 + +#ifndef ADSL_TTY_MAJOR +#define ADSL_TTY_MAJOR 240 +#endif + +#define ADSL_WAN_MAX_CHANNELS 1 +#define ADSL_WAN_TTY_NAME "ttyWP" + +#ifndef ADSL_NR_PORTS +# define ADSL_NR_PORTS 4 +#else +# if ADSL_NR_PORTS > 16 +# undef ADSL_NR_PORTS +# define ADSL_NR_PORTS 16 +# endif +#endif + +/* FIXME Redefined in gpwan.c */ +#define GSI_WAN_MAX_CHANNELS 1 + +#if defined(__LINUX__) +static int adsl_wan_tx(ttystruct_t*, int, const unsigned char*, int); +static int adsl_wan_open(ttystruct_t *tp, struct file *pFile); +static void adsl_wan_close(ttystruct_t *tp, struct file *pFile); + +static ttydriver_t serial_driver; +static int serial_refcount=1; +static int tty_init_cnt=0; + +static struct tty_struct *serial_table[ADSL_NR_PORTS]; +static struct termios *serial_termios[ADSL_NR_PORTS]; +static struct termios *serial_termios_locked[ADSL_NR_PORTS]; +static void* tty_card_map[ADSL_NR_PORTS] = {NULL,NULL,NULL,NULL}; + +STATIC void adsl_wan_flush_chars(ttystruct_t *tp); +STATIC void adsl_wan_flush_buffer(ttystruct_t *tp); +STATIC int adsl_wan_chars_in_buffer(ttystruct_t *tp); +STATIC void adsl_wan_set_termios(ttystruct_t *tp, struct termios *old_termios); +STATIC int adsl_wan_write_room(ttystruct_t *tp); + +unsigned int adsl_get_tty_minor(void *tty_ptr); +unsigned int adsl_get_tty_minor_start(void *tty_ptr); +void adsl_mod_inc_use_count (void); +void adsl_mod_dec_use_count (void); +void adsl_set_tty_driver_data(void *tty_ptr, void *ptr); +void adsl_set_low_latency(void *tty_ptr, unsigned char data); +void *adsl_get_tty_driver_state(void *tty_ptr); + +STATIC void adsl_wan_flush_chars(ttystruct_t *tp) +{ + return; +} + +STATIC void adsl_wan_flush_buffer(ttystruct_t *tp) +{ + if (!tp){ + return; + } + + wake_up_interruptible(&tp->write_wait); +#if defined(SERIAL_HAVE_POLL_WAIT) || \ + (defined LINUX_2_1 && LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,15)) + wake_up_interruptible(&tp->poll_wait); +#endif + if ((tp->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tp->ldisc.write_wakeup) + (tp->ldisc.write_wakeup)(tp); + return; +} + +/*+F************************************************************************* + * Function: + * adsl_wan_chars_in_buffer() + * + * Description: + * Return the number of bytes waiting to be transmitted out the adapter. + *-F*************************************************************************/ +STATIC int adsl_wan_chars_in_buffer(ttystruct_t *tp) +{ + return 0; +} + + +STATIC void adsl_wan_set_termios(ttystruct_t *tp, struct termios *old_termios) +{ + return; +} + +STATIC int adsl_wan_write_room(ttystruct_t *tp) +{ + if (!tp) + return 0; + + if (!tp->driver_data) + return 0; + + return GpWanWriteRoom(tp->driver_data); +} + + +/*+F************************************************************************* + * Function: + * adsl_wan_open + * + * Description: + * Entry point for TTY device open request from the application. + *-F*************************************************************************/ +static int adsl_wan_open(ttystruct_t *tp, struct file *pFile) +{ + int status = 0; + int line; + + DEBUG_CFG("wanpipe: WanOpen\n"); + + line = MINOR(tp->device) - tp->driver.minor_start; + if ((line < 0) || (line >= ADSL_NR_PORTS)){ + DEBUG_EVENT("wanpipe: Error: Invalid tty line %d!\n", line); + status = -ENODEV; + goto adsl_wan_open_exit; + } + + if (!tty_card_map[line]){ + DEBUG_EVENT("wanpipe: Error: No adapter in tty map for minor %d!\n", line); + return -ENODEV; + } + + status = GpWanOpen(tty_card_map[line], line, tp, &tp->driver_data); + +adsl_wan_open_exit: + return status; +} + +/*+F************************************************************************* + * Function: + * GpWanClose + * + * Description: + * Entry point for TTY device close request from the application. + *-F*************************************************************************/ +static void adsl_wan_close(ttystruct_t *tp, struct file *pFile) +{ + int line; + DEBUG_CFG("wanpipe: GpWanClose\n"); + + line = MINOR(tp->device) - tp->driver.minor_start; + if ((line < 0) || (line >= ADSL_NR_PORTS)){ + DEBUG_EVENT("wanpipe: Error: Invalid tty line %d!\n", line); + return; + } + + if (!tty_card_map[line]){ + DEBUG_EVENT("wanpipe: Error: No adapter in tty map for minor %d!\n", line); + return; + } + + GpWanClose(tty_card_map[line],tp->driver_data); + + if (tp->driver.flush_buffer){ + tp->driver.flush_buffer(tp); + } + + if (tp->ldisc.flush_buffer){ + tp->ldisc.flush_buffer(tp); + } +} + +/*+F************************************************************************* + * Function: + * GpWanTx + * + * Description: + * Send a buffer to the adapter. It is assumed that the data has already + * been formatted as a synchronous PPP packet. This can be assured by + * setting the sync flag to PPP. Since the adapter does not need the PPP + * Address/Control bytes, they are stripped before the packet is sent down + * to the adapter. + *-F*************************************************************************/ +static int +adsl_wan_tx(ttystruct_t* tp, int fromUser, const unsigned char* buffer, int bufferLen) +{ + if (tp->driver_data == NULL){ + return -EINVAL; + } + + return GpWanTx(tp->driver_data, fromUser, buffer, bufferLen); +} + + +unsigned int adsl_get_tty_minor(void *tty_ptr) +{ + ttystruct_t *tp = (ttystruct_t *)tty_ptr; + return MINOR(tp->device); +} + +unsigned int adsl_get_tty_minor_start(void *tty_ptr) +{ + ttystruct_t *tp = (ttystruct_t *)tty_ptr; + return tp->driver.minor_start; +} + +void adsl_mod_inc_use_count (void) +{ +#if !defined(LINUX_2_6) + MOD_INC_USE_COUNT; +#endif +} + +void adsl_mod_dec_use_count (void) +{ +#if !defined(LINUX_2_6) + MOD_DEC_USE_COUNT; +#endif +} + +void adsl_set_tty_driver_data(void *tty_ptr, void *ptr) +{ + ttystruct_t *tp = (ttystruct_t *)tty_ptr; + tp->driver_data = ptr; +} +void adsl_set_low_latency(void *tty_ptr, unsigned char data) +{ + ttystruct_t *tp = (ttystruct_t *)tty_ptr; + tp->low_latency = data; +} +void *adsl_get_tty_driver_state(void *tty_ptr) +{ + ttystruct_t *tp = (ttystruct_t *)tty_ptr; + WAN_ASSERT2((tp==NULL),NULL); + + return (void*)tp->driver.driver_state; +} + + +void adsl_tty_hangup(void *tty_ptr) +{ + ttystruct_t *tp = (ttystruct_t *)tty_ptr; + WAN_ASSERT1((tp==NULL)); + DEBUG_EVENT("Hanging up TTY\n"); + tty_hangup(tp); + schedule(); +} +#endif + +void* adsl_termios_alloc(void) +{ + return wan_malloc(sizeof(termios_t)); +} + +/*+F************************************************************************* + * Function: + * GpWanRegister + * + * Description: + * Register the WAN interface of the adapter as a TTY device with the + * operating system. + *-F*************************************************************************/ +int adsl_wan_register(void *driver_data, + char *devname, + unsigned char minor_no) +{ + int status = 0; + +#if defined(__LINUX__) + ttydriver_t *tp = &serial_driver; + + if (minor_no >= ADSL_NR_PORTS){ + DEBUG_EVENT("%s: Error Illegal Minor TTY number (0-%d): %i\n", + devname,ADSL_NR_PORTS,minor_no); + return -EINVAL; + } + + if (tty_card_map[minor_no] != NULL){ + DEBUG_EVENT("%s: Error TTY Minor %i, already in use\n", + devname,minor_no); + return -EBUSY; + } + + DEBUG_EVENT ("%s: ADSL Registering %s%d Major=%d Minor=%i Channels=(0-%d)\n", + devname,ADSL_WAN_TTY_NAME,minor_no,ADSL_TTY_MAJOR,minor_no,ADSL_NR_PORTS-1); + + if (tty_init_cnt==0){ + + memset(tp,0,sizeof(ttydriver_t)); + + tp->magic = TTY_DRIVER_MAGIC; + tp->driver_name = "wanpipe"; + tp->name = ADSL_WAN_TTY_NAME; + tp->major = ADSL_TTY_MAJOR; + tp->minor_start = 0; + tp->num = ADSL_NR_PORTS; + tp->type = TTY_DRIVER_TYPE_SERIAL; + tp->subtype = SERIAL_TYPE_NORMAL; + tp->init_termios = tty_std_termios; + tp->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; + tp->flags = TTY_DRIVER_REAL_RAW; + tp->refcount = &serial_refcount; + tp->table = serial_table; + tp->termios = serial_termios; + tp->termios_locked = serial_termios_locked; + + tp->open = adsl_wan_open; + tp->close = adsl_wan_close; + tp->write = adsl_wan_tx; + tp->write_room = adsl_wan_write_room; + tp->chars_in_buffer = adsl_wan_chars_in_buffer; + tp->flush_chars = adsl_wan_flush_chars; + tp->flush_buffer = adsl_wan_flush_buffer; + tp->ioctl = NULL;// GpWanIoctl; + tp->set_termios = adsl_wan_set_termios; + tp->stop = NULL; + tp->start = NULL; + tp->throttle = NULL; + tp->unthrottle = NULL; + tp->hangup = NULL; + tp->break_ctl = NULL; + tp->send_xchar = NULL; + tp->wait_until_sent = NULL; + tp->read_proc = NULL; + + if (tty_register_driver(tp)){ + DEBUG_EVENT("Unabled to register TTY interface!\n"); + return -ENODEV; + } + } + + tty_init_cnt++; + tty_card_map[minor_no] = driver_data; + +#endif + return status; +} + +void adsl_wan_unregister(unsigned char minor_no) +{ +#if defined(__LINUX__) + + if ((--tty_init_cnt) == 0){ + *serial_driver.refcount=0; + tty_unregister_driver(&serial_driver); + } + tty_card_map[minor_no]=NULL; + +#endif +} + +/*+F************************************************************************* + * Function: + * adsl_wan_soft_intr + * + * Description: + * Routine to actually process queued channel events. + *-F*************************************************************************/ +void adsl_wan_soft_intr(void *tty_ptr, unsigned int bit, unsigned long *event) +{ + +#if defined(__LINUX__) + ttystruct_t *tp = (ttystruct_t *)tty_ptr; + DEBUG_TX("In adsl_wan_soft_intr\n"); + if (test_and_clear_bit(bit, event)){ + if ((tp->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + (tp->ldisc.write_wakeup != NULL)){ + (tp->ldisc.write_wakeup)(tp); + } + wake_up_interruptible(&(tp->write_wait)); +# if defined(SERIAL_HAVE_POLL_WAIT) || \ + (defined LINUX_2_1 && LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,15)) + wake_up_interruptible(&tp->poll_wait); +# endif + } +#endif +} + +void adsl_tty_receive(void *tty_ptr, unsigned char *pData, + unsigned char *pFlags,unsigned int dataLen) +{ +#if defined(__LINUX__) + ttystruct_t *tp = (ttystruct_t *)tty_ptr; + WAN_ASSERT1((tp==NULL)); + tp->ldisc.receive_buf(tp, pData, pFlags, dataLen); +#endif +} + + diff -Nur linux.org/drivers/net/wan/sdla_aft_te1.c linux-2.6.17/drivers/net/wan/sdla_aft_te1.c --- linux.org/drivers/net/wan/sdla_aft_te1.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/drivers/net/wan/sdla_aft_te1.c 2006-08-30 10:07:16.000000000 +0000 @@ -0,0 +1,9489 @@ +/***************************************************************************** +* sdla_aft_te1.c +* +* WANPIPE(tm) AFT TE1 Hardware Support +* +* Authors: Nenad Corbic +* +* Copyright: (c) 2003-2005 Sangoma Technologies Inc. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version +* 2 of the License, or (at your option) any later version. +* ============================================================================ +* Jan 07, 2003 Nenad Corbic Initial version. +* Oct 25, 2004 Nenad Corbic Support for QuadPort TE1 +*****************************************************************************/ + +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) +# include +# include +# include +# include /* Socket Driver common area */ +# include +# include +# include +#else +# include +# include +# include +# include +# include +# include /* Socket Driver common area */ +# include +# include +# include +# include +# include +#endif + +#include + +#undef DEBUG_REG + +#if 1 +#define AFT_FUNC_DEBUG() +#else +#define AFT_FUNC_DEBUG() DEBUG_EVENT("%s:%d\n",__FUNCTION__,__LINE__) +#endif + + +#if 0 +# define AFT_XTEST_UPDATE 1 +#else +# undef AFT_XTEST_UPDATE +#endif + + +#if 1 +# define AFT_SECURITY_CHECK 1 +#else +# undef AFT_SECURITY_CHECK +#endif + +#if 1 +# define AFT_WDT_ENABLE 1 +#else +# undef AFT_WDT_ENABLE +#endif + +#if 0 +# define AFT_RX_FIFO_DEBUG 1 +# warning "AFT_RX_FIFO_DEBUG Flag used" +#else +# undef AFT_RX_FIFO_DEBUG +#endif + +#if 0 +# define AFT_TX_FIFO_DEBUG 1 +# warning "AFT_TX_FIFO_DEBUG Flag used" +#else +# undef AFT_TX_FIFO_DEBUG +#endif + +#if 0 +# define AFT_SINGLE_DMA_CHAIN 1 +# warning "AFT_SINGLE_DMA_CHAIN: SET" +#else +# undef AFT_SINGLE_DMA_CHAIN +#endif + +#if 1 +# define AFT_IFT_INTR_ENABLE 1 +#else +# undef AFT_IFT_INTR_ENABLE +#endif + +#if 0 +# define AFT_IRQ_DEBUG 1 +#else +# undef AFT_IRQ_DEBUG +#endif + +#if 0 +# define AFT_IRQ_STAT_DEBUG 1 +#else +# undef AFT_IRQ_STAT_DEBUG +#endif + + +#if 0 +# define AFT_TDMV_BH_ENABLE 1 +# warning "AFT_TDMV_BH_ENABLE flag used" +#else +# undef AFT_TDMV_BH_ENABLE +#endif + +#if 1 +# define AFT_TDMV_CHANNELIZATION 1 +#else +# undef AFT_TDMV_CHANNELIZATION +#endif + +#if 1 +# define AFT_CLOCK_SYNC 1 +#else +# undef AFT_CLOCK_SYNC +#endif + +#if defined(__LINUX__) +#define AFT_TDM_API_SUPPORT 1 +#else +#undef AFT_TDM_API_SUPPORT +#endif + + +/* Trigger on Number of transactions + * 1= 1x8 byte transactions + * 2= 2x8 byte transactions + * 3= 3x8 byte transactions + * 4= 4x8 byte transactions + */ +#define AFT_TDMV_FIFO_LEVEL 1 + +#define AFT_SS7_CTRL_LEN_MASK 0x0F +#define AFT_SS7_CTRL_TYPE_BIT 4 +#define AFT_SS7_CTRL_FORCE_BIT 5 + +#define AFT_MAX_CHIP_SECURITY_CNT 100 + +#define AFT_FE_FIX_FIRM_VER 100 + + +aft_hw_dev_t aft_hwdev[MAX_AFT_HW_DEV]; + + +/****** Defines & Macros ****************************************************/ + +/* Private critical flags */ +enum { + POLL_CRIT = PRIV_CRIT, + CARD_DOWN, + TE_CFG, + CARD_HW_EC +}; + +enum { + LINK_DOWN, + DEVICE_DOWN +}; + +enum { + AFT_CHIP_CONFIGURED, + AFT_FRONT_END_UP, +}; + +enum { + TX_DMA_BUSY, + TX_HANDLER_BUSY, + TX_INTR_PENDING, + + RX_HANDLER_BUSY, + RX_DMA_BUSY, + RX_INTR_PENDING +}; + +enum { + AFT_FE_CFG_ERR, + AFT_FE_CFG, + AFT_FE_INTR, + AFT_FE_POLL, + AFT_FE_TDM_RBS, + AFT_FE_LED, + AFT_FE_EC_POLL +}; + +#define MAX_IP_ERRORS 10 + +#define PORT(x) (x == 0 ? "PRIMARY" : "SECONDARY" ) + + +#if 1 +# define TRUE_FIFO_SIZE 1 +#else +# undef TRUE_FIFO_SIZE +# define HARD_FIFO_CODE 0x1F +#endif + + +/* Remove HDLC Address + * 1=Remove Enabled + * 0=Remove Disabled + */ + +#if 0 +#define WANPIPE_CODEC_CONVERTER 1 +#else +#undef WANPIPE_CODEC_CONVERTER +#endif + +static int aft_rx_copyback=500; +/******Data Structures*****************************************************/ + +/* This structure is placed in the private data area of the device structure. + * The card structure used to occupy the private area but now the following + * structure will incorporate the card structure along with Protocol specific data + */ + + +/* Route Status options */ +#define NO_ROUTE 0x00 +#define ADD_ROUTE 0x01 +#define ROUTE_ADDED 0x02 +#define REMOVE_ROUTE 0x03 + +#define WP_WAIT 0 +#define WP_NO_WAIT 1 + +/* variable for keeping track of enabling/disabling FT1 monitor status */ +/* static int rCount; */ + +/* Function interface between WANPIPE layer and kernel */ +extern wan_iface_t wan_iface; + +extern void disable_irq(unsigned int); +extern void enable_irq(unsigned int); + +/**SECTOIN************************************************** + * + * Function Prototypes + * + ***********************************************************/ +int wp_aft_te1default_devcfg(sdla_t* card, wandev_conf_t* conf); +int wp_aft_te1default_ifcfg(sdla_t* card, wanif_conf_t* conf); + +/* WAN link driver entry points. These are called by the WAN router module. */ +static int update (wan_device_t* wandev); +static int new_if (wan_device_t* wandev, netdevice_t* dev, wanif_conf_t* conf); +static int del_if(wan_device_t *wandev, netdevice_t *dev); + +/* Network device interface */ +#if defined(__LINUX__) +static int if_init (netdevice_t* dev); +#endif +static int if_open (netdevice_t* dev); +static int if_close (netdevice_t* dev); +static int if_do_ioctl(netdevice_t *dev, struct ifreq *ifr, int cmd); + +static struct net_device_stats* if_stats (netdevice_t* dev); + +#if defined(__LINUX__) +static int if_send (netskb_t* skb, netdevice_t* dev); +#else +static int if_send(netdevice_t*, netskb_t*, struct sockaddr*,struct rtentry*); +#endif + +static void handle_front_end_state(void* card_id); +static void enable_timer(void* card_id); +static void enable_ec_timer(void* card_id); +static void if_tx_timeout (netdevice_t *dev); + +/* Miscellaneous Functions */ +static void port_set_state (sdla_t *card, int); + +static void disable_comm (sdla_t *card); + +/* Interrupt handlers */ +static void wp_aft_global_isr (sdla_t* card); +static void wp_aft_dma_per_port_isr(sdla_t *card); +static void wp_aft_tdmv_per_port_isr(sdla_t *card); +static void wp_aft_fifo_per_port_isr(sdla_t *card); +static void wp_aft_wdt_per_port_isr(sdla_t *card, int wdt_intr); + +/* Bottom half handlers */ +#if defined(__LINUX__) +static void wp_bh (unsigned long); +static void wp_tdm_bh (unsigned long); +#else +static void wp_bh (void*,int); +static void wp_tdm_bh (void*,int); +#endif + +/* Miscellaneous functions */ +static int process_udp_mgmt_pkt(sdla_t* card, netdevice_t* dev, + private_area_t*, + int local_dev); + +static int aft_global_chip_configuration(sdla_t *card, wandev_conf_t* conf); +static int aft_global_chip_disable(sdla_t *card); + +static int aft_chip_configure(sdla_t *card, wandev_conf_t* conf); +static int aft_chip_unconfigure(sdla_t *card); +static int aft_dev_configure(sdla_t *card, private_area_t *chan, wanif_conf_t* conf); +static void aft_dev_unconfigure(sdla_t *card, private_area_t *chan); + +static int aft_dma_rx(sdla_t *card, private_area_t *chan); +static void aft_dev_enable(sdla_t *card, private_area_t *chan); +static void aft_dev_close(sdla_t *card, private_area_t *chan); +static void aft_dev_open(sdla_t *card, private_area_t *gchan); +static void aft_dma_tx_complete (sdla_t *card, private_area_t *chan,int wdt, int reset); + +static int aft_dma_rx_complete(sdla_t *card, private_area_t *chan, int reset); +static int aft_init_rx_dev_fifo(sdla_t *card, private_area_t *chan, unsigned char); +static int aft_init_tx_dev_fifo(sdla_t *card, private_area_t *chan, unsigned char); +static void aft_tx_post_complete (sdla_t *card, private_area_t *chan, netskb_t *skb); +static void aft_rx_post_complete (sdla_t *card, private_area_t *chan, + netskb_t *skb, + netskb_t **new_skb, + unsigned char *pkt_error); +static int aft_dma_rx_tdmv(sdla_t *card, private_area_t *chan); + + +static void aft_channel_txdma_ctrl(sdla_t *card, private_area_t *chan, int on); +static void aft_channel_rxdma_ctrl(sdla_t *card, private_area_t *chan, int on); +static void aft_channel_txintr_ctrl(sdla_t *card, private_area_t *chan, int on); +static void aft_channel_rxintr_ctrl(sdla_t *card, private_area_t *chan, int on); + +static int aft_read_security(sdla_t *card); +static int aft_front_end_mismatch_check(sdla_t * card); +static int aft_tslot_sync_ctrl(sdla_t *card, private_area_t *chan, int mode); + +#if defined(__LINUX__) +static void aft_port_task (void * card_ptr); +#else +static void aft_port_task (void * card_ptr, int arg); +#endif + +static int aft_devel_ioctl(sdla_t *card,struct ifreq *ifr); +static int aft_write_bios(sdla_t *card, wan_cmd_api_t *api_cmd); +static int aft_write(sdla_t *card, wan_cmd_api_t *api_cmd); +static int aft_read(sdla_t *card, wan_cmd_api_t *api_cmd); +static int aft_fe_write(sdla_t *card, wan_cmd_api_t *api_cmd); +static int aft_fe_read(sdla_t *card, wan_cmd_api_t *api_cmd); + +static void front_end_interrupt(sdla_t *card, unsigned long reg, int lock); +static void enable_data_error_intr(sdla_t *card); +static void disable_data_error_intr(sdla_t *card, unsigned char); + +static void aft_tx_fifo_under_recover (sdla_t *card, private_area_t *chan); +static void aft_rx_fifo_over_recover(sdla_t *card, private_area_t *chan); + +static int set_chan_state(sdla_t* card, netdevice_t* dev, int state); + +static int update_comms_stats(sdla_t* card); + +static int protocol_init (sdla_t*card,netdevice_t *dev, + private_area_t *chan, wanif_conf_t* conf); +static int protocol_stop (sdla_t *card, netdevice_t *dev); +static int protocol_shutdown (sdla_t *card, netdevice_t *dev); +static void protocol_recv(sdla_t *card, private_area_t *chan, netskb_t *skb); + +static int aft_alloc_rx_dma_buff(sdla_t *card, private_area_t *chan, int num); +static int aft_init_requeue_free_skb(private_area_t *chan, netskb_t *skb); + + +static int aft_dma_tx (sdla_t *card,private_area_t *chan); +static void aft_tx_dma_chain_handler(unsigned long data, int wdt, int reset); +static void aft_tx_dma_voice_handler(unsigned long data, int wdt, int reset); +static void aft_tx_dma_chain_init(private_area_t *chan, aft_dma_chain_t *); +static void aft_rx_dma_chain_init(private_area_t *chan, aft_dma_chain_t *); +static void aft_index_tx_rx_dma_chains(private_area_t *chan); +static void aft_init_tx_rx_dma_descr(private_area_t *chan); +static void aft_free_rx_complete_list(private_area_t *chan); +static void aft_rx_cur_go_test(private_area_t *chan); +static void aft_free_rx_descriptors(private_area_t *chan); +static void aft_reset_rx_chain_cnt(private_area_t *chan); +static void aft_reset_tx_chain_cnt(private_area_t *chan); +static void aft_free_tx_descriptors(private_area_t *chan); + + +static int aft_realign_skb_pkt(private_area_t *chan, netskb_t *skb); + +static void aft_data_mux_cfg(sdla_t *card); +static void aft_data_mux_get_cfg(sdla_t *card); + +static void __aft_fe_intr_ctrl(sdla_t *card, int status); + +static int aft_ss7_tx_mangle(sdla_t *card,private_area_t *chan, netskb_t *skb); + +static int aft_tdmv_init(sdla_t *card, wandev_conf_t *conf); +static int aft_tdmv_free(sdla_t *card); +static int aft_tdmv_if_init(sdla_t *card, private_area_t *chan, wanif_conf_t *conf); +static int aft_tdmv_if_free(sdla_t *card, private_area_t *chan); + +#if 0 +static void wp_tdmv_api_chan_rx_tx(sdla_t *card, + private_area_t *chan, + unsigned char *rxdata, unsigned char *tx_data); +static void wp_tdmv_api_rx_tx (sdla_t *card, private_area_t *chan); +#endif + +static int aft_fifo_intr_ctrl(sdla_t *card, int ctrl); +static int aft_tdm_intr_ctrl(sdla_t *card, int ctrl); + +#if defined(__LINUX__) +static void aft_set_ss7_force_rx(sdla_t *card, private_area_t *chan); +#endif +static void aft_clear_ss7_force_rx(sdla_t *card, private_area_t *chan); + +static int aft_event_ctrl(void *chan_ptr, wan_event_ctrl_t *ctrl); +#ifdef AFT_TDM_API_SUPPORT +static int aft_read_rbs_bits(void *chan_ptr, u32 ch, u8 *rbs_bits); +static int aft_write_rbs_bits(void *chan_ptr, u32 ch, u8 rbs_bits); +static int aft_write_hdlc_frame(void *chan_ptr, netskb_t *skb); +#endif + +/* API VoIP event */ +static int wan_aft_api_ioctl(sdla_t *card, private_area_t *chan, char *user_data); +static void wan_aft_api_dtmf (void* card_id, wan_event_t *event); + + +#if 0 +static void aft_list_descriptors(private_area_t *chan); +#endif +#if 0 +static void aft_list_dma_chain_regs(sdla_t *card); +#endif + +#if 0 +static void aft_list_tx_descriptors(private_area_t *chan); +#endif +#if 0 +static void aft_display_chain_history(private_area_t *chan); +static void aft_chain_history(private_area_t *chan,u8 end, u8 cur, u8 begin, u8 loc); +#endif + + +/* TE1 Control registers */ +#if 0 +static WRITE_FRONT_END_REG_T write_front_end_reg; +static READ_FRONT_END_REG_T read_front_end_reg; +#endif + +unsigned char aft_read_cpld(sdla_t *card, unsigned short cpld_off); +int aft_write_cpld(void *pcard, unsigned short off,unsigned char data); + +/* Procfs functions */ +static int wan_aft_get_info(void* pcard, struct seq_file* m, int* stop_cnt); + +static int wan_aft_init (sdla_t *card, wandev_conf_t* conf); + + +static unsigned char aft_write_ec (void*, unsigned short, unsigned char); +static unsigned char aft_read_ec (void*, unsigned short); + + +/**SECTION********************************************************* + * + * Public Functions + * + ******************************************************************/ + +int wp_aft_te1default_devcfg(sdla_t* card, wandev_conf_t* conf) +{ + conf->config_id = WANCONFIG_AFT_TE1; + conf->u.aft.dma_per_ch = MAX_RX_BUF; + conf->u.aft.mru = 1500; + return 0; +} + +int wp_aft_te1default_ifcfg(sdla_t* card, wanif_conf_t* conf) +{ + conf->protocol = WANCONFIG_HDLC; + memcpy(conf->usedby, "WANPIPE", 7); + conf->if_down = 0; + conf->ignore_dcd = WANOPT_NO; + conf->ignore_cts = WANOPT_NO; + conf->hdlc_streaming = WANOPT_NO; + conf->mc = 0; + conf->gateway = 0; + conf->active_ch = ENABLE_ALL_CHANNELS; + + return 0; +} + +#if 0 +static void aft_delay(int sec) +{ +#if 0 + unsigned long timeout=SYSTEM_TICKS; + while ((SYSTEM_TICKS-timeout)<(sec*HZ)){ + schedule(); + } +#endif +} +#endif + + +int aft_global_hw_device_init(void) +{ + memset(aft_hwdev,0,sizeof(aft_hwdev)); + + aft_hwdev[WANOPT_AFT104].init = 1; + aft_hwdev[WANOPT_AFT104].aft_global_chip_config = a104_global_chip_config; + aft_hwdev[WANOPT_AFT104].aft_global_chip_unconfig = a104_global_chip_unconfig; + aft_hwdev[WANOPT_AFT104].aft_chip_config = a104_chip_config; + aft_hwdev[WANOPT_AFT104].aft_chip_unconfig = a104_chip_unconfig; + aft_hwdev[WANOPT_AFT104].aft_chan_config = a104_chan_dev_config; + aft_hwdev[WANOPT_AFT104].aft_chan_unconfig = a104_chan_dev_unconfig; + aft_hwdev[WANOPT_AFT104].aft_led_ctrl = a104_led_ctrl; + aft_hwdev[WANOPT_AFT104].aft_test_sync = a104_test_sync; + aft_hwdev[WANOPT_AFT104].aft_read_cpld = a104_read_cpld; + aft_hwdev[WANOPT_AFT104].aft_write_cpld = a104_write_cpld; + aft_hwdev[WANOPT_AFT104].aft_fifo_adjust = a104_fifo_adjust; + aft_hwdev[WANOPT_AFT104].aft_check_ec_security = a104_check_ec_security; + + aft_hwdev[WANOPT_AFT_ANALOG].init = 1; + aft_hwdev[WANOPT_AFT_ANALOG].aft_global_chip_config = aft_analog_global_chip_config; + aft_hwdev[WANOPT_AFT_ANALOG].aft_global_chip_unconfig = aft_analog_global_chip_unconfig; + aft_hwdev[WANOPT_AFT_ANALOG].aft_chip_config = aft_analog_chip_config; + aft_hwdev[WANOPT_AFT_ANALOG].aft_chip_unconfig = aft_analog_chip_unconfig; + aft_hwdev[WANOPT_AFT_ANALOG].aft_chan_config = aft_analog_chan_dev_config; + aft_hwdev[WANOPT_AFT_ANALOG].aft_chan_unconfig = aft_analog_chan_dev_unconfig; + aft_hwdev[WANOPT_AFT_ANALOG].aft_led_ctrl = aft_analog_led_ctrl; + aft_hwdev[WANOPT_AFT_ANALOG].aft_test_sync = aft_analog_test_sync; + aft_hwdev[WANOPT_AFT_ANALOG].aft_read_cpld = aft_analog_read_cpld; + aft_hwdev[WANOPT_AFT_ANALOG].aft_write_cpld = aft_analog_write_cpld; + aft_hwdev[WANOPT_AFT_ANALOG].aft_fifo_adjust = aft_analog_fifo_adjust; + aft_hwdev[WANOPT_AFT_ANALOG].aft_check_ec_security = a200_check_ec_security; + + return 0; +} + + +/*============================================================================ + * wp_aft_te1_init - Cisco HDLC protocol initialization routine. + * + * @card: Wanpipe card pointer + * @conf: User hardware/firmware/general protocol configuration + * pointer. + * + * This routine is called by the main WANPIPE module + * during setup: ROUTER_SETUP ioctl(). + * + * At this point adapter is completely initialized + * and firmware is running. + * o read firmware version (to make sure it's alive) + * o configure adapter + * o initialize protocol-specific fields of the adapter data space. + * + * Return: 0 o.k. + * < 0 failure. + */ + +int wp_aft_analog_init (sdla_t *card, wandev_conf_t* conf) +{ + /* Verify configuration ID */ + if (card->wandev.config_id != WANCONFIG_AFT_ANALOG) { + DEBUG_EVENT( "%s: invalid configuration ID %u!\n", + card->devname, card->wandev.config_id); + return -EINVAL; + } + + ASSERT_AFT_HWDEV(card->wandev.card_type); + + card->hw_iface.getcfg(card->hw, SDLA_COREREV, &card->u.aft.firm_ver); + if (card->u.aft.firm_ver < AFT_MIN_ANALOG_FRMW_VER){ + DEBUG_EVENT( "%s: Invalid/Obselete AFT ANALOG firmware version %X (not >= %X)!\n", + card->devname, card->u.aft.firm_ver,AFT_MIN_ANALOG_FRMW_VER); + DEBUG_EVENT( "%s Refer to /usr/share/doc/wanpipe/README.aft_firm_update\n", + card->devname); + DEBUG_EVENT( "%s: Please contact Sangoma Technologies for more info.\n", + card->devname); + return -EINVAL; + } + + if (conf == NULL){ + DEBUG_EVENT("%s: Bad configuration structre!\n", + card->devname); + return -EINVAL; + } + + /* Make special hardware initialization for Analog board */ + memcpy(&card->fe.fe_cfg, &conf->fe_cfg, sizeof(sdla_fe_cfg_t)); + wp_remora_iface_init(&card->wandev.fe_iface); + card->fe.name = card->devname; + card->fe.card = card; + card->fe.write_fe_reg = aft_analog_write_fe; + card->fe.read_fe_reg = aft_analog_read_fe; + card->fe.__read_fe_reg = __aft_analog_read_fe; + + card->wandev.fe_enable_timer = enable_timer; + card->wandev.ec_enable_timer = enable_ec_timer; + card->wandev.te_link_state = handle_front_end_state; + + if (card->wandev.comm_port == WANOPT_PRI){ + conf->clocking = WANOPT_EXTERNAL; + } + + card->wandev.comm_port=card->fe.fe_cfg.line_no; + if (card->wandev.comm_port != 0){ + DEBUG_EVENT("%s: Error: Invalid port selected %d (Port 1)\n", + card->devname,card->wandev.comm_port); + return -EINVAL; + } + + card->u.aft.num_of_time_slots=MAX_REMORA_MODULES; + + return wan_aft_init(card,conf); + +} + + +int wp_aft_te1_init (sdla_t* card, wandev_conf_t* conf) +{ + + AFT_FUNC_DEBUG(); + + wan_set_bit(CARD_DOWN,&card->wandev.critical); + + /* Verify configuration ID */ + if (card->wandev.config_id != WANCONFIG_AFT_TE1) { + DEBUG_EVENT( "%s: invalid configuration ID %u!\n", + card->devname, card->wandev.config_id); + return -EINVAL; + } + + + card->hw_iface.getcfg(card->hw, SDLA_COREREV, &card->u.aft.firm_ver); + + if (card->u.aft.firm_ver < AFT_MIN_FRMW_VER){ + DEBUG_EVENT( "%s: Invalid/Obselete AFT firmware version %X (not >= %X)!\n", + card->devname, card->u.aft.firm_ver,AFT_MIN_FRMW_VER); + DEBUG_EVENT( "%s Refer to /usr/share/doc/wanpipe/README.aft_firm_update\n", + card->devname); + DEBUG_EVENT( "%s: Please contact Sangoma Technologies for more info.\n", + card->devname); + return -EINVAL; + } + + ASSERT_AFT_HWDEV(card->wandev.card_type); + + if (conf == NULL){ + DEBUG_EVENT("%s: Bad configuration structre!\n", + card->devname); + return -EINVAL; + } + +#if defined(WAN_DEBUG_MEM) + DEBUG_EVENT("%s: Total Mem %d\n",__FUNCTION__,wan_atomic_read(&wan_debug_mem)); +#endif + + /* TE1 Make special hardware initialization for T1/E1 board */ + if (IS_TE1_MEDIA(&conf->fe_cfg)){ + int max_ports = 4; + + if (conf->fe_cfg.cfg.te_cfg.active_ch == 0){ + conf->fe_cfg.cfg.te_cfg.active_ch = -1; + } + + memcpy(&card->fe.fe_cfg, &conf->fe_cfg, sizeof(sdla_fe_cfg_t)); + if (card->adptr_type == A108_ADPTR_8TE1) { + max_ports = 8; + sdla_8te1_iface_init(&card->wandev.fe_iface); + }else{ + sdla_te_iface_init(&card->wandev.fe_iface); + } + card->fe.name = card->devname; + card->fe.card = card; + card->fe.write_fe_reg = a104_write_fe; + card->fe.read_fe_reg = a104_read_fe; + card->fe.__read_fe_reg = __a104_read_fe; + + card->wandev.fe_enable_timer = enable_timer; + card->wandev.ec_enable_timer = enable_ec_timer; + card->wandev.te_link_state = handle_front_end_state; + conf->interface = + IS_T1_CARD(card) ? WANOPT_V35 : WANOPT_RS232; + + if (card->wandev.comm_port == WANOPT_PRI){ + conf->clocking = WANOPT_EXTERNAL; + } + + card->wandev.comm_port=card->fe.fe_cfg.line_no; + if (card->wandev.comm_port < 0 || card->wandev.comm_port > max_ports-1){ + DEBUG_EVENT("%s: Error: Invalid port selected %d (Min=1 Max=%d)\n", + card->devname,card->wandev.comm_port, max_ports); + return -EINVAL; + } + + if (IS_T1_CARD(card)){ + card->u.aft.num_of_time_slots=NUM_OF_T1_CHANNELS; + }else{ + card->u.aft.num_of_time_slots=NUM_OF_E1_CHANNELS; + } + }else{ + DEBUG_EVENT("%s: Invalid Front-End media type!!\n", + card->devname); + return -EINVAL; + } + + return wan_aft_init(card,conf); + +} + + +static int wan_aft_init (sdla_t *card, wandev_conf_t* conf) +{ + int err; + int used_cnt; + + /* Obtain hardware configuration parameters */ + card->wandev.clocking = conf->clocking; + card->wandev.ignore_front_end_status = conf->ignore_front_end_status; + card->wandev.ttl = conf->ttl; + card->wandev.interface = conf->interface; + card->wandev.comm_port = conf->comm_port; + card->wandev.udp_port = conf->udp_port; + card->wandev.new_if_cnt = 0; + wan_atomic_set(&card->wandev.if_cnt,0); + card->u.aft.chip_security_cnt=0; + + memcpy(&card->u.aft.cfg,&conf->u.aft,sizeof(wan_xilinx_conf_t)); + memset(card->u.aft.dev_to_ch_map,0,sizeof(card->u.aft.dev_to_ch_map)); + + card->u.aft.cfg.dma_per_ch = MAX_RX_BUF; + card->u.aft.tdmv_api_rx = NULL; + card->u.aft.tdmv_api_tx = NULL; + wan_skb_queue_init(&card->u.aft.tdmv_api_tx_list); + + + if (card->wandev.ignore_front_end_status == WANOPT_NO){ + DEBUG_EVENT( + "%s: Enabling front end link monitor\n", + card->devname); + }else{ + DEBUG_EVENT( + "%s: Disabling front end link monitor\n", + card->devname); + } + + AFT_FUNC_DEBUG(); + + /* WARNING: After this point the init function + * must return with 0. The following bind + * functions will cause problems if structures + * below are not initialized */ + + card->wandev.update = &update; + card->wandev.new_if = &new_if; + card->wandev.del_if = &del_if; + card->disable_comm = NULL; + + +#ifdef WANPIPE_ENABLE_PROC_FILE_HOOKS + /* Proc fs functions hooks */ + card->wandev.get_config_info = &get_config_info; + card->wandev.get_status_info = &get_status_info; + card->wandev.get_dev_config_info= &get_dev_config_info; + card->wandev.get_if_info = &get_if_info; + card->wandev.set_dev_config = &set_dev_config; + card->wandev.set_if_info = &set_if_info; +#endif + card->wandev.get_info = &wan_aft_get_info; + + /* Setup Port Bps */ + if(card->wandev.clocking) { + card->wandev.bps = conf->bps; + }else{ + card->wandev.bps = 0; + } + + /* For Primary Port 0 */ +#ifdef CONFIG_PRODUCT_WANPIPE_TDM_VOICE + card->wandev.mtu = conf->mtu; + card->wan_tdmv.sc = NULL; +#else + card->wandev.mtu=conf->mtu; + if (card->wandev.mtu > MAX_WP_PRI_MTU || + card->wandev.mtu < MIN_WP_PRI_MTU){ + DEBUG_EVENT("%s: Error Invalid Global MTU %d (Min=%d, Max=%d)\n", + card->devname,card->wandev.mtu, + MIN_WP_PRI_MTU,MAX_WP_PRI_MTU); + + return -EINVAL; + } +#endif + + + if (!card->u.aft.cfg.mru){ + card->u.aft.cfg.mru = card->wandev.mtu; + } + + + + if (card->u.aft.cfg.mru > MAX_WP_PRI_MTU || + card->u.aft.cfg.mru < MIN_WP_PRI_MTU){ + DEBUG_EVENT("%s: Error Invalid Global MRU %d (Min=%d, Max=%d)\n", + card->devname,card->u.aft.cfg.mru, + MIN_WP_PRI_MTU,MAX_WP_PRI_MTU); + + return -EINVAL; + } + + card->hw_iface.getcfg(card->hw, SDLA_BASEADDR, &card->u.aft.bar); + + port_set_state(card,WAN_CONNECTING); + + AFT_FUNC_DEBUG(); + + WAN_TASKQ_INIT((&card->u.aft.port_task),0,aft_port_task,card); + + card->u.aft.chip_cfg_status=0; + card->hw_iface.getcfg(card->hw, SDLA_USEDCNT, &used_cnt); + + wan_clear_bit(CARD_DOWN,&card->wandev.critical); + card->isr = &wp_aft_global_isr; + + if (used_cnt==1){ + DEBUG_EVENT("%s: Global Chip Configuration: used=%d\n", + card->devname,used_cnt); + + err=aft_global_chip_configuration(card, conf); + if (err){ + aft_global_chip_disable(card); + return err; + } + + aft_data_mux_cfg(card); + + }else{ + + aft_data_mux_get_cfg(card); + + err=aft_front_end_mismatch_check(card); + if (err){ + return err; + } + + DEBUG_EVENT("%s: Global Chip Configuration skiped: used=%d\n", + card->devname,used_cnt); + } + aft_read_security(card); + + err=aft_chip_configure(card,conf); + if (err){ + AFT_FUNC_DEBUG(); + + aft_chip_unconfigure(card); + if (used_cnt==1){ + aft_global_chip_disable(card); + } + return err; + } + wan_set_bit(AFT_CHIP_CONFIGURED,&card->u.aft.chip_cfg_status); + + if (wan_test_bit(AFT_FRONT_END_UP,&card->u.aft.chip_cfg_status)){ + wan_smp_flag_t smp_flags; + DEBUG_TEST("%s: Front end up, retrying enable front end!\n", + card->devname); + wan_spin_lock_irq(&card->wandev.lock,&smp_flags); + handle_front_end_state(card); + wan_spin_unlock_irq(&card->wandev.lock,&smp_flags); + + wan_clear_bit(AFT_FRONT_END_UP,&card->u.aft.chip_cfg_status); + } + + AFT_FUNC_DEBUG(); + + aft_read_security(card); + + + DEBUG_EVENT("%s: Configuring Device :%s FrmVr=%02X\n", + card->devname,card->devname,card->u.aft.firm_ver); + DEBUG_EVENT("%s: Global MTU = %d\n", + card->devname, + card->wandev.mtu); + DEBUG_EVENT("%s: Global MRU = %d\n", + card->devname, + card->u.aft.cfg.mru); + DEBUG_EVENT("%s: Data Mux Map = 0x%08X\n", + card->devname, + card->u.aft.cfg.data_mux_map); + DEBUG_EVENT("%s: Rx CRC Bytes = %i\n", + card->devname, + card->u.aft.cfg.rx_crc_bytes); + + err=aft_tdmv_init(card,conf); + if (err){ + disable_comm(card); + return err; + } + + card->disable_comm = &disable_comm; + + card->wandev.read_ec = aft_read_ec; + card->wandev.write_ec = aft_write_ec; + return 0; + +} + + + + +/**SECTION************************************************************** + * + * WANPIPE Device Driver Entry Points + * + * *********************************************************************/ + + + +/*============================================================================ + * update - Update wanpipe device status & statistics + * + * @wandev: Wanpipe device pointer + * + * This procedure is called when updating the PROC file system. + * It returns various communications statistics. + * + * cat /proc/net/wanrouter/wanpipe# (where #=1,2,3...) + * + * These statistics are accumulated from 3 + * different locations: + * 1) The 'if_stats' recorded for the device. + * 2) Communication error statistics on the adapter. + * 3) Operational statistics on the adapter. + * + * The board level statistics are read during a timer interrupt. + * Note that we read the error and operational statistics + * during consecitive timer ticks so as to minimize the time + * that we are inside the interrupt handler. + * + */ +static int update (wan_device_t* wandev) +{ + sdla_t* card = wandev->private; + netdevice_t* dev; + volatile private_area_t* chan; + + /* sanity checks */ + if((wandev == NULL) || (wandev->private == NULL)) + return -EFAULT; + + if(wandev->state == WAN_UNCONFIGURED) + return -ENODEV; + + if(wan_test_bit(PERI_CRIT, (void*)&card->wandev.critical)) + return -EAGAIN; + + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + if(dev == NULL) + return -ENODEV; + + if((chan=wan_netif_priv(dev)) == NULL) + return -ENODEV; + + if(card->update_comms_stats){ + return -EAGAIN; + } + + DEBUG_TEST("%s: Chain Dma Status=0x%lX, TxCur=%d, TxPend=%d RxCur=%d RxPend=%d\n", + chan->if_name, + chan->dma_chain_status, + chan->tx_chain_indx, + chan->tx_pending_chain_indx, + chan->rx_chain_indx, + chan->rx_pending_chain_indx); + + +#if 1 + update_comms_stats(card); +#endif + return 0; +} + + + +/*============================================================================ + * new_if - Create new logical channel. + * + * &wandev: Wanpipe device pointer + * &dev: Network device pointer + * &conf: User configuration options pointer + * + * This routine is called by the ROUTER_IFNEW ioctl, + * in wanmain.c. The ioctl passes us the user configuration + * options which we use to configure the driver and + * firmware. + * + * This functions main purpose is to allocate the + * private structure for protocol and bind it + * to dev->priv pointer. + * + * Also the dev->init pointer should also be initialized + * to the if_init() function. + * + * Any allocation necessary for the private strucutre + * should be done here, as well as proc/ file initializetion + * for the network interface. + * + * o parse media- and hardware-specific configuration + * o make sure that a new channel can be created + * o allocate resources, if necessary + * o prepare network device structure for registaration. + * o add network interface to the /proc/net/wanrouter + * + * The opposite of this function is del_if() + * + * Return: 0 o.k. + * < 0 failure (channel will not be created) + */ + +static int +aft_tdm_api_init(sdla_t *card, private_area_t *chan, wanif_conf_t *conf) +{ +#ifdef AFT_TDM_API_SUPPORT + int err=0; +#endif + + if (chan->common.usedby != TDM_VOICE_API && + chan->common.usedby != TDM_VOICE_DCHAN) { + return 0; + } + +#ifdef AFT_TDM_API_SUPPORT + if (chan->tdmv_zaptel_cfg) { + return 0; + } + + /* Initilaize TDM API Parameters */ + chan->wp_tdm_api_dev.chan = chan; + chan->wp_tdm_api_dev.card = card; + wan_spin_lock_init(&chan->wp_tdm_api_dev.lock); + strncpy(chan->wp_tdm_api_dev.name,chan->if_name,WAN_IFNAME_SZ); + + if (conf->hdlc_streaming) { + chan->wp_tdm_api_dev.hdlc_framing=1; + } + + chan->wp_tdm_api_dev.event_ctrl = aft_event_ctrl; + chan->wp_tdm_api_dev.read_rbs_bits = aft_read_rbs_bits; + chan->wp_tdm_api_dev.write_rbs_bits = aft_write_rbs_bits; + chan->wp_tdm_api_dev.write_hdlc_frame = aft_write_hdlc_frame; + + chan->wp_tdm_api_dev.cfg.rx_disable = 0; + chan->wp_tdm_api_dev.cfg.tx_disable = 0; + + if (IS_T1_CARD(card)){ + chan->wp_tdm_api_dev.cfg.hw_tdm_coding=WP_MULAW; + chan->wp_tdm_api_dev.tdm_chan = chan->first_time_slot+1; + }else{ + chan->wp_tdm_api_dev.cfg.hw_tdm_coding=WP_ALAW; + chan->wp_tdm_api_dev.tdm_chan = chan->first_time_slot; + } + + if (IS_T1_CARD(card) || IS_FXOFXS_CARD(card)){ + /* Convert active_ch bit map to user */ + chan->wp_tdm_api_dev.active_ch = conf->active_ch << 1; + }else{ + chan->wp_tdm_api_dev.active_ch = conf->active_ch; + } + + chan->wp_tdm_api_dev.cfg.idle_flag = conf->u.aft.idle_flag; + chan->wp_tdm_api_dev.cfg.rbs_tx_bits = conf->u.aft.rbs_cas_idle; + + chan->wp_tdm_api_dev.tdm_span = card->u.aft.cfg.tdmv_span_no; + + err=wanpipe_tdm_api_reg(&chan->wp_tdm_api_dev); + if (err){ + return err; + } + + if (card->wandev.ec_enable){ + int channel=chan->wp_tdm_api_dev.tdm_chan-1; + DEBUG_EVENT("%s: HW echo canceller Enabled on channel %d\n", + chan->if_name, + channel+1); + err = card->wandev.ec_enable(card, 1, channel); + if (err) { + DEBUG_EVENT("%s: Failed to enable HWEC on channel %d\n", + chan->if_name,channel+1); + + } + + /* Ignore this error */ + err=0; + } + + wan_set_bit(0,&chan->wp_tdm_api_dev.init); + return err; +#else + DEBUG_EVENT("%s: TDM API support not compiled in\n", + card->devname); + return -EINVAL; +#endif + +} + +static int aft_tdm_api_free(sdla_t *card, private_area_t *chan) +{ +#ifdef AFT_TDM_API_SUPPORT + int err=0; + if (wan_test_bit(0,&chan->wp_tdm_api_dev.init)){ + wan_clear_bit(0,&chan->wp_tdm_api_dev.init); + err=wanpipe_tdm_api_unreg(&chan->wp_tdm_api_dev); + if (err){ + wan_set_bit(0,&chan->wp_tdm_api_dev.init); + return err; + } + } +#endif + return 0; +} + + + +static int aft_chan_if_init(sdla_t *card, netdevice_t *dev, private_area_t *chan) +{ + chan->first_time_slot=-1; + chan->last_time_slot=-1; + chan->logic_ch_num=-1; +#if defined(AFT_SINGLE_DMA_CHAIN) + chan->single_dma_chain=1; + chan->max_tx_bufs=MAX_AFT_DMA_CHAINS; +#else + chan->single_dma_chain=0; + chan->max_tx_bufs=MAX_TX_BUF; +#endif + chan->tslot_sync=0; + + strncpy(chan->if_name, wan_netif_name(dev), WAN_IFNAME_SZ); + + chan->card = card; + chan->common.card = card; + + WAN_IFQ_INIT(&chan->wp_tx_pending_list,0); + WAN_IFQ_INIT(&chan->wp_tx_complete_list,0); + + WAN_IFQ_INIT(&chan->wp_rx_free_list,0); + WAN_IFQ_INIT(&chan->wp_rx_complete_list,0); + + WAN_IFQ_INIT(&chan->wp_rx_stack_complete_list, 0); + WAN_IFQ_INIT(&chan->wp_rx_zap_complete_list, 0); + + wan_trace_info_init(&chan->trace_info,MAX_TRACE_QUEUE); + + /* Initiaize Tx/Rx DMA Chains */ + aft_index_tx_rx_dma_chains(chan); + + /* Initialize the socket binding information + * These hooks are used by the API sockets to + * bind into the network interface */ + WAN_TASKLET_INIT((&chan->common.bh_task),0,wp_bh,chan); + chan->common.dev = dev; + chan->tracing_enabled = 0; + + return 0; +} + + + +static int aft_ss7_if_init(sdla_t *card, private_area_t *chan, wanif_conf_t *conf) +{ + if (chan->common.usedby != API){ + /* SS7 Support not supported in non API mode */ + chan->cfg.ss7_enable = 0; + return 0; + } + + DEBUG_EVENT("%s: SS7 Support :%s\n", + card->devname, + chan->cfg.ss7_enable?"On":"Off"); + + if (chan->cfg.ss7_enable){ + + wan_smp_flag_t smp_flags; + u32 lcfg_reg; + + DEBUG_EVENT("%s: SS7 Mode :%s\n", + card->devname, + chan->cfg.ss7_mode?"4096":"128"); + + DEBUG_EVENT("%s: SS7 LSSU Size :%d\n", + card->devname, + chan->cfg.ss7_lssu_size); + + wan_spin_lock_irq(&card->wandev.lock,&smp_flags); + card->hw_iface.bus_read_4(card->hw,AFT_PORT_REG(card,AFT_LINE_CFG_REG), + &lcfg_reg); + if (chan->cfg.ss7_mode){ + aft_lcfg_ss7_mode4096_cfg(&lcfg_reg,chan->cfg.ss7_lssu_size); + }else{ + aft_lcfg_ss7_mode128_cfg(&lcfg_reg,chan->cfg.ss7_lssu_size); + } + card->hw_iface.bus_write_4(card->hw,AFT_PORT_REG(card,AFT_LINE_CFG_REG), + lcfg_reg); + card->u.aft.lcfg_reg=lcfg_reg; + wan_spin_unlock_irq(&card->wandev.lock,&smp_flags); + + aft_hwdev[card->wandev.card_type].aft_fifo_adjust(card,AFT_TDMV_FIFO_LEVEL); + chan->single_dma_chain=1; + } + + return 0; +} + +static int aft_transp_if_init(sdla_t *card, private_area_t *chan, wanif_conf_t *conf) +{ + unsigned char *buf; + + if (chan->mtu&0x03){ + DEBUG_EVENT("%s:%s: Error, Transparent MTU must be word aligned!\n", + card->devname,chan->if_name); + return -EINVAL; + } + + chan->max_idle_size=chan->mtu; + + if (chan->tslot_sync && chan->mtu%chan->num_of_time_slots){ + DEBUG_EVENT("%s:%s: Error, Sync Transparent MTU must be timeslot aligned!\n", + card->devname,chan->if_name); + + DEBUG_EVENT("%s:%s: Error, MTU=%d not multiple of %d timeslots!\n", + card->devname,chan->if_name, + chan->mtu,chan->num_of_time_slots); + + return -EINVAL; + } + + if (conf->protocol != WANCONFIG_LIP_ATM && chan->mru%chan->num_of_time_slots){ + DEBUG_EVENT("%s:%s: Error, Transparent MRU must be timeslot aligned!\n", + card->devname,chan->if_name); + + DEBUG_EVENT("%s:%s: Error, MRU=%d not multiple of %d timeslots!\n", + card->devname,chan->if_name, + chan->mru,chan->num_of_time_slots); + + return -EINVAL; + } + + + DEBUG_TEST("%s:%s: Config for Transparent mode: Idle=%X Len=%u\n", + card->devname,chan->if_name, + chan->idle_flag,chan->max_idle_size); + + chan->idle_flag=0x7E; + + if (chan->tdmv_zaptel_cfg){ +#if defined(CONFIG_PRODUCT_WANPIPE_TDM_VOICE) + chan->idle_flag = WAN_TDMV_IDLE_FLAG; +#endif + } + + /* We use the dma_mru value here, just because it will + * be easier to change the idle tx size on the fly */ + chan->tx_idle_skb = wan_skb_alloc(chan->dma_mru); + if (!chan->tx_idle_skb){ + return -EINVAL; + } + buf = wan_skb_put(chan->tx_idle_skb,chan->dma_mru); + + if(conf->protocol != WANCONFIG_LIP_ATM){ + memset(buf,chan->idle_flag,chan->dma_mru); + }else{ + chan->lip_atm = 1; + /* if running below LIP ATM, transmit idle cells */ + if(init_atm_idle_buffer((unsigned char*)buf, + wan_skb_len(chan->tx_idle_skb), + chan->if_name, + chan->cfg.data_mux )){ + + wan_skb_free(chan->tx_idle_skb); + chan->tx_idle_skb = NULL; + return -EINVAL; + } + } + + /* reset the tx idle buffer to the actual mtu size */ + wan_skb_trim(chan->tx_idle_skb,0); + wan_skb_put(chan->tx_idle_skb,chan->max_idle_size); + + return 0; +} + + +static int new_if_private (wan_device_t* wandev, netdevice_t* dev, wanif_conf_t* conf, int channelized) +{ + sdla_t* card = wandev->private; + private_area_t* chan; + int dma_per_ch=card->u.aft.cfg.dma_per_ch; + int err = 0; + + DEBUG_EVENT( "%s: Configuring Interface: %s\n", + card->devname, wan_netif_name(dev)); + + if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)){ + DEBUG_EVENT( "%s: Invalid interface name!\n", + card->devname); + return -EINVAL; + } + + + if (card->adptr_subtype != AFT_SUBTYPE_SHARK){ + if (card->u.aft.security_id != 0x01 && + card->u.aft.security_cnt >= 2){ + DEBUG_EVENT("%s: Error: Security: Max HDLC channels(2) exceeded!\n", + card->devname); + DEBUG_EVENT("%s: Un-Channelised AFT supports 2 HDLC ifaces!\n", + card->devname); + return -EINVAL; + } + } + + /* ====================================== + * Allocate and initialize private data + * =====================================*/ + + chan = wan_malloc(sizeof(private_area_t)); + if(chan == NULL){ + WAN_MEM_ASSERT(card->devname); + return -ENOMEM; + } + + memset(chan, 0, sizeof(private_area_t)); + memcpy(&chan->cfg,&conf->u.aft,sizeof(chan->cfg)); + + + if (card->wandev.config_id == WANCONFIG_AFT_ANALOG) { + chan->single_dma_chain = 1; + conf->hdlc_streaming=0; + } + + chan->true_if_encoding=conf->true_if_encoding; + + aft_chan_if_init(card,dev,chan); + + if (channelized){ + chan->channelized_cfg=1; + if (wan_netif_priv(dev)){ +#if 1 + private_area_t *cptr; + for (cptr=wan_netif_priv(dev);cptr->next!=NULL;cptr=cptr->next); + cptr->next=chan; + chan->next=NULL; +#else +#warning "DEBUG: Chan list backwards!" + chan->next = wan_netif_priv(dev); + wan_netif_set_priv(dev, chan); +#endif + }else{ + wan_netif_set_priv(dev, chan); + } + }else{ + chan->channelized_cfg=0; + wan_netif_set_priv(dev, chan); + } + + /* ====================================== + * Configure chan MTU and MRU Values + * And setup E1 timeslots + * =====================================*/ + chan->mtu = card->wandev.mtu; + if (conf->u.aft.mtu){ + chan->mtu=conf->u.aft.mtu; + if (chan->mtu > MAX_WP_PRI_MTU || + chan->mtu < MIN_WP_PRI_MTU){ + DEBUG_EVENT("%s: Error Invalid %s MTU %d (Min=%d, Max=%d)\n", + card->devname,chan->if_name,chan->mtu, + MIN_WP_PRI_MTU,MAX_WP_PRI_MTU); + + err= -EINVAL; + goto new_if_error; + } + + } + + chan->mru = card->u.aft.cfg.mru; + if (conf->u.aft.mru){ + chan->mru = conf->u.aft.mru; + if (chan->mru > MAX_WP_PRI_MTU || + chan->mru < MIN_WP_PRI_MTU){ + DEBUG_EVENT("%s: Error Invalid %s MRU %d (Min=%d, Max=%d)\n", + card->devname,chan->if_name,chan->mru, + MIN_WP_PRI_MTU,MAX_WP_PRI_MTU); + + err= -EINVAL; + goto new_if_error; + } + } + + /*==================================================== + * Interface connects top services to driver + * Interface can be used by the following services: + * WANPIPE = TCP/IP -> Driver + * API = Raw Socket Access -> Driver + * BRIDGE = Bridge to Ethernet -> Driver + * BRIDGE_NODE = TCP/IP to Ethernet -> Driver + * STACK = LIP -> Driver + * TDM_VOICE = Zaptel -> Trans Ch Driver + * TDM_VOICE_DCHAN = Zaptel -> Hdlc Driver (PRIVATE) + * TDM_VOICE_API = Raw Socket -> Transp Ch Driver + * TMD_API = Raw Socket -> Transp Channelized API + *===================================================*/ + + if(strcmp(conf->usedby, "WANPIPE") == 0) { + + DEBUG_EVENT( "%s: Running in WANPIPE mode\n", + wandev->name); + chan->common.usedby = WANPIPE; + + /* Used by GENERIC driver only otherwise protocols + * are in LIP layer */ + if (conf->protocol != WANOPT_NO){ + wan_netif_set_priv(dev, chan); + if ((err=protocol_init(card,dev,chan,conf)) != 0){ + wan_netif_set_priv(dev, NULL); + goto new_if_error; + } + } + +#if defined(__LINUX__) + + } else if( strcmp(conf->usedby, "TDM_API") == 0) { + + err=-EINVAL; + goto new_if_error; + + } else if( strcmp(conf->usedby, "API") == 0) { + chan->common.usedby = API; + DEBUG_EVENT( "%s:%s: Running in API mode\n", + wandev->name,chan->if_name); + wan_reg_api(chan, dev, card->devname); + if (card->wandev.ec_dev){ + /* Calculate frequency for EC interrupt poll */ + //card->wandev.event_callback.dtmf = wan_aft_api_dtmf; + if (IS_TE1_CARD(card)){ + card->wandev.ec_intmask = 500; + }else{ + card->wandev.ec_intmask = 800 / (chan->mtu / 8); + } + } +#endif + +#if defined(__LINUX__) + }else if (strcmp(conf->usedby, "BRIDGE") == 0) { + chan->common.usedby = BRIDGE; + DEBUG_EVENT( "%s:%s: Running in WANPIPE (BRIDGE) mode.\n", + card->devname,chan->if_name); +#endif + +#if defined(__LINUX__) + }else if (strcmp(conf->usedby, "BRIDGE_N") == 0) { + chan->common.usedby = BRIDGE_NODE; + DEBUG_EVENT( "%s:%s: Running in WANPIPE (BRIDGE_NODE) mode.\n", + card->devname,chan->if_name); +#endif + + }else if (strcmp(conf->usedby, "TDM_VOICE") == 0) { + +#ifdef CONFIG_PRODUCT_WANPIPE_TDM_VOICE + chan->common.usedby = TDM_VOICE; + + chan->tdmv_zaptel_cfg=1; + card->u.aft.tdmv_zaptel_cfg=1; + conf->hdlc_streaming=0; + chan->single_dma_chain=1; + chan->max_tx_bufs=MAX_AFT_DMA_CHAINS; + if (card->wandev.ec_dev){ + card->wandev.ec_intmask = 5000; + } + + if (card->u.aft.cfg.tdmv_dchan){ +# ifdef CONFIG_PRODUCT_WANPIPE_TDM_VOICE_DCHAN + int dchan=card->u.aft.cfg.tdmv_dchan; + if (IS_T1_CARD(card)){ + dchan--; + } + if (wan_test_bit(dchan,&conf->active_ch)){ + chan->common.usedby = TDM_VOICE_DCHAN; + conf->hdlc_streaming=1; + chan->single_dma_chain=0; + chan->mru=chan->mtu=1500; + } +# else + DEBUG_EVENT("%s: Error: TDMV_DCHAN Option not compiled into the driver!\n", + card->devname); + err=-EINVAL; + goto new_if_error; +# endif + } + + DEBUG_EVENT( "%s:%s: Running in TDM %sVoice Zaptel Mode.\n", + card->devname,chan->if_name, + chan->common.usedby == TDM_VOICE_DCHAN?"DCHAN ":""); +#else + DEBUG_EVENT("\n"); + DEBUG_EVENT("%s:%s: Error: TDM VOICE prot not compiled\n", + card->devname,chan->if_name); + DEBUG_EVENT("%s:%s: during installation process!\n", + card->devname,chan->if_name); + err=-EINVAL; + goto new_if_error; +#endif + +#if defined(__LINUX__) + }else if (strcmp(conf->usedby, "TDM_VOICE_API") == 0) { + + chan->common.usedby = TDM_VOICE_API; + chan->cfg.data_mux=1; + conf->hdlc_streaming=0; + chan->single_dma_chain=1; + chan->tdmv_zaptel_cfg=0; + if (card->wandev.ec_dev){ + card->wandev.ec_intmask = 10000; + } + + if (card->u.aft.cfg.tdmv_dchan){ + + int dchan=card->u.aft.cfg.tdmv_dchan; + if (IS_T1_CARD(card)){ + dchan--; + } + if (wan_test_bit(dchan,&conf->active_ch)){ + chan->common.usedby = TDM_VOICE_DCHAN; + chan->cfg.data_mux=0; + chan->single_dma_chain=0; + conf->hdlc_streaming=1; + chan->mru=chan->mtu=1500; + } + } + + + if (chan->common.usedby == TDM_VOICE_DCHAN) { + DEBUG_EVENT( "%s:%s: Running in TDM Voice DCHAN API Mode.\n", + card->devname,chan->if_name); + } else { + DEBUG_EVENT( "%s:%s: Running in TDM Voice API Mode.\n", + card->devname,chan->if_name); + } +#endif + + }else if (strcmp(conf->usedby, "STACK") == 0) { + chan->common.usedby = STACK; + DEBUG_EVENT( "%s:%s: Running in Stack mode.\n", + card->devname,chan->if_name); + + }else{ + DEBUG_EVENT( "%s:%s: Error: Invalid IF operation mode %s\n", + card->devname,chan->if_name,conf->usedby); + err=-EINVAL; + goto new_if_error; + } + + + /*=============================================== + * Interface Operation Setup + *==============================================*/ + + if (conf->u.aft.tdmv_hwec){ + card->wandev.ec_enable_map |= conf->active_ch; + } + + /* Read user specified active_ch, we must do it + * here because the active_ch value might change + * for different user modes*/ + chan->time_slot_map=conf->active_ch; + chan->num_of_time_slots= + aft_get_num_of_slots(card->u.aft.num_of_time_slots, + chan->time_slot_map); + + if (!chan->num_of_time_slots){ + DEBUG_EVENT("%s: Error: Invalid number of timeslots in map 0x%08lX!\n", + chan->if_name,chan->time_slot_map); + return -EINVAL; + } + + if (card->wandev.config_id == WANCONFIG_AFT_ANALOG && chan->num_of_time_slots > 1) { + DEBUG_EVENT( + "%s: Error: Invalid Analog number of timeslots in map 0x%08lX: (Valid=1)\n", + chan->if_name,chan->time_slot_map); + return -EINVAL; + } + + + /* ===================== + * Interaface TDMV Setup + * + * Initialize the interface for TDMV + * operation, if TDMV is not used this + * function will just return */ + err=aft_tdmv_if_init(card,chan,conf); + if (err){ + err=-EINVAL; + goto new_if_error; + } + + + /* ===================== + * Interaface SS7 Setup + * + * Initialize the interface for TDMV + * operation, if TDMV is not used this + * function will just return */ + err=aft_ss7_if_init(card,chan,conf); + if (err){ + err=-EINVAL; + goto new_if_error; + } + + + /* Print out the current configuration */ + DEBUG_EVENT("%s: MRU :%d\n", + card->devname, + chan->mru); + + DEBUG_EVENT("%s: MTU :%d\n", + card->devname, + chan->mtu); + + + chan->hdlc_eng = conf->hdlc_streaming; + + DEBUG_EVENT("%s: HDLC Eng :%s\n", + card->devname, + chan->hdlc_eng?"On":"Off (Transparent)"); + + + /* Obtain the DMA MRU size based on user confgured + * MRU. The DMA MRU must be of size 2^x */ + chan->dma_mru = chan->mru; + +#if defined(__LINUX__) + chan->dma_mru = aft_valid_mtu(chan->dma_mru); +#else + chan->dma_mru = aft_valid_mtu(chan->dma_mru); +#endif + if (!chan->dma_mru){ + DEBUG_EVENT("%s:%s: Error invalid MTU %d MRU %d\n", + card->devname, + chan->if_name, + chan->mtu,chan->mru); + err= -EINVAL; + goto new_if_error; + } + + if (!chan->hdlc_eng){ + /* If hardware HDLC engine is disabled: + * 1. Configure DMA chains for SINGLE DMA + * 2. Enable Timeslot Synchronization + * 3. Configure Interface for Transparent Operation */ + chan->single_dma_chain=1; + chan->max_tx_bufs=MAX_AFT_DMA_CHAINS; + + if (chan->channelized_cfg) { + dma_per_ch=MAX_AFT_DMA_CHAINS; + }else{ + dma_per_ch= (MAX_AFT_DMA_CHAINS*1500) / chan->mtu; + if (dma_per_ch < MAX_AFT_DMA_CHAINS) { + dma_per_ch=MAX_AFT_DMA_CHAINS; + } + } + + chan->tslot_sync=1; + + if(conf->protocol == WANCONFIG_LIP_ATM){ + chan->tslot_sync=0; + } + + err=aft_transp_if_init(card,chan,conf); + if (err){ + goto new_if_error; + } + + }else{ + /* If hardware HDLC engine is enabled: + * 1. Force Disable DATA MUX option + * just in case user made a mistake + */ + chan->cfg.data_mux=0; + } + DEBUG_EVENT("%s: Data Mux Ctrl :%s\n", + card->devname, + chan->cfg.data_mux?"On":"Off"); + + + + + /*================================================= + * AFT CHANNEL Configuration + * + * Configure the AFT Hardware for this + * logic channel. Enable the above selected + * operation modes. + *================================================*/ + + err=aft_dev_configure(card,chan,conf); + if (err){ + goto new_if_error; + } + + /*Set the actual logic ch number of this chan + *as the dchan. Due to HDLC security issue, the + *HDLC channels are mapped on first TWO logic channels */ + if (chan->common.usedby == TDM_VOICE_DCHAN){ + card->u.aft.cfg.tdmv_dchan=chan->logic_ch_num+1; + } + + /* Configure the DCHAN on LAST Master interface. + * We will use the master interface information, until + * the next interface with the corrent DCHAN info is + * configured. This must be done in order to register + * the DCHAN in zaptel. */ + if (card->u.aft.tdmv_dchan_cfg_on_master && + card->u.aft.cfg.tdmv_dchan){ + int dchan=card->u.aft.cfg.tdmv_dchan; + if (IS_T1_CARD(card)){ + dchan--; + } + if (wan_test_bit(dchan,&conf->active_ch)){ + DEBUG_EVENT("%s: TDMV DCHAN :%d\n", + card->devname,dchan); + card->u.aft.tdmv_chan_ptr=chan; + card->u.aft.cfg.tdmv_dchan=chan->logic_ch_num+1; + } + } + + err=aft_tdm_api_init(card,chan,conf); + if (err){ + goto new_if_error; + } + + DEBUG_EVENT("%s: DMA/Len/Chain :%d/%d/%s\n", + card->devname, + dma_per_ch, + chan->dma_mru, + chan->single_dma_chain?"Off":"On"); + + + err=aft_alloc_rx_dma_buff(card, chan, dma_per_ch); + if (err){ + goto new_if_error; + } + + /*======================================================= + * Interface OS Specific Configuration + *======================================================*/ + + + /* If gateway option is set, then this interface is the + * default gateway on this system. We must know that information + * in case DYNAMIC interface configuration is enabled. + * + * I.E. If the interface is brought down by the driver, the + * default route will also be removed. Once the interface + * is brought back up, we must know to re-astablish the + * default route. + */ + if ((chan->gateway = conf->gateway) == WANOPT_YES){ + DEBUG_EVENT( "%s: Interface %s is set as a gateway.\n", + card->devname,chan->if_name); + } + + /* Get Multicast Information from the user + * FIXME: This is IP relevant, since this is now + * a hardware interface this option should't + * be here */ + chan->mc = conf->mc; + + + /* The network interface "dev" has been passed as + * an argument from the above layer. We must initialize + * it so it can be registered into the kernel. + * + * The "dev" structure is the link between the kernel + * stack and the wanpipe driver. It contains all + * access hooks that kernel uses to communicate to + * the our driver. + * + * For now, just set the "dev" name to the user + * defined name and initialize: + * dev->if_init : function that will be called + * to further initialize + * dev structure on "ifconfig up" + * + * dev->priv : private structure allocated above + * + */ + + + /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + * + * DO NOT PLACE ANY CODE BELOW THAT COULD RETURN ERROR + * + *!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/ + + + /* Only setup the dev pointer once the new_if function has + * finished successfully. DO NOT place any code below that + * can return an error */ +#if defined(__LINUX__) + dev->init = &if_init; +# if defined(CONFIG_PRODUCT_WANPIPE_GENERIC) + if_init(dev); +# endif +#else + chan->common.is_netdev = 1; + chan->common.iface.open = &if_open; + chan->common.iface.close = &if_close; + chan->common.iface.output = &if_send; + chan->common.iface.ioctl = &if_do_ioctl; + chan->common.iface.get_stats = &if_stats; + chan->common.iface.tx_timeout= &if_tx_timeout; + if (wan_iface.attach){ + if (!ifunit(wan_netif_name(dev))){ + wan_iface.attach(dev, NULL, chan->common.is_netdev); + } + }else{ + DEBUG_EVENT("%s: Failed to attach interface %s!\n", + card->devname, wan_netif_name(dev)); + wan_netif_set_priv(dev, NULL); + err = -EINVAL; + goto new_if_error; + } + wan_netif_set_mtu(dev, chan->mtu); +#endif + + /* + * Increment the number of network interfaces + * configured on this card. + */ + wan_atomic_inc(&card->wandev.if_cnt); + if (chan->hdlc_eng){ + ++card->u.aft.security_cnt; + } + + chan->common.state = WAN_CONNECTING; + + DEBUG_EVENT( "\n"); + + return 0; + +new_if_error: + + return err; +} + +static int new_if (wan_device_t* wandev, netdevice_t* dev, wanif_conf_t* conf) +{ + int err=-EINVAL; + sdla_t *card=wandev->private; + int dchan_found=0; + + wan_netif_set_priv(dev, NULL); + + if (IS_E1_CARD(card)) { + DEBUG_TEST("%s: Time Slot Orig 0x%lX Shifted 0x%lX\n", + wan_netif_name(dev), + conf->active_ch, + conf->active_ch<<1); + conf->active_ch = conf->active_ch << 1; + wan_clear_bit(0,&conf->active_ch); + } + + +#ifdef CONFIG_PRODUCT_WANPIPE_TDM_VOICE + if (strcmp(conf->usedby, "TDM_VOICE") == 0) { + if (card->u.aft.cfg.tdmv_span_no){ + + switch(card->wandev.config_id){ + case WANCONFIG_AFT_ANALOG: + err = wp_tdmv_remora_init(&card->tdmv_iface); + break; + default: + err = wp_tdmv_te1_init(&card->tdmv_iface); + break; + } + if (err){ + DEBUG_EVENT("%s: Error: Failed to initialize tdmv functions!\n", + card->devname); + return -EINVAL; + } + + + WAN_TDMV_CALL(create, (card, &card->u.aft.cfg), err); + if (err){ + DEBUG_EVENT("%s: Error: Failed to create tdmv span!\n", + card->devname); + return err; + } + } + } +#endif + + + if (strcmp(conf->usedby, "TDM_VOICE") == 0 || + strcmp(conf->usedby, "TDM_VOICE_API") == 0){ + + int i=0,master_if=-1; + u32 active_ch=conf->active_ch; + + if (card->wandev.fe_iface.active_map){ + conf->active_ch = card->wandev.fe_iface.active_map(&card->fe); + active_ch=conf->active_ch; + } + + DEBUG_TEST("%s: TDM VOICE: TESTING FOR DCHAN CHAN in 0x%08X Timeslots=%i CFG DCHAN=%i\n", + card->devname, active_ch, card->u.aft.num_of_time_slots, + card->u.aft.cfg.tdmv_dchan); + + for (i=card->u.aft.num_of_time_slots-1;i>=0;i--){ + if (wan_test_bit(i,&active_ch)){ + + if (card->u.aft.cfg.tdmv_dchan){ + int dchan=card->u.aft.cfg.tdmv_dchan; + if (IS_T1_CARD(card)){ + dchan--; + } + if (dchan == i){ + dchan_found=1; + continue; + } + } + + /* Find the TOP timeslot. This timeslot will be + * considered MASTER since it is the last timeslot + * to rx data from the T1 line */ + if (master_if < 0){ + master_if=i; + } + } + } + + if (card->u.aft.cfg.tdmv_dchan && !dchan_found){ + /* We configured for dchan however, this interface + * was not configued with the DCHAN timeslot. + * It IS now possible that another interface has + * this time slot */ + card->u.aft.tdmv_dchan_cfg_on_master=1; + } + + + for (i=0;iu.aft.num_of_time_slots;i++){ + if (wan_test_bit(i,&active_ch)){ + conf->active_ch=0; + conf->u.aft.tdmv_master_if=0; + wan_set_bit(i,&conf->active_ch); + if (i==master_if){ + conf->u.aft.tdmv_master_if=1; + } + err=new_if_private(wandev,dev,conf,1); + if (err){ + break; + } + } + } + +#if defined(CONFIG_PRODUCT_WANPIPE_TDM_VOICE) + if (!err && card->u.aft.tdmv_zaptel_cfg){ + WAN_TDMV_CALL(software_init, (&card->wan_tdmv), err); + } +#endif + + }else{ + err=new_if_private(wandev,dev,conf,0); + } + + if (err && wan_netif_priv(dev)){ + del_if(wandev,dev); + if (wan_netif_priv(dev)){ + wan_free(wan_netif_priv(dev)); + wan_netif_set_priv(dev, NULL); + } + } + + return err; +} + + +/*============================================================================ + * del_if - Delete logical channel. + * + * @wandev: Wanpipe private device pointer + * @dev: Netowrk interface pointer + * + * This function is called by ROUTER_DELIF ioctl call + * to deallocate the network interface. + * + * The network interface and the private structure are + * about to be deallocated by the upper layer. + * We have to clean and deallocate any allocated memory. + * + * NOTE: DO NOT deallocate dev->priv here! It will be + * done by the upper layer. + * + */ +static int del_if_private (wan_device_t* wandev, netdevice_t* dev) +{ + private_area_t* chan = wan_netif_priv(dev); + sdla_t* card; + netskb_t *skb; + wan_smp_flag_t flags; + + if (!chan){ + DEBUG_EVENT("%s: Critical Error del_if_private() chan=NULL!\n", + wan_netif_name(dev)); + return 0; + } + + card = chan->card; + if (!card){ + DEBUG_EVENT("%s: Critical Error del_if_private() chan=NULL!\n", + wan_netif_name(dev)); + return 0; + } + + wan_spin_lock_irq(&card->wandev.lock,&flags); + aft_dev_unconfigure(card,chan); + wan_spin_unlock_irq(&card->wandev.lock,&flags); + + WAN_TASKLET_KILL(&chan->common.bh_task); + + if (chan->common.usedby == API || chan->common.usedby == TDM_VOICE_API){ + wan_unreg_api(chan, card->devname); + + } + + if (aft_tdm_api_free(card,chan)) { + DEBUG_EVENT("%s: Error: Failed to del iface: TDM API Device in use!\n", + chan->if_name); + return -EBUSY; + } + + wan_spin_lock_irq(&card->wandev.lock,&flags); + aft_tdmv_if_free(card,chan); + wan_spin_unlock_irq(&card->wandev.lock,&flags); + + protocol_shutdown(card,dev); + +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) + if (wan_iface.detach){ + wan_iface.detach(dev, chan->common.is_netdev); + } +#endif + + /* We must set used by to API because + * the free_tx and free_rx are not allowed + * for TDM_VOICE mode in regular operation */ + + chan->common.usedby = API; + + wan_spin_lock_irq(&card->wandev.lock,&flags); + + aft_free_tx_descriptors(chan); + aft_free_rx_descriptors(chan); + + while ((skb=wan_skb_dequeue(&chan->wp_rx_free_list)) != NULL){ + wan_skb_free(skb); + } + + while ((skb=wan_skb_dequeue(&chan->wp_rx_complete_list)) != NULL){ + wan_skb_free(skb); + } + + while ((skb=wan_skb_dequeue(&chan->wp_rx_stack_complete_list)) != NULL){ + wan_skb_free(skb); + } + + while ((skb=wan_skb_dequeue(&chan->wp_rx_zap_complete_list)) != NULL){ + wan_skb_free(skb); + } + + while ((skb=wan_skb_dequeue(&chan->wp_tx_pending_list)) != NULL){ + wan_skb_free(skb); + } + + if (chan->tx_idle_skb){ + wan_skb_free(chan->tx_idle_skb); + chan->tx_idle_skb=NULL; + } + + if (chan->tx_realign_buf){ + wan_free(chan->tx_realign_buf); + chan->tx_realign_buf=NULL; + } + + if (chan->tx_ss7_realign_buf){ + wan_free(chan->tx_ss7_realign_buf); + chan->tx_ss7_realign_buf=NULL; + } + + if (card->u.aft.tdmv_chan_ptr == chan){ + card->u.aft.tdmv_chan_ptr=NULL; + } + + wan_spin_unlock_irq(&card->wandev.lock,&flags); + + /* Delete interface name from proc fs. */ +#if 0 + wanrouter_proc_delete_interface(wandev, chan->if_name); +#endif + + /* Decrement the number of network interfaces + * configured on this card. + */ + wan_atomic_dec(&card->wandev.if_cnt); + if (chan->hdlc_eng){ + --card->u.aft.security_cnt; + } + + DEBUG_SUB_MEM(sizeof(private_area_t)); + return 0; +} + +static int del_if (wan_device_t* wandev, netdevice_t* dev) +{ + private_area_t* chan=wan_netif_priv(dev); + + if (!chan){ + DEBUG_EVENT("%s: Critical Error del_if() chan=NULL!\n", + wan_netif_name(dev)); + return 0; + } + + if (!chan->card){ + DEBUG_EVENT("%s: Critical Error del_if() chan=NULL!\n", + wan_netif_name(dev)); + return 0; + } + + if (chan->channelized_cfg) { + + sdla_t *card=chan->card; + wan_smp_flag_t flags; + +#if defined(CONFIG_PRODUCT_WANPIPE_TDM_VOICE) + if (chan->tdmv_zaptel_cfg) { + sdla_t *card=chan->card; + int err; + WAN_TDMV_CALL(running, (card), err); + if (err){ + return -EBUSY; + } + } +#endif + + /* Disable the TDMV Interrupt first, before + * shutting down all TDMV channels */ + wan_spin_lock_irq(&card->wandev.lock,&flags); + + aft_tdm_intr_ctrl(card,0); + aft_fifo_intr_ctrl(card, 0); + +#if defined(CONFIG_PRODUCT_WANPIPE_TDM_VOICE) + if (card->wan_tdmv.sc) { + int err; + WAN_TDMV_CALL(state, (card, WAN_DISCONNECTED), err); + } +#endif + wan_spin_unlock_irq(&card->wandev.lock,&flags); + + while(chan){ + int err=del_if_private(wandev,dev); + if (err) { + return err; + } + if (chan->next) { + wan_netif_set_priv(dev, chan->next); + wan_free(chan); + chan = wan_netif_priv(dev); + } else { + /* Leave the last chan dev + * in dev->priv. It will get + * deallocated normally */ + break; + } + } + +#if defined(CONFIG_PRODUCT_WANPIPE_TDM_VOICE) + if (card->wan_tdmv.sc) { + aft_tdmv_free(card); + } +#endif + return 0; + } else { + return del_if_private(wandev,dev); + } +} + + +/**SECTION*********************************************************** + * + * KERNEL Device Entry Interfaces + * + ********************************************************************/ + + + +/*============================================================================ + * if_init - Initialize Linux network interface. + * + * @dev: Network interface pointer + * + * During "ifconfig up" the upper layer calls this function + * to initialize dev access pointers. Such as transmit, + * stats and header. + * + * It is called only once for each interface, + * during Linux network interface registration. + * + * Returning anything but zero will fail interface + * registration. + */ +#if defined(__LINUX__) +static int if_init (netdevice_t* dev) +{ + private_area_t* chan = wan_netif_priv(dev); + sdla_t* card = chan->card; + wan_device_t* wandev = &card->wandev; +#if defined(CONFIG_PRODUCT_WANPIPE_GENERIC) + hdlc_device* hdlc; +#endif + + /* Initialize device driver entry points */ + dev->open = &if_open; + dev->stop = &if_close; +#if defined(CONFIG_PRODUCT_WANPIPE_GENERIC) + hdlc = dev_to_hdlc(dev); + hdlc->xmit = if_send; +#else + dev->hard_start_xmit = &if_send; +#endif + dev->get_stats = &if_stats; + +#if 0 + dev->tx_timeout = &if_tx_timeout; + dev->watchdog_timeo = 2*HZ; +#else + if (chan->common.usedby == TDM_VOICE || + chan->common.usedby == TDM_VOICE_DCHAN || + chan->common.usedby == TDM_VOICE_API){ + dev->tx_timeout = NULL; + }else{ + dev->tx_timeout = &if_tx_timeout; + } + dev->watchdog_timeo = 2*HZ; + +#endif + dev->do_ioctl = if_do_ioctl; + + if (chan->common.usedby == BRIDGE || + chan->common.usedby == BRIDGE_NODE){ + + /* Setup the interface for Bridging */ + int hw_addr=0; + ether_setup(dev); + + /* Use a random number to generate the MAC address */ + memcpy(dev->dev_addr, "\xFE\xFC\x00\x00\x00\x00", 6); + get_random_bytes(&hw_addr, sizeof(hw_addr)); + *(int *)(dev->dev_addr + 2) += hw_addr; + + }else{ + + dev->flags |= IFF_POINTOPOINT; + dev->flags |= IFF_NOARP; + dev->type = ARPHRD_PPP; + dev->mtu = chan->mtu; + dev->hard_header_len = 0; + dev->hard_header = NULL; + dev->rebuild_header = NULL; + + if (chan->common.usedby == API || chan->common.usedby == STACK){ + if (chan->hdlc_eng) { + dev->mtu = chan->dma_mru+sizeof(api_tx_hdr_t); + }else{ + dev->mtu = chan->mtu+sizeof(api_tx_hdr_t); + } + } + + /* Enable Mulitcasting if user selected */ + if (chan->mc == WANOPT_YES){ + dev->flags |= IFF_MULTICAST; + } + + if (chan->true_if_encoding){ + DEBUG_EVENT("%s: Setting IF Type to Broadcast\n",chan->if_name); + dev->type = ARPHRD_PPP; /* This breaks the tcpdump */ + dev->flags &= ~IFF_POINTOPOINT; + dev->flags |= IFF_BROADCAST; + }else{ + dev->type = ARPHRD_PPP; + } + } + + /* Initialize hardware parameters */ + dev->irq = wandev->irq; + dev->dma = wandev->dma; + dev->base_addr = wandev->ioport; + card->hw_iface.getcfg(card->hw, SDLA_MEMBASE, &dev->mem_start); + card->hw_iface.getcfg(card->hw, SDLA_MEMEND, &dev->mem_end); + + /* Set transmit buffer queue length + * If too low packets will not be retransmitted + * by stack. + */ + dev->tx_queue_len = 100; + return 0; +} +#endif + +/*============================================================================ + * if_open - Open network interface. + * + * @dev: Network device pointer + * + * On ifconfig up, this function gets called in order + * to initialize and configure the private area. + * Driver should be configured to send and receive data. + * + * This functions starts a timer that will call + * frmw_config() function. This function must be called + * because the IP addresses could have been changed + * for this interface. + * + * Return 0 if O.k. or errno. + */ +static int if_open (netdevice_t* dev) +{ + private_area_t* chan = wan_netif_priv(dev); + sdla_t* card = chan->card; + wan_smp_flag_t flags; + +#if defined(__LINUX__) + /* Only one open per interface is allowed */ + if (open_dev_check(dev)){ + DEBUG_EVENT("%s: Open dev check failed!\n", + wan_netif_name(dev)); + return -EBUSY; + } +#endif + + if (wan_test_bit(CARD_DOWN,&card->wandev.critical)){ + DEBUG_EVENT("%s:%s: Card down: Failed to open interface!\n", + card->devname,chan->if_name); + return -EINVAL; + } + + + /* Initialize the router start time. + * Used by wanpipemon debugger to indicate + * how long has the interface been up */ + wan_getcurrenttime(&chan->router_start_time, NULL); + + WAN_NETIF_START_QUEUE(dev); + WAN_NETIF_CARRIER_OFF(dev); + + /* If FRONT End is down, it means that the DMA + * is disabled. In this case don't try to + * reset fifo. Let the enable_data_error_intr() + * function do this, after front end has come up */ + + wan_spin_lock_irq(&card->wandev.lock,&flags); + + aft_dev_open(card, chan); + + if (card->wandev.state == WAN_CONNECTED){ + set_chan_state(card, dev, WAN_CONNECTED); + } + + if (chan->cfg.ss7_enable){ + aft_clear_ss7_force_rx(card,chan); + } + wan_spin_unlock_irq(&card->wandev.lock,&flags); + + + /* Increment the module usage count */ + wanpipe_open(card); + + + if (card->wandev.config_id == WANCONFIG_AFT_ANALOG) { + wan_spin_lock_irq(&card->wandev.lock,&flags); + card->fe.fe_status = FE_CONNECTED; + handle_front_end_state(card); + wan_spin_unlock_irq(&card->wandev.lock,&flags); + } + + /* Wait for the front end interrupt + * before enabling the card */ + return 0; +} + +/*============================================================================ + * if_close - Close network interface. + * + * @dev: Network device pointer + * + * On ifconfig down, this function gets called in order + * to cleanup interace private area. + * + * IMPORTANT: + * + * No deallocation or unconfiguration should ever occur in this + * function, because the interface can come back up + * (via ifconfig up). + * + * Furthermore, in dynamic interfacace configuration mode, the + * interface will come up and down to reflect the protocol state. + * + * Any deallocation and cleanup can occur in del_if() + * function. That function is called before the dev interface + * itself is deallocated. + * + * Thus, we should only stop the net queue and decrement + * the wanpipe usage counter via wanpipe_close() function. + */ + +static int if_close (netdevice_t* dev) +{ + private_area_t* chan = wan_netif_priv(dev); + sdla_t* card = chan->card; + wan_smp_flag_t smp_flags; + + WAN_NETIF_STOP_QUEUE(dev); + +#if defined(LINUX_2_1) + dev->start=0; +#endif + protocol_stop(card,dev); + + chan->common.state = WAN_DISCONNECTED; + + + wan_spin_lock_irq(&card->wandev.lock,&smp_flags); + aft_dev_close(card,chan); + wan_spin_unlock_irq(&card->wandev.lock,&smp_flags); + + wanpipe_close(card); + return 0; +} + + +/*============================================================= + * disable_comm - Main shutdown function + * + * @card: Wanpipe device pointer + * + * The command 'wanrouter stop' has been called + * and the whole wanpipe device is going down. + * This is the last function called to disable + * all comunications and deallocate any memory + * that is still allocated. + * + * o Disable communications, turn off interrupts + * o Deallocate memory used, if any + * o Unconfigure TE1 card + */ + +static void disable_comm (sdla_t *card) +{ + wan_smp_flag_t flags,flags1; + int used_cnt; + + wan_spin_lock_irq(&card->wandev.lock,&flags); + + wan_set_bit(CARD_DOWN,&card->wandev.critical); + + /* Disable DMA ENGINE before we perform + * core reset. Otherwise, we will receive + * rx fifo errors on subsequent resetart. */ + disable_data_error_intr(card,DEVICE_DOWN); + + wan_spin_unlock_irq(&card->wandev.lock,&flags); + + aft_chip_unconfigure(card); + + WP_DELAY(10); + + card->hw_iface.getcfg(card->hw, SDLA_USEDCNT, &used_cnt); + + card->hw_iface.hw_lock(card->hw,&flags1); + wan_spin_lock_irq(&card->wandev.lock,&flags); + aft_hwdev[card->wandev.card_type].aft_led_ctrl(card, WAN_AFT_RED, 0,WAN_AFT_ON); + aft_hwdev[card->wandev.card_type].aft_led_ctrl(card, WAN_AFT_GREEN, 0, WAN_AFT_ON); + wan_spin_unlock_irq(&card->wandev.lock,&flags); + card->hw_iface.hw_unlock(card->hw,&flags1); + + if (used_cnt<=1){ + DEBUG_EVENT("%s: Global Chip Shutdown Usage=%d\n", + card->devname,used_cnt); + + wan_spin_lock_irq(&card->wandev.lock,&flags); + aft_global_chip_disable(card); + wan_spin_unlock_irq(&card->wandev.lock,&flags); + } + + +#if defined(WAN_DEBUG_MEM) + DEBUG_EVENT("%s: Total Mem %d\n",__FUNCTION__,wan_atomic_read(&wan_debug_mem)); +#endif + + return; +} + + + +/*============================================================================ + * if_tx_timeout + * + * Kernel networking stack calls this function in case + * the interface has been stopped for TX_TIMEOUT seconds. + * + * This would occur if we lost TX interrupts or the + * card has stopped working for some reason. + * + * Handle transmit timeout event from netif watchdog + */ +static void if_tx_timeout (netdevice_t *dev) +{ + private_area_t* chan = wan_netif_priv(dev); + private_area_t* ch_ptr; + sdla_t *card = chan->card; + unsigned int cur_dma_ptr; + u32 reg,dma_ram_desc; + wan_smp_flag_t smp_flags; + + /* If our device stays busy for at least 5 seconds then we will + * kick start the device by making dev->tbusy = 0. We expect + * that our device never stays busy more than 5 seconds. So this + * is only used as a last resort. + */ + + ++chan->if_stats.collisions; + + DEBUG_EVENT( "%s: Transmit timed out on %s\n", + card->devname, + wan_netif_name(dev)); + + dma_ram_desc=chan->logic_ch_num*4+AFT_PORT_REG(card,AFT_DMA_CHAIN_RAM_BASE_REG); + card->hw_iface.bus_read_4(card->hw,dma_ram_desc,®); + cur_dma_ptr=aft_dmachain_get_tx_dma_addr(reg); + + DEBUG_EVENT("%s: Chain TxPend=%d, TxCur=%d, TxPend=%d HwCur=%d TxA=%d TxC=%ld\n", + chan->if_name, + wan_test_bit(TX_INTR_PENDING,&chan->dma_chain_status), + chan->tx_chain_indx, + chan->tx_pending_chain_indx, + cur_dma_ptr, + chan->tx_attempts, + chan->if_stats.tx_packets); + + if (wan_test_bit(TX_DMA_BUSY,&chan->dma_status)){ + wan_clear_bit(TX_DMA_BUSY,&chan->dma_status); + } + + wan_netif_set_ticks(dev, SYSTEM_TICKS); + +#ifdef AFT_TX_FIFO_DEBUG + aft_list_tx_descriptors(chan); +#endif + + wan_spin_lock_irq(&card->wandev.lock, &smp_flags); + if (chan->channelized_cfg){ + for (ch_ptr=chan;ch_ptr;ch_ptr=ch_ptr->next){ + aft_tx_fifo_under_recover(card,chan); + } + }else{ + aft_tx_fifo_under_recover(card,chan); + } + wan_spin_unlock_irq(&card->wandev.lock, &smp_flags); + +#ifdef AFT_TX_FIFO_DEBUG + aft_list_tx_descriptors(chan); +#endif + + WAN_NETIF_WAKE_QUEUE(dev); + if (chan->common.usedby == API){ + wan_wakeup_api(chan); + }else if (chan->common.usedby == STACK){ + wanpipe_lip_kick(chan,0); + }else if (chan->common.usedby == TDM_VOICE_DCHAN){ +#ifdef AFT_TDM_API_SUPPORT + if (is_tdm_api(chan,&chan->wp_tdm_api_dev)){ + wanpipe_tdm_api_kick(&chan->wp_tdm_api_dev); + } +#endif + } +} + + +/*============================================================================ + * if_send - Send a packet on a network interface. + * + * @dev: Network interface pointer + * @skb: Packet obtained from the stack or API + * that should be sent out the port. + * + * o Mark interface as stopped + * (marks start of the transmission) to indicate + * to the stack that the interface is busy. + * + * o Check link state. + * If link is not up, then drop the packet. + * + * o Copy the tx packet into the protocol tx buffers on + * the adapter. + * + * o If tx successful: + * Free the skb buffer and mark interface as running + * and return 0. + * + * o If tx failed, busy: + * Keep interface marked as busy + * Do not free skb buffer + * Enable Tx interrupt (which will tell the stack + * that interace is not busy) + * Return a non-zero value to tell the stack + * that the tx should be retried. + * + * Return: 0 complete (socket buffer must be freed) + * non-0 packet may be re-transmitted + * + */ +#if defined(__LINUX__) +static int if_send (netskb_t* skb, netdevice_t* dev) +#else +static int if_send(netdevice_t *dev, netskb_t *skb, struct sockaddr *dst,struct rtentry *rt) +#endif +{ + private_area_t *chan = wan_netif_priv(dev); + sdla_t *card = chan->card; + int err; + wan_smp_flag_t smp_flags; + + /* Mark interface as busy. The kernel will not + * attempt to send any more packets until we clear + * this condition */ + + if (skb == NULL){ + /* This should never happen. Just a sanity check. + */ + DEBUG_EVENT( "%s: interface %s got kicked!\n", + card->devname, + wan_netif_name(dev)); + + WAN_NETIF_WAKE_QUEUE(dev); + return 0; + } + + /* Non 2.4 kernels used to call if_send() + * after TX_TIMEOUT seconds have passed of interface + * being busy. Same as if_tx_timeout() in 2.4 kernels */ +#if defined(LINUX_2_1) + if (dev->tbusy){ + + /* If our device stays busy for at least 5 seconds then we will + * kick start the device by making dev->tbusy = 0. We expect + * that our device never stays busy more than 5 seconds. So this + * is only used as a last resort. + */ + ++chan->if_stats.collisions; + if((SYSTEM_TICKS - chan->tick_counter) < (5 * HZ)) { + return 1; + } + + if_tx_timeout(dev); + } +#endif + err=0; + + if (chan->common.state != WAN_CONNECTED){ +#if 1 + WAN_NETIF_STOP_QUEUE(dev); + wan_netif_set_ticks(dev, SYSTEM_TICKS); + ++chan->if_stats.tx_carrier_errors; + return 1; +#else + ++chan->if_stats.tx_carrier_errors; + wan_skb_free(skb); + WAN_NETIF_START_QUEUE(dev); + err=0; + goto if_send_exit_crit; +#endif + } + + if (chan->channelized_cfg) { + + private_area_t *top_chan=wan_netif_priv(chan->common.dev); + + DEBUG_TEST("%s:%ld Prev: Zaptel HDLC Tt TDMV_DCHAN=%i\n", + chan->if_name,chan->logic_ch_num, + card->u.aft.cfg.tdmv_dchan-1); + + if (!card->u.aft.cfg.tdmv_dchan || card->u.aft.cfg.tdmv_dchan>32){ + + DEBUG_EVENT("%s: DCHAN TX No DCHAN Configured!\n", + card->devname); + + wan_skb_free(skb); + WAN_NETIF_START_QUEUE(dev); + err=0; + goto if_send_exit_crit; + } + + chan=(private_area_t*)card->u.aft.dev_to_ch_map[card->u.aft.cfg.tdmv_dchan-1]; + if (!chan){ + DEBUG_EVENT("%s: DCHAN TX No DCHAN Configured by not preset!\n", + card->devname); + wan_skb_free(skb); + WAN_NETIF_START_QUEUE(dev); + err=0; + goto if_send_exit_crit; + } + + if (!chan->hdlc_eng){ + wan_skb_free(skb); + WAN_NETIF_START_QUEUE(dev); + err=0; + goto if_send_exit_crit; + } + +#if 0 + if (chan->common.usedby == STACK){ + wan_smp_flag_t flags; + netskb_t *new_skb; + + wan_capture_trace_packet(chan->card, &chan->trace_info, + skb,TRC_OUTGOING_FRM); + + new_skb=NULL; +#if 0 + + new_skb=skb_copy(skb,GFP_ATOMIC); + if (new_skb){ + wan_spin_lock_irq(&card->wandev.lock,&flags); + wan_skb_unlink(new_skb); + wan_skb_set_csum(new_skb,1); + wan_skb_queue_tail(&chan->wp_rx_stack_complete_list,new_skb); + wan_spin_unlock_irq(&card->wandev.lock,&flags); + } +#else + wan_spin_lock_irq(&card->wandev.lock,&flags); + wan_skb_unlink(skb); + wan_skb_set_csum(skb,1); + wan_skb_queue_tail(&chan->wp_rx_stack_complete_list,skb); + wan_spin_unlock_irq(&card->wandev.lock,&flags); + + WAN_TASKLET_SCHEDULE((&chan->common.bh_task)); + + DEBUG_TEST("%s: IF_SEND: Passing packet up the STACK!\n", + chan->if_name); + err=0; + goto if_send_exit_crit; +#endif + + } +#endif + wan_capture_trace_packet(chan->card, &top_chan->trace_info, + skb,TRC_OUTGOING_FRM); + + DEBUG_TEST("%s:%ld Zaptel HDLC Tt TDMV_DCHAN=%i\n", + chan->if_name,chan->logic_ch_num, + card->u.aft.cfg.tdmv_dchan-1); + } + + /* For TDM_VOICE_API no tx is supported in if_send */ + if (chan->common.usedby == TDM_VOICE_API){ + ++chan->if_stats.tx_errors; + WAN_NETIF_START_QUEUE(dev); + err=0; + goto if_send_exit_crit; + } + + if (chan->common.usedby == API){ + + if (sizeof(api_tx_hdr_t) >= wan_skb_len(skb)){ + wan_skb_free(skb); + ++chan->if_stats.tx_errors; + WAN_NETIF_START_QUEUE(dev); + err=0; + goto if_send_exit_crit; + } + + if (chan->cfg.ss7_enable){ + err=aft_ss7_tx_mangle(card,chan,skb); + if (err){ + wan_skb_free(skb); + ++chan->if_stats.tx_errors; + WAN_NETIF_START_QUEUE(dev); + err=0; + goto if_send_exit_crit; + } + }else{ + wan_skb_pull(skb,sizeof(api_tx_hdr_t)); + } + + } + +#if 0 + /* NC: + * This is support for SS7/ZAPTEL Converter stuff + * as of right now its not being used + * NOTE: This can break HW HDLC DCHAN support on some machines + * because we cannot use csum value in skb buffer. + */ + if (card->u.aft.cfg.tdmv_dchan && + card->u.aft.cfg.tdmv_dchan == (chan->logic_ch_num+1)){ + if (wan_skb_csum(skb)){ + wan_smp_flag_t flags; + + DEBUG_TEST("%s: IF_SEND: Rx ZAPTEL bound packet!\n", + chan->if_name); + + wan_spin_lock_irq(&card->wandev.lock,&flags); + wan_skb_unlink(skb); + wan_skb_set_csum(skb,0); + wan_skb_queue_tail(&chan->wp_rx_zap_complete_list,skb); + wan_spin_unlock_irq(&card->wandev.lock,&flags); + + WAN_TASKLET_SCHEDULE((&chan->common.bh_task)); + err=0; + goto if_send_exit_crit; + } + + + } +#endif + + if (!chan->hdlc_eng && chan->tslot_sync){ + if (wan_skb_len(skb)%chan->num_of_time_slots){ + if (WAN_NET_RATELIMIT()){ + DEBUG_EVENT("%s:%s: Tx Error pkt len(%d) not multiple of timeslots(%d)\n", + card->devname, + chan->if_name, + wan_skb_len(skb), + chan->num_of_time_slots); + } + wan_skb_free(skb); + ++chan->if_stats.tx_errors; + WAN_NETIF_START_QUEUE(dev); + err=0; + goto if_send_exit_crit; + } + } + + if (!chan->hdlc_eng && !chan->lip_atm && (wan_skb_len(skb)%4)){ + if (WAN_NET_RATELIMIT()){ + DEBUG_EVENT("%s: Tx Error: Tx Length %i is not 32bit divisible\n", + chan->if_name,wan_skb_len(skb)); + } + wan_skb_free(skb); + ++chan->if_stats.tx_errors; + WAN_NETIF_START_QUEUE(dev); + err=0; + goto if_send_exit_crit; + } + + wan_spin_lock_irq(&card->wandev.lock, &smp_flags); + + if (wan_skb_queue_len(&chan->wp_tx_pending_list) > chan->max_tx_bufs){ + WAN_NETIF_STOP_QUEUE(dev); + aft_dma_tx(card,chan); + wan_spin_unlock_irq(&card->wandev.lock, &smp_flags); + return 1; + + } + + wan_skb_unlink(skb); + + wan_skb_queue_tail(&chan->wp_tx_pending_list,skb); + + if(!chan->lip_atm){ + aft_dma_tx(card,chan); /*not needed for LIP_ATM!!*/ + } + + wan_netif_set_ticks(dev, SYSTEM_TICKS); + WAN_NETIF_START_QUEUE(dev); + err=0; + wan_spin_unlock_irq(&card->wandev.lock, &smp_flags); + +if_send_exit_crit: + + return err; +} + + +/*============================================================================ + * if_stats + * + * Used by /proc/net/dev and ifconfig to obtain interface + * statistics. + * + * Return a pointer to struct net_device_stats. + */ +static struct net_device_stats gstats; +static struct net_device_stats* if_stats (netdevice_t* dev) +{ + private_area_t* chan; + + if ((chan=wan_netif_priv(dev)) == NULL) + return &gstats; + + return &chan->if_stats; +} + +/*======================================================================== + * + * if_do_ioctl - Ioctl handler for fr + * + * @dev: Device subject to ioctl + * @ifr: Interface request block from the user + * @cmd: Command that is being issued + * + * This function handles the ioctls that may be issued by the user + * to control or debug the protocol or hardware . + * + * It does both busy and security checks. + * This function is intended to be wrapped by callers who wish to + * add additional ioctl calls of their own. + * + * Used by: SNMP Mibs + * wanpipemon debugger + * + */ +static int if_do_ioctl(netdevice_t *dev, struct ifreq *ifr, int cmd) +{ + private_area_t* chan= (private_area_t*)wan_netif_priv(dev); + sdla_t *card; +#if defined(__LINUX__) + wan_smp_flag_t smp_flags; +#endif + wan_udp_pkt_t *wan_udp_pkt; + int err=-EOPNOTSUPP; + + if (!chan || !chan->card){ + DEBUG_EVENT("%s:%d: No Chan of card ptr\n", + __FUNCTION__,__LINE__); + return -ENODEV; + } + card=chan->card; + + if (wan_test_bit(CARD_DOWN,&card->wandev.critical)){ + DEBUG_EVENT("%s: Card down: Ignoring Ioctl call!\n", + card->devname); + return -ENODEV; + } + + switch(cmd) + { +#if defined(__LINUX__) + case SIOC_WANPIPE_BIND_SK: + if (!ifr){ + err= -EINVAL; + break; + } + + wan_spin_lock_irq(&card->wandev.lock, &smp_flags); + err=wan_bind_api_to_svc(chan,ifr->ifr_data); + chan->if_stats.rx_dropped=0; + if (!chan->hdlc_eng){ + chan->if_stats.tx_carrier_errors=0; + } + wan_spin_unlock_irq(&card->wandev.lock, &smp_flags); + break; + + case SIOC_WANPIPE_UNBIND_SK: + if (!ifr){ + err= -EINVAL; + break; + } + + wan_spin_lock_irq(&card->wandev.lock, &smp_flags); + err=wan_unbind_api_from_svc(chan,ifr->ifr_data); + wan_spin_unlock_irq(&card->wandev.lock, &smp_flags); + + break; + + case SIOC_WANPIPE_CHECK_TX: + case SIOC_ANNEXG_CHECK_TX: + err=0; + break; + + case SIOC_WANPIPE_DEV_STATE: + err = chan->common.state; + break; + + case SIOC_ANNEXG_KICK: + err=0; + break; + + case SIOC_AFT_SS7_FORCE_RX: + wan_spin_lock_irq(&card->wandev.lock, &smp_flags); + aft_set_ss7_force_rx(card,chan); + wan_spin_unlock_irq(&card->wandev.lock, &smp_flags); + break; + + case SIOC_WANPIPE_API: + DEBUG_TEST("%s: WANPIPE API IOCTL!\n", card->devname); + err = wan_aft_api_ioctl(card,chan,ifr->ifr_data); + break; +#endif + case SIOC_WAN_DEVEL_IOCTL: + err = aft_devel_ioctl(card, ifr); + break; + + case SIOC_AFT_CUSTOMER_ID: + err=0; + break; + +#if defined(__LINUX__) + case SIOC_WANPIPE_GET_DEVICE_CONFIG_ID: + err=card->wandev.config_id; + break; +#endif + case SIOC_WANPIPE_PIPEMON: + + NET_ADMIN_CHECK(); + + if (wan_atomic_read(&chan->udp_pkt_len) != 0){ + return -EBUSY; + } + + wan_atomic_set(&chan->udp_pkt_len,MAX_LGTH_UDP_MGNT_PKT); + + /* For performance reasons test the critical + * here before spin lock */ + if (wan_test_bit(0,&card->in_isr)){ + wan_atomic_set(&chan->udp_pkt_len,0); + return -EBUSY; + } + + + wan_udp_pkt=(wan_udp_pkt_t*)chan->udp_pkt_data; + if (WAN_COPY_FROM_USER( + &wan_udp_pkt->wan_udp_hdr, + ifr->ifr_data, + sizeof(wan_udp_hdr_t))){ + wan_atomic_set(&chan->udp_pkt_len,0); + return -EFAULT; + } + + /* We have to check here again because we don't know + * what happened during spin_lock */ + if (wan_test_bit(0,&card->in_isr)) { + DEBUG_EVENT( "%s:%s Pipemon command failed, Driver busy: try again.\n", + card->devname, + wan_netif_name(dev)); + wan_atomic_set(&chan->udp_pkt_len,0); + return -EBUSY; + } + + process_udp_mgmt_pkt(card,dev,chan,1); + + /* This area will still be critical to other + * PIPEMON commands due to udp_pkt_len + * thus we can release the irq */ + + if (wan_atomic_read(&chan->udp_pkt_len) > sizeof(wan_udp_pkt_t)){ + DEBUG_EVENT( "%s: Error: Pipemon buf too bit on the way up! %d\n", + card->devname,wan_atomic_read(&chan->udp_pkt_len)); + wan_atomic_set(&chan->udp_pkt_len,0); + return -EINVAL; + } + + if (WAN_COPY_TO_USER( + ifr->ifr_data, + &wan_udp_pkt->wan_udp_hdr, + sizeof(wan_udp_hdr_t))){ + wan_atomic_set(&chan->udp_pkt_len,0); + return -EFAULT; + } + + wan_atomic_set(&chan->udp_pkt_len,0); + return 0; + +#if 0 + case SIOC_WAN_EC_IOCTL: + if (wan_test_and_set_bit(CARD_HW_EC,&card->wandev.critical)){ + DEBUG_EVENT("%s: Error: EC IOCTL Reentrant!\n", + card->devname); + return -EBUSY; + } + if (card->wandev.ec){ + err = wan_ec_ioctl(card->wandev.ec, ifr, card); + }else{ + err = -EINVAL; + } + wan_clear_bit(CARD_HW_EC,&card->wandev.critical); + break; +#endif + +/* + case SIOC_WAN_FE_IOCTL: + DEBUG_TEST("%s: Command %x not supported!\n", + card->devname,cmd); + return -EOPNOTSUPP; + break; +*/ + default: +#ifndef WANPIPE_GENERIC + DEBUG_TEST("%s: Command %x not supported!\n", + card->devname,cmd); + return -EOPNOTSUPP; +#else + if (card->wandev.ioctl){ + err = card->wandev.hdlc_ioctl(card, dev, ifr, cmd); + } +#endif + } + + return err; +} + + +/**SECTION********************************************************** + * + * FIRMWARE Specific Interface Functions + * + *******************************************************************/ + + +#define FIFO_RESET_TIMEOUT_CNT 1000 +#define FIFO_RESET_TIMEOUT_US 10 +static int aft_init_rx_dev_fifo(sdla_t *card, private_area_t *chan, unsigned char wait) +{ + + u32 reg; + u32 dma_descr; + u8 timeout=1; + u16 i; + unsigned int cur_dma_ptr; + u32 dma_ram_desc; + + /* Clean RX DMA fifo */ + + if (chan->single_dma_chain){ + dma_descr=(chan->logic_ch_num<<4) + AFT_PORT_REG(card,AFT_RX_DMA_HI_DESCR_BASE_REG); + + dma_ram_desc=chan->logic_ch_num*4 + AFT_PORT_REG(card,AFT_DMA_CHAIN_RAM_BASE_REG); + card->hw_iface.bus_read_4(card->hw,dma_ram_desc,®); + aft_dmachain_set_rx_dma_addr(®,0); + card->hw_iface.bus_write_4(card->hw,dma_ram_desc,reg); + }else{ + dma_ram_desc=chan->logic_ch_num*4 + AFT_PORT_REG(card,AFT_DMA_CHAIN_RAM_BASE_REG); + card->hw_iface.bus_read_4(card->hw,dma_ram_desc,®); + cur_dma_ptr=aft_dmachain_get_rx_dma_addr(reg); + + dma_descr=(chan->logic_ch_num<<4) + (cur_dma_ptr*AFT_DMA_INDEX_OFFSET) + + AFT_PORT_REG(card,AFT_RX_DMA_HI_DESCR_BASE_REG); + } + + reg=0; + wan_set_bit(AFT_RXDMA_HI_DMA_CMD_BIT,®); + + DEBUG_TEST("%s: Clearing RX Fifo %s Ch=%ld DmaDescr=(0x%X) Reg=(0x%X)\n", + __FUNCTION__,chan->if_name,chan->logic_ch_num, + dma_descr,reg); + + card->hw_iface.bus_write_4(card->hw,dma_descr,reg); + + if (wait == WP_WAIT){ + for(i=0;ihw_iface.bus_read_4(card->hw,dma_descr,®); + if (wan_test_bit(AFT_RXDMA_HI_DMA_CMD_BIT,®)){ + WP_DELAY(FIFO_RESET_TIMEOUT_US); + continue; + } + timeout=0; + break; + } + + if (timeout){ + DEBUG_EVENT("%s:%s: Error: Rx fifo reset timedout %u us\n", + card->devname,chan->if_name,i*FIFO_RESET_TIMEOUT_US); + }else{ + DEBUG_TEST("%s:%s: Rx Fifo Reset Successful\n", + card->devname,chan->if_name); + } + }else{ + timeout=0; + } + + return timeout; +} + +static int aft_init_tx_dev_fifo(sdla_t *card, private_area_t *chan, unsigned char wait) +{ + u32 reg; + u32 dma_descr,dma_ram_desc; + u8 timeout=1; + u16 i; + unsigned int cur_dma_ptr; + + if (chan->single_dma_chain){ + dma_descr=(chan->logic_ch_num<<4) + AFT_PORT_REG(card,AFT_TX_DMA_HI_DESCR_BASE_REG); + + dma_ram_desc=chan->logic_ch_num*4 + AFT_PORT_REG(card,AFT_DMA_CHAIN_RAM_BASE_REG); + card->hw_iface.bus_read_4(card->hw,dma_ram_desc,®); + aft_dmachain_set_tx_dma_addr(®,0); + card->hw_iface.bus_write_4(card->hw,dma_ram_desc,reg); + }else{ + dma_ram_desc=chan->logic_ch_num*4 + AFT_PORT_REG(card,AFT_DMA_CHAIN_RAM_BASE_REG); + card->hw_iface.bus_read_4(card->hw,dma_ram_desc,®); + cur_dma_ptr=aft_dmachain_get_tx_dma_addr(reg); + + /* Clean TX DMA fifo */ + dma_descr=(chan->logic_ch_num<<4) + (cur_dma_ptr*AFT_DMA_INDEX_OFFSET) + + AFT_PORT_REG(card,AFT_TX_DMA_HI_DESCR_BASE_REG); + } + + reg=0; + wan_set_bit(AFT_TXDMA_HI_DMA_CMD_BIT,®); + + DEBUG_TEST("%s: Clearing TX Fifo %s DmaDescr=(0x%X) Reg=(0x%X)\n", + __FUNCTION__,chan->if_name, + dma_descr,reg); + + card->hw_iface.bus_write_4(card->hw,dma_descr,reg); + + if (wait == WP_WAIT){ + for(i=0;ihw_iface.bus_read_4(card->hw,dma_descr,®); + if (wan_test_bit(AFT_TXDMA_HI_DMA_CMD_BIT,®)){ + WP_DELAY(FIFO_RESET_TIMEOUT_US); + continue; + } + timeout=0; + break; + } + + if (timeout){ + DEBUG_EVENT("%s:%s: Error: Tx fifo reset timedout %u us\n", + card->devname,chan->if_name,i*FIFO_RESET_TIMEOUT_US); + }else{ + DEBUG_TEST("%s:%s: Tx Fifo Reset Successful\n", + card->devname,chan->if_name); + } + }else{ + timeout=0; + } + + return timeout; +} + +static void aft_channel_txdma_ctrl(sdla_t *card, private_area_t *chan, int on) +{ + u32 reg; + /* Enable TX DMA for Logic Channel */ + card->hw_iface.bus_read_4(card->hw, + AFT_PORT_REG(card,AFT_TX_DMA_CTRL_REG), ®); + if (on){ + wan_set_bit(chan->logic_ch_num,®); + }else{ + wan_clear_bit(chan->logic_ch_num,®); + } + + card->hw_iface.bus_write_4(card->hw, + AFT_PORT_REG(card,AFT_TX_DMA_CTRL_REG), reg); + +} +static void aft_channel_rxdma_ctrl(sdla_t *card, private_area_t *chan, int on) +{ + u32 reg; + /* Enable TX DMA for Logic Channel */ + card->hw_iface.bus_read_4(card->hw, + AFT_PORT_REG(card,AFT_RX_DMA_CTRL_REG), ®); + if (on){ + wan_set_bit(chan->logic_ch_num,®); + }else{ + wan_clear_bit(chan->logic_ch_num,®); + } + + card->hw_iface.bus_write_4(card->hw, + AFT_PORT_REG(card,AFT_RX_DMA_CTRL_REG), reg); + +} + +static void aft_channel_txintr_ctrl(sdla_t *card, private_area_t *chan, int on) +{ + u32 reg; + + /* Enable Logic Channel TX Interrupts */ + card->hw_iface.bus_read_4(card->hw, + AFT_PORT_REG(card,AFT_TX_DMA_INTR_MASK_REG), ®); + if (on){ + wan_set_bit(chan->logic_ch_num,®); + }else{ + wan_clear_bit(chan->logic_ch_num,®); + + } + card->hw_iface.bus_write_4(card->hw, + AFT_PORT_REG(card,AFT_TX_DMA_INTR_MASK_REG), reg); +} + +static void aft_channel_rxintr_ctrl(sdla_t *card, private_area_t *chan, int on) +{ + u32 reg; + + /* Enable Logic Channel TX Interrupts */ + card->hw_iface.bus_read_4(card->hw, + AFT_PORT_REG(card,AFT_RX_DMA_INTR_MASK_REG), ®); + if (on){ + wan_set_bit(chan->logic_ch_num,®); + }else{ + wan_clear_bit(chan->logic_ch_num,®); + + } + card->hw_iface.bus_write_4(card->hw, + AFT_PORT_REG(card,AFT_RX_DMA_INTR_MASK_REG), reg); +} + + +static void aft_dev_enable(sdla_t *card, private_area_t *chan) +{ + DEBUG_TEST("%s: Enabling Global Inter Mask !\n",chan->if_name); + + /* Enable TX DMA for Logic Channel */ + aft_channel_txdma_ctrl(card,chan,1); + + /* Enable RX DMA for Logic Channel */ + aft_channel_rxdma_ctrl(card,chan,1); + + /* Enable Logic Channel TX Interrupts */ + if (chan->channelized_cfg && !chan->hdlc_eng){ + aft_channel_txintr_ctrl(card,chan,0); + aft_channel_rxintr_ctrl(card,chan,0); + chan->tdmv_irq_cfg=1; + }else{ + aft_channel_txintr_ctrl(card,chan,1); + aft_channel_rxintr_ctrl(card,chan,1); + } + + wan_set_bit(chan->logic_ch_num,&card->u.aft.active_ch_map); +} + +static void aft_dev_open_private(sdla_t *card, private_area_t *chan) +{ + if (card->wandev.state == WAN_CONNECTED && + wan_test_bit(0,&card->u.aft.comm_enabled)){ + + DEBUG_TEST("%s: OPEN reseting fifo\n", + chan->if_name); + + aft_tslot_sync_ctrl(card,chan,0); + + aft_init_rx_dev_fifo(card,chan,WP_NO_WAIT); + aft_init_tx_dev_fifo(card,chan,WP_NO_WAIT); + + aft_dev_enable(card,chan); + + aft_init_rx_dev_fifo(card,chan,WP_WAIT); + aft_init_tx_dev_fifo(card,chan,WP_WAIT); + + chan->dma_index=0; + memset(chan->dma_history,0,sizeof(chan->dma_history)); + + aft_reset_rx_chain_cnt(chan); + aft_dma_rx(card,chan); + + aft_tslot_sync_ctrl(card,chan,1); + + if (!chan->hdlc_eng){ + aft_reset_tx_chain_cnt(chan); + aft_dma_tx(card,chan); + } + }else{ + aft_dev_enable(card,chan); + } + +} + +static void aft_dev_open(sdla_t *card, private_area_t *gchan) +{ + private_area_t *chan=gchan; + + if (chan->channelized_cfg){ + + for (chan=gchan; chan != NULL; chan=chan->next){ + + aft_dev_open_private(card,chan); + + wan_set_bit(0,&chan->up); + + } + + if (gchan->common.usedby == TDM_VOICE_API){ + /* Set the global mtu value which is + * the sum of all timeslots mtus */ + wan_netif_set_mtu( + gchan->common.dev, + card->u.aft.tdmv_mtu+sizeof(api_tx_hdr_t)); + + } + + wan_set_bit(0,&card->u.aft.tdmv_master_if_up); + + if (card->wandev.state == WAN_CONNECTED && + !wan_test_bit(0,&card->u.aft.comm_enabled)){ + DEBUG_EVENT("%s: Master IF Starting %s Communications\n", + gchan->if_name,card->devname); + enable_data_error_intr(card); + } + }else{ + aft_dev_open_private(card,chan); + wan_set_bit(0,&chan->up); + } + return; +} + +static void aft_dev_close_private(sdla_t *card, private_area_t *chan) +{ + + DEBUG_CFG("-- Close Xilinx device. --\n"); + + if (chan->logic_ch_num < 0){ + return; + } + + /* Disable TX DMA for Logic Channel */ + aft_channel_txdma_ctrl(card,chan,0); + + /* Disable RX DMA for Logic Channel */ + aft_channel_rxdma_ctrl(card,chan,0); + + + /* Disable Logic Channel TX Interrupts */ + aft_channel_txintr_ctrl(card,chan,0); + + /* Disable Logic Channel RX Interrupts */ + aft_channel_rxintr_ctrl(card,chan,0); + + /* Initialize DMA descriptors and DMA Chains */ + aft_init_tx_rx_dma_descr(chan); + +} + + +static void aft_dev_close(sdla_t *card, private_area_t *gchan) +{ + private_area_t *chan=gchan; + + if (chan->channelized_cfg){ + + aft_tdm_intr_ctrl(card,0); + aft_fifo_intr_ctrl(card, 0); + + for (chan=gchan; chan != NULL; chan=chan->next){ + + aft_dev_close_private(card,chan); + + DEBUG_TEST("%s: Closing Ch=%ld\n", + chan->if_name,chan->logic_ch_num); + + wan_clear_bit(0,&chan->up); + wan_set_bit(0,&chan->interface_down); + if (chan->cfg.tdmv_master_if){ + wan_clear_bit(0,&card->u.aft.tdmv_master_if_up); + } + } + }else{ + aft_dev_close_private(card,chan); + wan_clear_bit(0,&chan->up); + wan_set_bit(0,&chan->interface_down); + } + return; +} + +/**SECTION************************************************************* + * + * TX Handlers + * + **********************************************************************/ + + +/*=============================================== + * aft_dma_tx_complete + * + */ +static void aft_dma_tx_complete (sdla_t *card, private_area_t *chan, int wdt, int reset) +{ + DEBUG_TEST("%s: Tx interrupt wdt=%d\n",chan->if_name,wdt); + + if (!wdt){ + wan_clear_bit(TX_INTR_PENDING,&chan->dma_chain_status); + } + + if (chan->channelized_cfg && !chan->hdlc_eng){ + aft_tx_dma_voice_handler((unsigned long)chan,wdt,reset); + }else{ + aft_tx_dma_chain_handler((unsigned long)chan,wdt,reset); + } + + wan_set_bit(0,&chan->idle_start); + + if (reset){ + return; + } + + aft_dma_tx(card,chan); + + if (WAN_NETIF_QUEUE_STOPPED(chan->common.dev)){ + WAN_NETIF_WAKE_QUEUE(chan->common.dev); +#ifndef CONFIG_PRODUCT_WANPIPE_GENERIC + if (chan->common.usedby == API){ + wan_wakeup_api(chan); + }else if (chan->common.usedby == STACK){ + wanpipe_lip_kick(chan,0); + } +#endif + } + + if (chan->common.usedby == TDM_VOICE_DCHAN){ +#ifdef AFT_TDM_API_SUPPORT + if (is_tdm_api(chan,&chan->wp_tdm_api_dev)){ + wanpipe_tdm_api_kick(&chan->wp_tdm_api_dev); + } +#endif + } + + return; +} + +/*=============================================== + * aft_tx_post_complete + * + */ +static void aft_tx_post_complete (sdla_t *card, private_area_t *chan, netskb_t *skb) +{ + unsigned int reg = wan_skb_csum(skb); + u32 dma_status = aft_txdma_hi_get_dma_status(reg); + + wan_skb_set_csum(skb,0); + + if (reg & AFT_TXDMA_HI_DMA_LENGTH_MASK){ + chan->errstats.Tx_dma_len_nonzero++; + } + + if ((wan_test_bit(AFT_TXDMA_HI_GO_BIT,®)) || + (reg & AFT_TXDMA_HI_DMA_LENGTH_MASK) || + dma_status){ + + DEBUG_TEST("%s:%s: Tx DMA Descriptor=0x%X\n", + card->devname,chan->if_name,reg); + + /* Checking Tx DMA Go bit. Has to be '0' */ + if (wan_test_bit(AFT_TXDMA_HI_GO_BIT,®)){ + DEBUG_TEST("%s:%s: Error: TxDMA Intr: GO bit set on Tx intr\n", + card->devname,chan->if_name); + chan->errstats.Tx_dma_errors++; + } + + if (reg & AFT_TXDMA_HI_DMA_LENGTH_MASK){ + DEBUG_EVENT("%s:%s: Error: TxDMA Length not equal 0 \n", + card->devname,chan->if_name); + chan->errstats.Tx_dma_errors++; + } + + /* Checking Tx DMA PCI error status. Has to be '0's */ + if (dma_status){ + + chan->errstats.Tx_pci_errors++; + if (wan_test_bit(AFT_TXDMA_HIDMASTATUS_PCI_M_ABRT,&dma_status)){ + if (WAN_NET_RATELIMIT()){ + DEBUG_EVENT("%s:%s: Tx Error: Abort from Master: pci fatal error!\n", + card->devname,chan->if_name); + } + + } + if (wan_test_bit(AFT_TXDMA_HIDMASTATUS_PCI_T_ABRT,&dma_status)){ + if (WAN_NET_RATELIMIT()){ + DEBUG_EVENT("%s:%s: Tx Error: Abort from Target: pci fatal error!\n", + card->devname,chan->if_name); + } + } + if (wan_test_bit(AFT_TXDMA_HIDMASTATUS_PCI_DS_TOUT,&dma_status)){ + DEBUG_TEST("%s:%s: Tx Warning: PCI Latency Timeout!\n", + card->devname,chan->if_name); + chan->errstats.Tx_pci_latency++; + goto tx_post_ok; + } + if (wan_test_bit(AFT_TXDMA_HIDMASTATUS_PCI_RETRY,&dma_status)){ + if (WAN_NET_RATELIMIT()){ + DEBUG_EVENT("%s:%s: Tx Error: 'Retry' exceeds maximum (64k): pci fatal error!\n", + card->devname,chan->if_name); + } + } + } + chan->if_stats.tx_errors++; + goto tx_post_exit; + } + +tx_post_ok: + + chan->opstats.Data_frames_Tx_count++; + chan->opstats.Data_bytes_Tx_count+=wan_skb_len(skb); + chan->if_stats.tx_packets++; + chan->if_stats.tx_bytes+=wan_skb_len(skb); + +#if 0 + if (chan->common.usedby != TDM_VOICE){ + wan_capture_trace_packet(card, &chan->trace_info, skb, TRC_OUTGOING_FRM); + } +#endif + +tx_post_exit: + + return; +} + + + +/**SECTION************************************************************* + * + * RX Handlers + * + **********************************************************************/ + + +/*=============================================== + * aft_rx_post_complete + * + */ +static void aft_rx_post_complete (sdla_t *card, private_area_t *chan, + netskb_t *skb, + netskb_t **new_skb, + unsigned char *pkt_error) +{ + + unsigned int len,data_error = 0; + unsigned char *buf; + wp_rx_element_t *rx_el; + u32 dma_status; + rx_el=(wp_rx_element_t *)wan_skb_data(skb); + + DEBUG_RX("%s:%s: RX HI=0x%X LO=0x%X\n DMA=0x%X", + __FUNCTION__, + chan->if_name, + rx_el->reg, + rx_el->align, + rx_el->dma_addr); + +#if 0 + chan->if_stats.rx_errors++; +#endif + + rx_el->align&=AFT_RXDMA_LO_ALIGN_MASK; + *pkt_error=0; + *new_skb=NULL; + + dma_status=aft_rxdma_hi_get_dma_status(rx_el->reg); + + /* Checking Rx DMA Go bit. Has to be '0' */ + if (wan_test_bit(AFT_RXDMA_HI_GO_BIT,&rx_el->reg)){ + DEBUG_TEST("%s:%s: Error: RxDMA Intr: GO bit set on Rx intr\n", + card->devname,chan->if_name); + chan->if_stats.rx_errors++; + chan->errstats.Rx_dma_descr_err++; + goto rx_comp_error; + } + + /* Checking Rx DMA PCI error status. Has to be '0's */ + if (dma_status){ + + if (wan_test_bit(AFT_RXDMA_HIDMASTATUS_PCI_M_ABRT,&dma_status)){ + if (WAN_NET_RATELIMIT()){ + DEBUG_EVENT("%s:%s: Rx Error: Abort from Master: pci fatal error 0x%X!\n", + card->devname,chan->if_name,rx_el->reg); + } + } + if (wan_test_bit(AFT_RXDMA_HIDMASTATUS_PCI_T_ABRT,&dma_status)){ + if (WAN_NET_RATELIMIT()){ + DEBUG_EVENT("%s:%s: Rx Error: Abort from Target: pci fatal error 0x%X!\n", + card->devname,chan->if_name,rx_el->reg); + } + } + if (wan_test_bit(AFT_RXDMA_HIDMASTATUS_PCI_DS_TOUT,&dma_status)){ + if (WAN_NET_RATELIMIT()){ + DEBUG_EVENT("%s:%s: Rx Error: No 'DeviceSelect' from target: pci fatal error 0x%X!\n", + card->devname,chan->if_name,rx_el->reg); + } + } + if (wan_test_bit(AFT_RXDMA_HIDMASTATUS_PCI_RETRY,&dma_status)){ + if (WAN_NET_RATELIMIT()){ + DEBUG_EVENT("%s:%s: Rx Error: 'Retry' exceeds maximum (64k): pci fatal error 0x%X!\n", + card->devname,chan->if_name,rx_el->reg); + } + } + + chan->errstats.Rx_pci_errors++; + chan->if_stats.rx_errors++; + goto rx_comp_error; + } + + if (chan->hdlc_eng){ + + /* Checking Rx DMA Frame start bit. (information for api) */ + if (!wan_test_bit(AFT_RXDMA_HI_START_BIT,&rx_el->reg)){ + DEBUG_TEST("%s:%s RxDMA Intr: Start flag missing: MTU Mismatch! Reg=0x%X\n", + card->devname,chan->if_name,rx_el->reg); + chan->if_stats.rx_frame_errors++; + chan->opstats.Rx_Data_discard_long_count++; + chan->errstats.Rx_hdlc_corrupiton++; + goto rx_comp_error; + } + + /* Checking Rx DMA Frame end bit. (information for api) */ + if (!wan_test_bit(AFT_RXDMA_HI_EOF_BIT,&rx_el->reg)){ + DEBUG_TEST("%s:%s: RxDMA Intr: End flag missing: MTU Mismatch! Reg=0x%X\n", + card->devname,chan->if_name,rx_el->reg); + chan->if_stats.rx_frame_errors++; + chan->opstats.Rx_Data_discard_long_count++; + chan->errstats.Rx_hdlc_corrupiton++; + goto rx_comp_error; + + } else { /* Check CRC error flag only if this is the end of Frame */ + + if (wan_test_bit(AFT_RXDMA_HI_FCS_ERR_BIT,&rx_el->reg)){ + DEBUG_TEST("%s:%s: RxDMA Intr: CRC Error! Reg=0x%X Len=%d\n", + card->devname,chan->if_name,rx_el->reg, + (rx_el->reg&AFT_RXDMA_HI_DMA_LENGTH_MASK)>>2); + chan->if_stats.rx_frame_errors++; + chan->errstats.Rx_crc_err_count++; + wan_set_bit(WP_CRC_ERROR_BIT,&rx_el->pkt_error); + data_error = 1; + } + + /* Check if this frame is an abort, if it is + * drop it and continue receiving */ + if (wan_test_bit(AFT_RXDMA_HI_FRM_ABORT_BIT,&rx_el->reg)){ + DEBUG_TEST("%s:%s: RxDMA Intr: Abort! Reg=0x%X\n", + card->devname,chan->if_name,rx_el->reg); + chan->if_stats.rx_frame_errors++; + chan->errstats.Rx_hdlc_corrupiton++; + wan_set_bit(WP_ABORT_ERROR_BIT,&rx_el->pkt_error); + data_error = 1; + } + + if (chan->common.usedby != API && data_error){ + goto rx_comp_error; + } + + } + } + + len=rx_el->reg&AFT_RXDMA_HI_DMA_LENGTH_MASK; + + if (chan->hdlc_eng){ + /* In HDLC mode, calculate rx length based + * on alignment value, received from DMA */ + len=((((chan->dma_mru>>2)-1)-len)<<2) - (~(rx_el->align)&AFT_RXDMA_LO_ALIGN_MASK); + + if (len < 3 || len > chan->dma_mru){ + chan->if_stats.rx_frame_errors++; + chan->errstats.Rx_hdlc_corrupiton++; + goto rx_comp_error; + } + }else{ + /* In Transparent mode, our RX buffer will always be + * aligned to the 32bit (word) boundary, because + * the RX buffers are all of equal length */ + len=(((chan->mru>>2)-len)<<2) - (~(0x03)&AFT_RXDMA_LO_ALIGN_MASK); + + if (len < 1 || len > chan->mru){ + chan->if_stats.rx_frame_errors++; + goto rx_comp_error; + } + } + + + + *pkt_error=rx_el->pkt_error; + + /* After a RX FIFO overflow, we must mark max 7 + * subsequent frames since firmware, cannot + * guarantee the contents of the fifo */ + + if (wan_test_bit(WP_FIFO_ERROR_BIT,&rx_el->pkt_error)){ + if (chan->hdlc_eng){ + if (++chan->rx_fifo_err_cnt >= WP_MAX_FIFO_FRAMES){ + chan->rx_fifo_err_cnt=0; + } + }else{ + chan->rx_fifo_err_cnt=0; + } + wan_set_bit(WP_FIFO_ERROR_BIT,pkt_error); + }else{ + if (chan->rx_fifo_err_cnt){ + if (++chan->rx_fifo_err_cnt >= WP_MAX_FIFO_FRAMES){ + chan->rx_fifo_err_cnt=0; + } + wan_set_bit(WP_FIFO_ERROR_BIT,pkt_error); + } + } + + + if (len > aft_rx_copyback){ + /* The rx size is big enough, thus + * send this buffer up the stack + * and allocate another one */ + memset(wan_skb_data(skb),0,sizeof(wp_rx_element_t)); + wan_skb_put(skb,len); + wan_skb_pull(skb, sizeof(wp_rx_element_t)); + *new_skb=skb; + + aft_alloc_rx_dma_buff(card,chan,1); + }else{ + + /* The rx packet is very + * small thus, allocate a new + * buffer and pass it up */ + *new_skb=wan_skb_alloc(len + 20); + if (!*new_skb){ + DEBUG_EVENT("%s:%s: Failed to allocate rx skb pkt (len=%d)!\n", + card->devname,chan->if_name,(len+20)); + chan->if_stats.rx_dropped++; + goto rx_comp_error; + } + + buf=wan_skb_put((*new_skb),len); + memcpy(buf,wan_skb_tail(skb),len); + + aft_init_requeue_free_skb(chan, skb); + } + +#if 0 + if (chan->hdlc_eng){ + buf=wan_skb_data(*new_skb); + if (buf[wan_skb_len(*new_skb)-1] != 0x7E && + buf[wan_skb_len(*new_skb)-1] != 0x7F){ + if (WAN_NET_RATELIMIT()){ + DEBUG_EVENT("%s: Rx: Invalid packet len=%d: 0x%X 0x%X 0x%X\n", + card->devname, + wan_skb_len(*new_skb), + buf[wan_skb_len(*new_skb)-3], + buf[wan_skb_len(*new_skb)-2], + buf[wan_skb_len(*new_skb)-1]); + } + } + } +#endif + + return; + +rx_comp_error: + + aft_init_requeue_free_skb(chan, skb); + return; +} + + + +/**SECTION************************************************** + * + * Logic Channel Registration Support and + * Utility funcitons + * + **********************************************************/ + +static int aft_init_requeue_free_skb(private_area_t *chan, netskb_t *skb) +{ + WAN_ASSERT(skb == NULL); + + wan_skb_init(skb,16); + wan_skb_trim(skb,0); + wan_skb_queue_tail(&chan->wp_rx_free_list,skb); + + return 0; +} + +static int aft_alloc_rx_dma_buff(sdla_t *card, private_area_t *chan, int num) +{ + int i; + netskb_t *skb; + + for (i=0;ichannelized_cfg && !chan->hdlc_eng){ +#ifdef __LINUX__ + /* On Systems greater than 4GB we must + * allocated our DMA buffers using GFP_DMA + * flag */ + skb=__dev_alloc_skb(chan->dma_mru,GFP_DMA); +#else + skb=wan_skb_alloc(chan->dma_mru); +#endif + }else{ + skb=wan_skb_alloc(chan->dma_mru); + } + if (!skb){ + DEBUG_EVENT("%s: %s no rx memory\n", + chan->if_name,__FUNCTION__); + return -ENOMEM; + } + wan_skb_queue_tail(&chan->wp_rx_free_list,skb); + } + + + + return 0; +} + + +/*============================================================================ + * Enable timer interrupt + */ +static void enable_timer (void* card_id) +{ + sdla_t* card = (sdla_t*)card_id; +#if !defined(WAN_IS_TASKQ_SCHEDULE) + wan_smp_flag_t smp_flags; + wan_smp_flag_t smp_flags1; +#endif + + if (wan_test_bit(CARD_DOWN,&card->wandev.critical)){ + DEBUG_EVENT("%s: Card down: Ignoring enable_timer!\n", + card->devname); + return; + } + + DEBUG_TEST("%s: %s Sdla Polling %p!\n",__FUNCTION__, + card->devname, + card->wandev.fe_iface.polling); + +#if defined(WAN_IS_TASKQ_SCHEDULE) + wan_set_bit(AFT_FE_POLL,&card->u.aft.port_task_cmd); + WAN_TASKQ_SCHEDULE((&card->u.aft.port_task)); +#else + card->hw_iface.hw_lock(card->hw,&smp_flags1); + wan_spin_lock_irq(&card->wandev.lock, &smp_flags); + if (card->wandev.fe_iface.polling){ + card->wandev.fe_iface.polling(&card->fe); + } + wan_spin_unlock_irq(&card->wandev.lock, &smp_flags); + card->hw_iface.hw_unlock(card->hw,&smp_flags1); +#endif + + return; +} + +static void enable_ec_timer (void* card_id) +{ +#if defined(CONFIG_WANPIPE_HWEC) + sdla_t* card = (sdla_t*)card_id; +# if !defined(WAN_IS_TASKQ_SCHEDULE) + wan_smp_flag_t smp_flags; + wan_smp_flag_t smp_flags1; +# endif + + if (wan_test_bit(CARD_DOWN,&card->wandev.critical)){ + DEBUG_EVENT("%s: Card down: Ignoring enable_timer!\n", + card->devname); + return; + } + + DEBUG_TEST("%s: %s Sdla Polling %p!\n",__FUNCTION__, + card->devname, + card->wandev.fe_iface.polling); + +# if defined(WAN_IS_TASKQ_SCHEDULE) + wan_set_bit(AFT_FE_EC_POLL,&card->u.aft.port_task_cmd); + WAN_TASKQ_SCHEDULE((&card->u.aft.port_task)); +# else + card->hw_iface.hw_lock(card->hw,&smp_flags1); + wan_spin_lock_irq(&card->wandev.lock, &smp_flags); + + wanpipe_ec_poll(card->wandev.ec_dev, card); + + wan_spin_unlock_irq(&card->wandev.lock, &smp_flags); + card->hw_iface.hw_unlock(card->hw,&smp_flags1); +# endif +#endif + return; +} +/**SECTION************************************************** + * + * API Bottom Half Handlers + * + **********************************************************/ + +static int tdm_check=0; + +#if defined(__LINUX__) +static void wp_tdm_bh (unsigned long data) +#else +static void wp_tdm_bh (void *data, int pending) +#endif +{ +#if defined(CONFIG_PRODUCT_WANPIPE_TDM_VOICE) + private_area_t* chan = (private_area_t *)data; + sdla_t *card=chan->card; + int err; + +#if 0 + if (WAN_NET_RATELIMIT()){ + DEBUG_EVENT("%s: TDM BH Running !\n", + chan->if_name); + } +#endif + + if (wan_test_bit(CARD_DOWN,&card->wandev.critical)){ + goto wp_tdm_bh_exit; + } + + if (!wan_test_bit(0,&chan->up)){ + if (WAN_NET_RATELIMIT()){ + DEBUG_EVENT("%s: wp_tdm_bh() chan not up!\n", + chan->if_name); + } + goto wp_tdm_bh_exit; + } + +#if 0 + if (tdm_check){ + if (WAN_NET_RATELIMIT()){ + DEBUG_EVENT("%s: TDM BH Already Running 0x%02X... cool!\n", + chan->if_name,tdm_check); + } + } + wan_set_bit(card->u.aft.cfg.tdmv_span_no,&tdm_check); +#endif + + WAN_TDMV_CALL(rx_tx_span, (card), err); + + WAN_TASKLET_END((&chan->common.bh_task)); + + if (card->wan_tdmv.sc){ + WAN_TDMV_CALL(is_rbsbits, (&card->wan_tdmv), err); + if (err == 1){ + wan_set_bit(AFT_FE_TDM_RBS,&card->u.aft.port_task_cmd); + WAN_TASKQ_SCHEDULE((&card->u.aft.port_task)); + } + } + +#if 0 + wan_clear_bit(card->u.aft.cfg.tdmv_span_no,&tdm_check); +#endif + tdm_check++; + + return; + +wp_tdm_bh_exit: + WAN_TASKLET_END((&chan->common.bh_task)); +#endif + return; +} + + +#if defined(__LINUX__) +static void wp_bh (unsigned long data) +#else +static void wp_bh (void *data, int pending) +#endif +{ + private_area_t* chan = (private_area_t *)data; + sdla_t *card=chan->card; + netskb_t *new_skb,*skb; + unsigned char pkt_error; + unsigned long timeout=SYSTEM_TICKS; + private_area_t *top_chan; + int len; + + if (wan_test_bit(CARD_DOWN,&card->wandev.critical)){ + WAN_TASKLET_END((&chan->common.bh_task)); + return; + } + + if (card->u.aft.cfg.tdmv_dchan){ + top_chan=wan_netif_priv(chan->common.dev); + }else{ + top_chan=chan; + } + + DEBUG_TEST("%s: ------------ BEGIN --------------: %u\n", + __FUNCTION__,SYSTEM_TICKS); + + if (!wan_test_bit(0,&chan->up)){ + if (WAN_NET_RATELIMIT()){ + DEBUG_EVENT("%s: wp_bh() chan not up!\n", + chan->if_name); + } + WAN_TASKLET_END((&chan->common.bh_task)); + return; + } + + while((skb=wan_skb_dequeue(&chan->wp_rx_complete_list)) != NULL){ + +#if 0 + chan->if_stats.rx_errors++; +#endif + + if (SYSTEM_TICKS-timeout > 1){ + wan_skb_queue_head(&chan->wp_rx_complete_list,skb); + break; + } + + if (chan->common.usedby == API && chan->common.sk == NULL){ + DEBUG_TEST("%s: No sock bound to channel rx dropping!\n", + chan->if_name); + chan->if_stats.rx_dropped++; + aft_init_requeue_free_skb(chan, skb); + continue; + } + + new_skb=NULL; + pkt_error=0; + + + + /* The post function will take care + * of the skb and new_skb buffer. + * If new_skb buffer exists, driver + * must pass it up the stack, or free it */ + aft_rx_post_complete (chan->card, chan, + skb, + &new_skb, + &pkt_error); + if (new_skb){ + + len=wan_skb_len(new_skb); + + if (chan->hdlc_eng){ + /* HDLC packets contain 2 byte crc and 1 byte + * flag. If data is not greater than 3, then + * we have a 0 length frame. Thus discard + * (only if HDLC engine enabled) */ + if (len <= 3){ + ++chan->if_stats.rx_errors; + wan_skb_free(new_skb); + continue; + } + + wan_skb_trim(new_skb,wan_skb_len(new_skb)-3); + len-=3; + } + + wan_capture_trace_packet(chan->card, &top_chan->trace_info, + new_skb,TRC_INCOMING_FRM); + + + if (chan->common.usedby == API){ + + if (chan->hdlc_eng){ + if (card->u.aft.cfg.rx_crc_bytes == 3){ + wan_skb_put(new_skb,3); + }else if (card->u.aft.cfg.rx_crc_bytes == 2){ + wan_skb_put(new_skb,2); + } + } + +#if defined(__LINUX__) +# ifndef CONFIG_PRODUCT_WANPIPE_GENERIC + + + /* Only for API, we insert packet status + * byte to indicate a packet error. Take + * this byte and put it in the api header */ + + if (wan_skb_headroom(new_skb) >= sizeof(api_rx_hdr_t)){ + api_rx_hdr_t *rx_hdr= + (api_rx_hdr_t*)skb_push(new_skb,sizeof(api_rx_hdr_t)); + memset(rx_hdr,0,sizeof(api_rx_hdr_t)); + rx_hdr->error_flag=pkt_error; + }else{ + if (WAN_NET_RATELIMIT()){ + DEBUG_EVENT("%s: Error Rx pkt headroom %u < %u\n", + chan->if_name, + (u32)wan_skb_headroom(new_skb), + (u32)sizeof(api_rx_hdr_t)); + } + ++chan->if_stats.rx_dropped; + wan_skb_free(new_skb); + continue; + } + + new_skb->protocol = htons(PVC_PROT); + new_skb->mac.raw = new_skb->data; + new_skb->dev = chan->common.dev; + new_skb->pkt_type = WAN_PACKET_DATA; +#if 0 + chan->if_stats.rx_frame_errors++; +#endif + if (wan_api_rx(chan,new_skb) != 0){ + ++chan->if_stats.rx_dropped; + wan_skb_free(new_skb); + continue; + } +# endif +#endif + + }else if (chan->common.usedby == TDM_VOICE_DCHAN){ + +#ifdef AFT_TDM_API_SUPPORT + if (is_tdm_api(chan,&chan->wp_tdm_api_dev)) { + int err; + + if (wan_skb_headroom(new_skb) >= sizeof(api_rx_hdr_t)){ + api_rx_hdr_t *rx_hdr = + (api_rx_hdr_t*)skb_push(new_skb,sizeof(api_rx_hdr_t)); + memset(rx_hdr,0,sizeof(api_rx_hdr_t)); + //rx_hdr->error_flag=pkt_error; + }else{ + if (WAN_NET_RATELIMIT()){ + DEBUG_EVENT("%s: Error Rx pkt headroom %u < %u\n", + chan->if_name, + (u32)wan_skb_headroom(new_skb), + (u32)sizeof(api_rx_hdr_t)); + } + ++chan->if_stats.rx_dropped; + wan_skb_free(new_skb); + continue; + } + err=wanpipe_tdm_api_rx_hdlc(&chan->wp_tdm_api_dev,new_skb); + if (err){ + ++chan->if_stats.rx_dropped; + wan_skb_free(new_skb); + continue; + } + + }else +#endif + if (chan->tdmv_zaptel_cfg){ + +#if defined(CONFIG_PRODUCT_WANPIPE_TDM_VOICE_DCHAN) + int err; +/* ADEBUG */ + WAN_TDMV_CALL(rx_dchan, + (&card->wan_tdmv,chan->tdmv_chan, + wan_skb_data(new_skb),wan_skb_len(new_skb)), + err); + DEBUG_RX("%s TDM DCHAN VOICE Rx Pkt Len=%i Chan=%i\n", + card->devname,wan_skb_len(new_skb), + chan->tdmv_chan); +#else + DEBUG_EVENT("%s: DCHAN Rx Packet critical error TDMV not compiled!\n",card->devname); +#endif + + wan_skb_free(new_skb); + /* Continue through since the above + * function returns void */ + + } else { + DEBUG_EVENT("%s: DCHAN Rx Packet critical error op not supported\n",card->devname); + ++chan->if_stats.rx_dropped; + wan_skb_free(new_skb); + continue; + } + + }else if (chan->common.usedby == TDM_VOICE){ + + DEBUG_EVENT("%s: TDM VOICE CRITICAL: IN BH!!!!\n",card->devname); + ++chan->if_stats.rx_dropped; + wan_skb_free(new_skb); + continue; + + }else if (chan->common.usedby == STACK){ + + wan_skb_set_csum(new_skb,0); + + if (wanpipe_lip_rx(chan,new_skb) != 0){ + ++chan->if_stats.rx_dropped; + wan_skb_free(new_skb); + continue; + } + + }else{ + protocol_recv(chan->card,chan,new_skb); + } + + chan->opstats.Data_frames_Rx_count++; + chan->opstats.Data_bytes_Rx_count+=len; + chan->if_stats.rx_packets++; + chan->if_stats.rx_bytes+=len; + } + + } + + while((skb=wan_skb_dequeue(&chan->wp_rx_stack_complete_list)) != NULL){ + len=wan_skb_len(skb); + if (wanpipe_lip_rx(chan,skb) != 0){ + ++chan->if_stats.rx_dropped; + wan_skb_free(skb); + }else{ + chan->opstats.Data_frames_Rx_count++; + chan->opstats.Data_bytes_Rx_count+=len; + chan->if_stats.rx_packets++; + chan->if_stats.rx_bytes+=len; + } + } + + while((skb=wan_skb_dequeue(&chan->wp_rx_zap_complete_list)) != NULL){ + int err; + err=0; + len=wan_skb_len(skb); +# if defined(CONFIG_PRODUCT_WANPIPE_TDM_VOICE_DCHAN) + WAN_TDMV_CALL(rx_dchan, + (&card->wan_tdmv,card->u.aft.tdmv_chan, + wan_skb_data(skb),wan_skb_len(skb)), err); + DEBUG_TEST("%s TDM DCHAN VOICE Rx Pkt Len=%i Chan=%i\n", + chan->if_name,wan_skb_len(skb), + chan->tdmv_chan); +# endif + wan_skb_free(skb); + } + + while((skb=wan_skb_dequeue(&chan->wp_tx_complete_list)) != NULL){ + aft_tx_post_complete (chan->card,chan,skb); + wan_skb_free(skb); + } + + + WAN_TASKLET_END((&chan->common.bh_task)); +#if 1 + { + + if ((len=wan_skb_queue_len(&chan->wp_rx_complete_list))){ + WAN_TASKLET_SCHEDULE((&chan->common.bh_task)); + }else if ((len=wan_skb_queue_len(&chan->wp_tx_complete_list))){ + WAN_TASKLET_SCHEDULE((&chan->common.bh_task)); + }else if ((len=wan_skb_queue_len(&chan->wp_rx_stack_complete_list))){ + WAN_TASKLET_SCHEDULE((&chan->common.bh_task)); + }else if ((len=wan_skb_queue_len(&chan->wp_rx_zap_complete_list))){ + WAN_TASKLET_SCHEDULE((&chan->common.bh_task)); + } + + } +#endif + + DEBUG_TEST("%s: ------------ END -----------------: %u\n", + __FUNCTION__,SYSTEM_TICKS); + + return; +} + +/**SECTION************************************************** + * + * Interrupt Support Functions + * + **********************************************************/ +static void wp_aft_fifo_per_port_isr(sdla_t *card) +{ + u32 rx_status, tx_status; + u32 i; + private_area_t *chan; + int num_of_logic_ch; + u32 tmp_fifo_reg; + + /* Clear HDLC pending registers */ + card->hw_iface.bus_read_4(card->hw,AFT_PORT_REG(card,AFT_TX_FIFO_INTR_PENDING_REG),&tx_status); + card->hw_iface.bus_read_4(card->hw,AFT_PORT_REG(card,AFT_RX_FIFO_INTR_PENDING_REG),&rx_status); + + tx_status&=card->u.aft.active_ch_map; + rx_status&=card->u.aft.active_ch_map; + + num_of_logic_ch=card->u.aft.num_of_time_slots; + + if (!wan_test_bit(0,&card->u.aft.comm_enabled)){ + if (tx_status){ + card->wandev.stats.tx_aborted_errors++; + } + if (rx_status){ + card->wandev.stats.rx_over_errors++; + } + return; + } + + if (tx_status != 0){ + for (i=0;iu.aft.logic_ch_map)){ + + chan=(private_area_t*)card->u.aft.dev_to_ch_map[i]; + if (!chan){ + DEBUG_EVENT("Warning: ignoring tx fifo intr: no dev!\n"); + continue; + } + + if (wan_test_bit(0,&chan->interface_down)){ + continue; + } +#if 1 + if (!chan->hdlc_eng && !wan_test_bit(0,&chan->idle_start)){ + DEBUG_TEST("%s: Warning: ignoring tx fifo: dev idle start!\n", + chan->if_name); + continue; + } +#endif + DEBUG_TEST("%s:%s: Warning TX Fifo Error on LogicCh=%ld Slot=%d!\n", + card->devname,chan->if_name,chan->logic_ch_num,i); + +#if 0 +{ + u32 dma_descr,tmp_reg; + dma_descr=(chan->logic_ch_num<<4) + + AFT_PORT_REG(card,AFT_TX_DMA_HI_DESCR_BASE_REG); + + + card->hw_iface.bus_read_4(card->hw,dma_descr, &tmp_reg); + + DEBUG_EVENT("%s:%s: Warning TX Fifo Error on LogicCh=%ld Slot=%d Reg=0x%X!\n", + card->devname,chan->if_name,chan->logic_ch_num,i,tmp_reg); + +#if 1 + aft_list_tx_descriptors(chan); + disable_data_error_intr(card,DEVICE_DOWN); + wan_set_bit(CARD_DOWN,&card->wandev.critical); + port_set_state(card,WAN_DISCONNECTED); + break; + +#endif + +} +#endif + + aft_tx_fifo_under_recover(card,chan); + ++chan->if_stats.tx_fifo_errors; + card->wandev.stats.tx_aborted_errors++; + card->hw_iface.bus_read_4(card->hw,AFT_PORT_REG(card,AFT_TX_FIFO_INTR_PENDING_REG),&tmp_fifo_reg); + } + } + } + + + if (rx_status != 0){ + for (i=0;iu.aft.logic_ch_map)){ + chan=(private_area_t*)card->u.aft.dev_to_ch_map[i]; + if (!chan){ + continue; + } + + if (wan_test_bit(0,&chan->interface_down)){ + continue; + } + +#ifdef AFT_RX_FIFO_DEBUG +{ + u32 dma_descr,tmp1_reg,tmp_reg,cur_dma_ptr; + u32 dma_ram_desc=chan->logic_ch_num*4 + + AFT_PORT_REG(card,AFT_DMA_CHAIN_RAM_BASE_REG); + + card->hw_iface.bus_read_4(card->hw,dma_ram_desc,&tmp_reg); + cur_dma_ptr=aft_dmachain_get_rx_dma_addr(tmp_reg); + + dma_descr=(chan->logic_ch_num<<4) + cur_dma_ptr*AFT_DMA_INDEX_OFFSET + + AFT_PORT_REG(card,AFT_RX_DMA_HI_DESCR_BASE_REG); + + card->hw_iface.bus_read_4(card->hw,dma_descr, &tmp_reg); + card->hw_iface.bus_read_4(card->hw,(dma_descr-4), &tmp1_reg); + + + if (wan_test_bit(AFT_RXDMA_HI_GO_BIT,&tmp_reg)){ + DEBUG_EVENT("%s: Rx Fifo Go Bit Set DMA=%d Addr=0x%X : HI=0x%08X LO=0x%08X OLO=0x%08X Cfg=0x%08X!\n", + card->devname, + cur_dma_ptr, + dma_descr, + tmp_reg,tmp1_reg, +chan->rx_dma_chain_table[chan->rx_chain_indx].dma_addr, +0); + } + + DEBUG_EVENT("%s:%s: Warning RX Fifo Error on Ch=%ld End=%d Cur=%d: Reg=0x%X Addr=0x%X!\n", + card->devname,chan->if_name,chan->logic_ch_num, + chan->rx_chain_indx,cur_dma_ptr,tmp_reg,dma_descr); + +} +#if 0 + aft_display_chain_history(chan); + aft_list_descriptors(chan); +#endif +#endif + ++chan->if_stats.rx_fifo_errors; + chan->errstats.Rx_overrun_err_count++; + card->wandev.stats.rx_over_errors++; + + aft_rx_fifo_over_recover(card,chan); + wan_set_bit(WP_FIFO_ERROR_BIT, &chan->pkt_error); + + card->hw_iface.bus_read_4(card->hw, + AFT_PORT_REG(card,AFT_RX_FIFO_INTR_PENDING_REG),&tmp_fifo_reg); +#if 0 + /* Debuging Code used to stop the line in + * case of fifo errors */ + aft_list_descriptors(chan); + disable_data_error_intr(card,DEVICE_DOWN); + port_set_state(card,WAN_DISCONNECTED); +#endif + } + } + } + + return; +} + + +static void front_end_interrupt(sdla_t *card, unsigned long reg, int lock) +{ + if (card->wandev.fe_iface.isr){ + card->wandev.fe_iface.isr(&card->fe); + + if (lock){ + wan_smp_flag_t smp_flags; + wan_spin_lock_irq(&card->wandev.lock,&smp_flags); + handle_front_end_state(card); + wan_spin_unlock_irq(&card->wandev.lock,&smp_flags); + }else{ + handle_front_end_state(card); + } + } + return; +} +/**SECTION*************************************************************** + * + * HARDWARE Interrupt Handlers + * + ***********************************************************************/ + + +/*============================================================================ + * wpfw_isr + * + * Main interrupt service routine. + * Determin the interrupt received and handle it. + * + */ + +#if 0 +static u32 aft_shared_irq=0; +static u32 aft_master_dev=0xF; +#endif +#if 0 +static int gdma_cnt=0; +#endif + +static void wp_aft_global_isr (sdla_t* card) +{ + u32 reg; + u32 fifo_port_intr; + u32 dma_port_intr; + u32 wdt_port_intr; + u32 tdmv_port_intr; + u32 fe_intr=0; + + if (wan_test_bit(CARD_DOWN,&card->wandev.critical)){ + DEBUG_TEST("%s: Card down, ignoring interrupt!!!!!!!\n", + card->devname); + return; + } + +#ifdef AFT_IRQ_STAT_DEBUG + card->wandev.stats.rx_errors++; +#endif + + if (tdm_check > 0){ + card->wandev.stats.rx_errors=tdm_check; + } + +#ifdef AFT_IRQ_DEBUG + card->wandev.stats.rx_packets++; + if (SYSTEM_TICKS-card->u.aft.gtimeout >= HZ){ + card->wandev.stats.tx_packets=card->wandev.stats.rx_packets; + card->wandev.stats.rx_packets=0; + card->u.aft.gtimeout=SYSTEM_TICKS; + } +#endif + + wan_set_bit(0,&card->in_isr); + card->intcount ++; + + /* -----------------2/6/2003 9:02AM------------------ + * Disable all chip Interrupts (offset 0x040) + * -- "Transmit/Receive DMA Engine" interrupt disable + * -- "FiFo/Line Abort Error" interrupt disable + * --------------------------------------------------*/ + card->hw_iface.bus_read_4(card->hw,AFT_CHIP_CFG_REG, ®); + + + if (wan_test_bit(AFT_CHIPCFG_FE_INTR_STAT_BIT,®)){ + if (wan_test_bit(AFT_CHIPCFG_FE_INTR_CFG_BIT,®)) { + DEBUG_ISR("%s: Got Front End Interrupt 0x%08X\n", + card->devname,reg); + +#ifdef AFT_IRQ_STAT_DEBUG + card->wandev.stats.rx_dropped++; +#endif + + + fe_intr=1; + /*FIXME: Give Alex the reg to acknowledge remoras */ + if (card->wandev.fe_iface.check_isr && + card->wandev.fe_iface.check_isr(&card->fe)){ +#if defined(__LINUX__) + wan_set_bit(AFT_FE_INTR,&card->u.aft.port_task_cmd); + WAN_TASKQ_SCHEDULE((&card->u.aft.port_task)); + + __aft_fe_intr_ctrl(card,0); +#else + front_end_interrupt(card,reg,0); +#endif + } + } + } + +/* New Octasic implementarion May 16 2006 */ +#if defined(CONFIG_WANPIPE_HWEC) + if (card->wandev.ec_dev && card->wandev.ec_intmask && + (card->intcount % card->wandev.ec_intmask == 0)){ + if (!wan_test_bit(AFT_FE_EC_POLL,&card->u.aft.port_task_cmd)){ + if (wanpipe_ec_isr(card->wandev.ec_dev, card)){ + wan_set_bit(AFT_FE_EC_POLL,&card->u.aft.port_task_cmd); + WAN_TASKQ_SCHEDULE((&card->u.aft.port_task)); + } + } + } +#endif + + if (card->adptr_type == A108_ADPTR_8TE1) { + u32 a108_reg; + card->hw_iface.bus_read_4(card->hw,AFT_CHIP_STAT_REG, &a108_reg); + fifo_port_intr = aft_chipcfg_a108_get_fifo_intr_stats(a108_reg); + dma_port_intr = aft_chipcfg_a108_get_dma_intr_stats(a108_reg); + wdt_port_intr = aft_chipcfg_a108_get_wdt_intr_stats(a108_reg); + tdmv_port_intr = aft_chipcfg_a108_get_tdmv_intr_stats(a108_reg); + + }else{ + fifo_port_intr = aft_chipcfg_get_hdlc_intr_stats(reg); + dma_port_intr = aft_chipcfg_get_dma_intr_stats(reg); + wdt_port_intr = aft_chipcfg_get_wdt_intr_stats(reg); + tdmv_port_intr = aft_chipcfg_get_tdmv_intr_stats(reg); + } + + + if (wan_test_bit(AFT_LCFG_FIFO_INTR_BIT,&card->u.aft.lcfg_reg) && + wan_test_bit(card->wandev.comm_port,&fifo_port_intr)){ +#ifdef AFT_IRQ_STAT_DEBUG + card->wandev.stats.multicast++; +#endif + wp_aft_fifo_per_port_isr(card); + } + + if (wan_test_bit(AFT_LCFG_DMA_INTR_BIT,&card->u.aft.lcfg_reg) && + wan_test_bit(card->wandev.comm_port,&dma_port_intr)){ + wp_aft_dma_per_port_isr(card); + + /* Only enable fifo interrupts after a first + * successful DMA interrupt */ +#ifdef AFT_IRQ_STAT_DEBUG + card->wandev.stats.rx_length_errors++; +#endif + + if (wan_test_bit(0,&card->u.aft.comm_enabled) && + !wan_test_bit(AFT_LCFG_FIFO_INTR_BIT,&card->u.aft.lcfg_reg)){ + aft_fifo_intr_ctrl(card, 1); + } + } + + if (wan_test_bit(AFT_LCFG_TDMV_INTR_BIT,&card->u.aft.lcfg_reg) && + wan_test_bit(card->wandev.comm_port,&tdmv_port_intr)){ +#ifdef AFT_IRQ_STAT_DEBUG + card->wandev.stats.rx_crc_errors++; +#endif + + wp_aft_tdmv_per_port_isr(card); + } + + if (wan_test_bit(card->wandev.comm_port,&wdt_port_intr)){ + wp_aft_wdt_per_port_isr(card,1); + card->u.aft.wdt_tx_cnt=SYSTEM_TICKS; +#ifdef AFT_IRQ_STAT_DEBUG + card->wandev.stats.rx_fifo_errors++; +#endif + } + +#ifdef AFT_WDT_ENABLE + else if (card->wandev.state == WAN_CONNECTED && + SYSTEM_TICKS-card->u.aft.wdt_tx_cnt > (HZ>>2)){ + wp_aft_wdt_per_port_isr(card,0); + card->u.aft.wdt_tx_cnt=SYSTEM_TICKS; +#ifdef AFT_IRQ_STAT_DEBUG + card->wandev.stats.tx_aborted_errors++; +#endif + } +#endif + + /* -----------------2/6/2003 10:36AM----------------- + * Finish of the interupt handler + * --------------------------------------------------*/ + + +#if AFT_SECURITY_CHECK + if (wan_test_bit(AFT_CHIPCFG_SECURITY_STAT_BIT,®)){ + if (++card->u.aft.chip_security_cnt > AFT_MAX_CHIP_SECURITY_CNT){ + DEBUG_EVENT("%s: Critical: AFT Chip Security Compromised: Disabling Driver!\n", + card->devname); + DEBUG_EVENT("%s: Please call Sangoma Tech Support (www.sangoma.com)!\n", + card->devname); + + disable_data_error_intr(card,DEVICE_DOWN); + wan_set_bit(CARD_DOWN,&card->wandev.critical); + } + + } else if (aft_hwdev[card->wandev.card_type].aft_check_ec_security(card)){ + if (++card->u.aft.chip_security_cnt > AFT_MAX_CHIP_SECURITY_CNT){ + DEBUG_EVENT("%s: Critical: Echo Canceller Chip Security Compromised: Disabling Driver!\n", + card->devname); + DEBUG_EVENT("%s: Please call Sangoma Tech Support (www.sangoma.com)!\n", + card->devname); + + disable_data_error_intr(card,DEVICE_DOWN); + wan_set_bit(CARD_DOWN,&card->wandev.critical); + } + + } else if (card->adptr_type == A108_ADPTR_8TE1 && card->wandev.state == WAN_CONNECTED) { + card->hw_iface.bus_read_4(card->hw,AFT_PORT_REG(card,AFT_LINE_CFG_REG), ®); + card->u.aft.lcfg_reg=reg; + if (wan_test_bit(AFT_LCFG_TX_FE_SYNC_STAT_BIT,®) || + wan_test_bit(AFT_LCFG_RX_FE_SYNC_STAT_BIT,®)){ + if (++card->u.aft.chip_security_cnt > AFT_MAX_CHIP_SECURITY_CNT){ + DEBUG_EVENT("%s: Critical: A108 Lost Sync with Front End: Disabling Driver (0x%0X)!\n", + card->devname, + reg); + DEBUG_EVENT("%s: Please call Sangoma Tech Support (www.sangoma.com)!\n", + card->devname); + disable_data_error_intr(card,DEVICE_DOWN); + wan_set_bit(CARD_DOWN,&card->wandev.critical); + } + } else { + card->u.aft.chip_security_cnt=0; + } + } else { + card->u.aft.chip_security_cnt=0; + } +#endif + + DEBUG_TEST("---- ISR end.-------------------\n"); + + wan_clear_bit(0,&card->in_isr); + return; + +} + +static void wp_aft_dma_per_port_isr(sdla_t *card) +{ + int i; + u32 dma_tx_reg,dma_rx_reg; + private_area_t *chan; + u32 dma_tx_voice=0; + + /* -----------------2/6/2003 9:37AM------------------ + * Checking for Interrupt source: + * 1. Receive DMA Engine + * 2. Transmit DMA Engine + * 3. Error conditions. + * --------------------------------------------------*/ + + int num_of_logic_ch; + num_of_logic_ch=card->u.aft.num_of_time_slots; + + + /* Receive DMA Engine */ + card->hw_iface.bus_read_4(card->hw, + AFT_PORT_REG(card,AFT_RX_DMA_INTR_PENDING_REG), + &dma_rx_reg); + + dma_rx_reg&=card->u.aft.active_ch_map; + +#if 0 + DEBUG_EVENT("%s: DMA_RX_INTR_REG(0x%X) = 0x%08X, ChMap=0x%lX NumofCh=%d\n", + card->devname, + AFT_PORT_REG(card,AFT_RX_DMA_INTR_PENDING_REG), + dma_rx_reg, + card->u.aft.active_ch_map, + num_of_logic_ch); +#endif + + if (dma_rx_reg == 0){ + goto isr_skb_rx; + } + + for (i=0; iu.aft.logic_ch_map)){ + + chan=(private_area_t*)card->u.aft.dev_to_ch_map[i]; + if (!chan){ + DEBUG_EVENT("%s: Error: No Dev for Rx logical ch=%d\n", + card->devname,i); + continue; + } + + if (!wan_test_bit(0,&chan->up)){ + continue; + } + + if (chan->channelized_cfg && !chan->hdlc_eng){ + wan_set_bit(i,&dma_tx_voice); + continue; + } + +#if 0 + chan->if_stats.rx_frame_errors++; +#endif + + DEBUG_ISR("%s: RX Interrupt pend. \n", + card->devname); + +#ifdef AFT_IRQ_DEBUG + card->wandev.stats.rx_bytes++; + if (SYSTEM_TICKS-card->u.aft.rx_timeout >= HZ){ + card->wandev.stats.tx_bytes=card->wandev.stats.rx_bytes; + card->wandev.stats.rx_bytes=0; + card->u.aft.rx_timeout=SYSTEM_TICKS; + } +#endif + + aft_dma_rx_complete(card,chan,0); + + +#if 0 + if (chan->cfg.tdmv_master_if && !chan->tdmv_irq_cfg){ + aft_channel_rxintr_ctrl(card,chan,1); + DEBUG_EVENT("%s: Master dev %s Synched to master irq\n", + card->devname,chan->if_name); + chan->tdmv_irq_cfg=1; + } +#endif + } + } + + +isr_skb_rx: + + /* Transmit DMA Engine */ + card->hw_iface.bus_read_4(card->hw, + AFT_PORT_REG(card,AFT_TX_DMA_INTR_PENDING_REG), + &dma_tx_reg); + + dma_tx_reg&=card->u.aft.active_ch_map; + + dma_tx_reg&=~dma_tx_voice; + + if (dma_tx_reg == 0){ + goto isr_skb_tx; + } + + for (i=0; iu.aft.logic_ch_map)){ + chan=(private_area_t*)card->u.aft.dev_to_ch_map[i]; + if (!chan){ + DEBUG_EVENT("%s: Error: No Dev for Tx logical ch=%d\n", + card->devname,i); + continue; + } + + if (chan->channelized_cfg && !chan->hdlc_eng){ + continue; + } + + DEBUG_TEST("---- TX Interrupt pend. --\n"); + aft_dma_tx_complete(card,chan,0,0); + }else{ + DEBUG_TEST("Failed Testing for Tx Timeslot %d TxReg=0x%X ChMap=0x%lX\n",i, + dma_tx_reg,card->u.aft.logic_ch_map); + } + } + +isr_skb_tx: + DEBUG_ISR("---- ISR SKB TX end.-------------------\n"); + + +} + + +static void wp_aft_tdmv_per_port_isr(sdla_t *card) +{ + int i; + private_area_t *chan; + +#if 0 + DEBUG_EVENT("%s: TDMV Interrupt LogicCh=%i\n", + card->devname,card->u.aft.num_of_time_slots); +#endif + /* -----------------2/6/2003 9:37AM------------------ + * Checking for Interrupt source: + * 1. Receive DMA Engine + * 2. Transmit DMA Engine + * 3. Error conditions. + * --------------------------------------------------*/ + + + for (i=0; iu.aft.num_of_time_slots;i++){ + + if (!wan_test_bit(i,&card->u.aft.logic_ch_map)){ + continue; + } + + chan=(private_area_t*)card->u.aft.dev_to_ch_map[i]; + if (!chan){ + DEBUG_EVENT("%s: Error: No Dev for Rx logical ch=%d\n", + card->devname,i); + continue; + } + + if (!wan_test_bit(0,&chan->up)){ + continue; + } + + if (chan->channelized_cfg && !chan->hdlc_eng){ + aft_dma_rx_tdmv(card,chan); + } + +#if 0 + chan->if_stats.rx_frame_errors++; +#endif + + DEBUG_ISR("%s: RX Interrupt pend. \n", + card->devname); + + } +} + + + + + +static void wp_aft_wdt_per_port_isr(sdla_t *card, int wdt_intr) +{ + int i,wdt_disable = 0; + int timeout=AFT_WDTCTRL_TIMEOUT; + + aft_wdt_reset(card); + + for (i=0; iu.aft.num_of_time_slots;i++){ + + private_area_t *chan; + + if (!wan_test_bit(i,&card->u.aft.logic_ch_map)){ + continue; + } + + chan=(private_area_t*)card->u.aft.dev_to_ch_map[i]; + if (!chan){ + continue; + } + + if (!wan_test_bit(0,&chan->up) || + wan_test_bit(0,&chan->interface_down)){ + continue; + } + +#if 0 + if (wdt_intr){ + ++chan->if_stats.tx_dropped; + }else{ + ++chan->if_stats.tx_errors; + } +#endif + + if (card->wandev.state == WAN_CONNECTED){ + + if (chan->single_dma_chain && !chan->hdlc_eng){ + wdt_disable=1; + continue; + } +#if 0 + ++chan->if_stats.tx_errors; +#endif + aft_dma_tx_complete (card,chan,1,0); + + } + +#if defined(CONFIG_PRODUCT_WANPIPE_TDM_VOICE) + else{ + if (chan->tdmv_zaptel_cfg && + wan_test_bit(0,&chan->up) && + chan->cfg.tdmv_master_if){ + /* If the line becomes disconnected + * keep calling TDMV zaptel in order to + * provide timing */ + if (wdt_intr && chan->cfg.tdmv_master_if){ + int err; +#if 0 + ++chan->if_stats.tx_dropped; +#endif + WAN_TDMV_CALL(rx_tx_span, (card), err); + + if (card->wan_tdmv.sc){ + WAN_TDMV_CALL(is_rbsbits, (&card->wan_tdmv), err); + if (err == 1){ + wan_set_bit(AFT_FE_TDM_RBS,&card->u.aft.port_task_cmd); + WAN_TASKQ_SCHEDULE((&card->u.aft.port_task)); + } + } + + timeout=1; + } + } + } +#endif + } + +#ifdef AFT_WDT_ENABLE + if (!wdt_disable){ + aft_wdt_set(card,timeout); + } +#endif + + return; + +} + +/**SECTION*********************************************************** + * + * WANPIPE Debugging Interfaces + * + ********************************************************************/ + + + +/*============================================================================= + * process_udp_mgmt_pkt + * + * Process all "wanpipemon" debugger commands. This function + * performs all debugging tasks: + * + * Line Tracing + * Line/Hardware Statistics + * Protocol Statistics + * + * "wanpipemon" utility is a user-space program that + * is used to debug the WANPIPE product. + * + */ +#if 1 +static int process_udp_mgmt_pkt(sdla_t* card, netdevice_t* dev, + private_area_t* chan, int local_dev ) +{ + unsigned short buffer_length; + wan_udp_pkt_t *wan_udp_pkt; + wan_trace_t *trace_info=NULL; + + wan_udp_pkt = (wan_udp_pkt_t *)chan->udp_pkt_data; + + if (wan_atomic_read(&chan->udp_pkt_len) == 0){ + return -ENODEV; + } + + trace_info=&chan->trace_info; + wan_udp_pkt = (wan_udp_pkt_t *)chan->udp_pkt_data; + + { + + netskb_t *skb; + + wan_udp_pkt->wan_udp_opp_flag = 0; + + switch(wan_udp_pkt->wan_udp_command) { + + case READ_CONFIGURATION: + wan_udp_pkt->wan_udp_return_code = 0; + wan_udp_pkt->wan_udp_data_len=0; + break; + + case READ_CODE_VERSION: + wan_udp_pkt->wan_udp_return_code = 0; + wan_udp_pkt->wan_udp_data[0]=card->u.aft.firm_ver; + wan_udp_pkt->wan_udp_data_len=1; + break; + + case AFT_LINK_STATUS: + wan_udp_pkt->wan_udp_return_code = 0; + if (card->wandev.state == WAN_CONNECTED){ + wan_udp_pkt->wan_udp_data[0]=1; + }else{ + wan_udp_pkt->wan_udp_data[0]=0; + } + wan_udp_pkt->wan_udp_data_len=1; + break; + + case AFT_MODEM_STATUS: + wan_udp_pkt->wan_udp_return_code = 0; + if (card->wandev.state == WAN_CONNECTED){ + wan_udp_pkt->wan_udp_data[0]=0x28; + }else{ + wan_udp_pkt->wan_udp_data[0]=0; + } + wan_udp_pkt->wan_udp_data_len=1; + break; + + + case READ_OPERATIONAL_STATS: + wan_udp_pkt->wan_udp_return_code = 0; + memcpy(wan_udp_pkt->wan_udp_data,&chan->opstats,sizeof(aft_op_stats_t)); + wan_udp_pkt->wan_udp_data_len=sizeof(aft_op_stats_t); + break; + + case FLUSH_OPERATIONAL_STATS: + wan_udp_pkt->wan_udp_return_code = 0; + memset(&chan->opstats,0,sizeof(aft_op_stats_t)); + wan_udp_pkt->wan_udp_data_len=0; + break; + + case READ_COMMS_ERROR_STATS: + wan_udp_pkt->wan_udp_return_code = 0; + memcpy(wan_udp_pkt->wan_udp_data,&chan->errstats,sizeof(aft_comm_err_stats_t)); + wan_udp_pkt->wan_udp_data_len=sizeof(aft_comm_err_stats_t); + break; + + case FLUSH_COMMS_ERROR_STATS: + wan_udp_pkt->wan_udp_return_code = 0; + memset(&chan->errstats,0,sizeof(aft_comm_err_stats_t)); + wan_udp_pkt->wan_udp_data_len=0; + break; + + + case ENABLE_TRACING: + + wan_udp_pkt->wan_udp_return_code = WAN_CMD_OK; + wan_udp_pkt->wan_udp_data_len = 0; + + if (!wan_test_bit(0,&trace_info->tracing_enabled)){ + + trace_info->trace_timeout = SYSTEM_TICKS; + + wan_trace_purge(trace_info); + + if (wan_udp_pkt->wan_udp_data[0] == 0){ + wan_clear_bit(1,&trace_info->tracing_enabled); + DEBUG_UDP("%s: ADSL L3 trace enabled!\n", + card->devname); + }else if (wan_udp_pkt->wan_udp_data[0] == 1){ + wan_clear_bit(2,&trace_info->tracing_enabled); + wan_set_bit(1,&trace_info->tracing_enabled); + DEBUG_UDP("%s: ADSL L2 trace enabled!\n", + card->devname); + }else{ + wan_clear_bit(1,&trace_info->tracing_enabled); + wan_set_bit(2,&trace_info->tracing_enabled); + DEBUG_UDP("%s: ADSL L1 trace enabled!\n", + card->devname); + } + wan_set_bit (0,&trace_info->tracing_enabled); + + }else{ + DEBUG_EVENT("%s: Error: ATM trace running!\n", + card->devname); + wan_udp_pkt->wan_udp_return_code = 2; + } + + break; + + case DISABLE_TRACING: + + wan_udp_pkt->wan_udp_return_code = WAN_CMD_OK; + + if(wan_test_bit(0,&trace_info->tracing_enabled)) { + + wan_clear_bit(0,&trace_info->tracing_enabled); + wan_clear_bit(1,&trace_info->tracing_enabled); + wan_clear_bit(2,&trace_info->tracing_enabled); + + wan_trace_purge(trace_info); + + DEBUG_UDP("%s: Disabling AFT trace\n", + card->devname); + + }else{ + /* set return code to line trace already + disabled */ + wan_udp_pkt->wan_udp_return_code = 1; + } + + break; + + case GET_TRACE_INFO: + + if(wan_test_bit(0,&trace_info->tracing_enabled)){ + trace_info->trace_timeout = SYSTEM_TICKS; + }else{ + DEBUG_EVENT("%s: Error ATM trace not enabled\n", + card->devname); + /* set return code */ + wan_udp_pkt->wan_udp_return_code = 1; + break; + } + + buffer_length = 0; + wan_udp_pkt->wan_udp_atm_num_frames = 0; + wan_udp_pkt->wan_udp_atm_ismoredata = 0; + +#if defined(__FreeBSD__) || defined(__OpenBSD__) + while (wan_skb_queue_len(&trace_info->trace_queue)){ + WAN_IFQ_POLL(&trace_info->trace_queue, skb); + if (skb == NULL){ + DEBUG_EVENT("%s: No more trace packets in trace queue!\n", + card->devname); + break; + } + if ((WAN_MAX_DATA_SIZE - buffer_length) < skb->m_pkthdr.len){ + /* indicate there are more frames on board & exit */ + wan_udp_pkt->wan_udp_atm_ismoredata = 0x01; + break; + } + + m_copydata(skb, + 0, + skb->m_pkthdr.len, + &wan_udp_pkt->wan_udp_data[buffer_length]); + buffer_length += skb->m_pkthdr.len; + WAN_IFQ_DEQUEUE(&trace_info->trace_queue, skb); + if (skb){ + wan_skb_free(skb); + } + wan_udp_pkt->wan_udp_atm_num_frames++; + } +#elif defined(__LINUX__) + while ((skb=skb_dequeue(&trace_info->trace_queue)) != NULL){ + + if((MAX_TRACE_BUFFER - buffer_length) < wan_skb_len(skb)){ + /* indicate there are more frames on board & exit */ + wan_udp_pkt->wan_udp_atm_ismoredata = 0x01; + if (buffer_length != 0){ + wan_skb_queue_head(&trace_info->trace_queue, skb); + }else{ + /* If rx buffer length is greater than the + * whole udp buffer copy only the trace + * header and drop the trace packet */ + + memcpy(&wan_udp_pkt->wan_udp_atm_data[buffer_length], + wan_skb_data(skb), + sizeof(wan_trace_pkt_t)); + + buffer_length = sizeof(wan_trace_pkt_t); + wan_udp_pkt->wan_udp_atm_num_frames++; + wan_skb_free(skb); + } + break; + } + + memcpy(&wan_udp_pkt->wan_udp_atm_data[buffer_length], + wan_skb_data(skb), + wan_skb_len(skb)); + + buffer_length += wan_skb_len(skb); + wan_skb_free(skb); + wan_udp_pkt->wan_udp_atm_num_frames++; + } +#endif + /* set the data length and return code */ + wan_udp_pkt->wan_udp_data_len = buffer_length; + wan_udp_pkt->wan_udp_return_code = WAN_CMD_OK; + break; + + case ROUTER_UP_TIME: + wan_getcurrenttime(&chan->router_up_time, NULL); + chan->router_up_time -= chan->router_start_time; + *(unsigned long *)&wan_udp_pkt->wan_udp_data = + chan->router_up_time; + wan_udp_pkt->wan_udp_data_len = sizeof(unsigned long); + wan_udp_pkt->wan_udp_return_code = 0; + break; + + case WAN_GET_MEDIA_TYPE: + if (card->wandev.fe_iface.get_fe_media){ + wan_udp_pkt->wan_udp_data[0] = + card->wandev.fe_iface.get_fe_media(&card->fe); + wan_udp_pkt->wan_udp_return_code = WAN_CMD_OK; + wan_udp_pkt->wan_udp_data_len = sizeof(unsigned char); + }else{ + wan_udp_pkt->wan_udp_return_code = WAN_UDP_INVALID_CMD; + } + break; +#if 0 + case WAN_FE_GET_STAT: + case WAN_FE_SET_LB_MODE: + case WAN_FE_FLUSH_PMON: + case WAN_FE_GET_CFG: + case WAN_FE_SET_DEBUG_MODE: + case WAN_FE_TX_MODE: + + if (IS_TE1_CARD(card)){ + wan_smp_flag_t smp_flags; + card->hw_iface.hw_lock(card->hw,&smp_flags); + card->wandev.fe_iface.process_udp( + &card->fe, + &wan_udp_pkt->wan_udp_cmd, + &wan_udp_pkt->wan_udp_data[0]); + card->hw_iface.hw_unlock(card->hw,&smp_flags); + }else{ + wan_udp_pkt->wan_udp_return_code = WAN_UDP_INVALID_CMD; + } + break; +#endif + + case WAN_GET_PROTOCOL: + wan_udp_pkt->wan_udp_aft_num_frames = card->wandev.config_id; + wan_udp_pkt->wan_udp_return_code = CMD_OK; + wan_udp_pkt->wan_udp_data_len = 1; + break; + + case WAN_GET_PLATFORM: + wan_udp_pkt->wan_udp_data[0] = WAN_PLATFORM_ID; + wan_udp_pkt->wan_udp_return_code = CMD_OK; + wan_udp_pkt->wan_udp_data_len = 1; + break; + + case WAN_GET_MASTER_DEV_NAME: + wan_udp_pkt->wan_udp_data_len = 0; + wan_udp_pkt->wan_udp_return_code = 0xCD; + break; + + case AFT_HWEC_STATUS: + *(unsigned long *)&wan_udp_pkt->wan_udp_data[0] = + IS_E1_CARD(card) ? card->wandev.ec_map: + card->wandev.ec_map << 1; + wan_udp_pkt->wan_udp_data_len = sizeof(unsigned long); + wan_udp_pkt->wan_udp_return_code = 0; + break; + + default: + if ((wan_udp_pkt->wan_udp_command & 0xF0) == WAN_FE_UDP_CMD_START){ + /* FE udp calls */ + wan_smp_flag_t smp_flags,smp_flags1; + wan_spin_lock_irq(&card->wandev.lock,&smp_flags1); + card->hw_iface.hw_lock(card->hw,&smp_flags); + card->wandev.fe_iface.process_udp( + &card->fe, + &wan_udp_pkt->wan_udp_cmd, + &wan_udp_pkt->wan_udp_data[0]); + card->hw_iface.hw_unlock(card->hw,&smp_flags); + wan_spin_unlock_irq(&card->wandev.lock,&smp_flags1); + break; + } + wan_udp_pkt->wan_udp_data_len = 0; + wan_udp_pkt->wan_udp_return_code = 0xCD; + + if (WAN_NET_RATELIMIT()){ + DEBUG_EVENT( + "%s: Warning, Illegal UDP command attempted from network: %x\n", + card->devname,wan_udp_pkt->wan_udp_command); + } + break; + } /* end of switch */ + } /* end of else */ + + /* Fill UDP TTL */ + wan_udp_pkt->wan_ip_ttl= card->wandev.ttl; + + wan_udp_pkt->wan_udp_request_reply = UDPMGMT_REPLY; + return 1; + +} +#endif + + + +/**SECTION************************************************************* + * + * TASK Functions and Triggers + * + **********************************************************************/ + + +/*============================================================================ + * port_set_state + * + * Set PORT state. + * + */ +static void port_set_state (sdla_t *card, int state) +{ + struct wan_dev_le *devle; + netdevice_t *dev; + + if (card->wandev.state != state) + { +#if 0 + switch (state) + { + case WAN_CONNECTED: + DEBUG_EVENT( "%s: Front End Link connected!\n", + card->devname); + break; + + case WAN_CONNECTING: + DEBUG_EVENT( "%s: Front End Link connecting...\n", + card->devname); + break; + + case WAN_DISCONNECTED: + DEBUG_EVENT( "%s: Front End Link disconnected!\n", + card->devname); + break; + } +#endif + card->wandev.state = state; + WAN_LIST_FOREACH(devle, &card->wandev.dev_head, dev_link){ + dev = WAN_DEVLE2DEV(devle); + if (!dev) continue; + set_chan_state(card, dev, state); + } + } +} + +/*============================================================ + * handle_front_end_state + * + * Front end state indicates the physical medium that + * the Z80 backend connects to. + * + * S514-1/2/3: V32/RS232/FT1 Front End + * Front end state is determined via + * Modem/Status. + * S514-4/5/7/8: 56K/T1/E1 Front End + * Front end state is determined via + * link status interrupt received + * from the front end hardware. + * + * If the front end state handler is enabed by the + * user. The interface state will follow the + * front end state. I.E. If the front end goes down + * the protocol and interface will be declared down. + * + * If the front end state is UP, then the interface + * and protocol will be up ONLY if the protocol is + * also UP. + * + * Therefore, we must have three state variables + * 1. Front End State (card->wandev.front_end_status) + * 2. Protocol State (card->wandev.state) + * 3. Interface State (dev->flags & IFF_UP) + * + */ + +static void handle_front_end_state(void *card_id) +{ + sdla_t *card = (sdla_t*)card_id; + + if (card->wandev.ignore_front_end_status == WANOPT_YES){ + return; + } + + if (!wan_test_bit(AFT_CHIP_CONFIGURED,&card->u.aft.chip_cfg_status) && + card->fe.fe_status == FE_CONNECTED){ + DEBUG_TEST("%s: Skipping Front Front End State = %x\n", + card->devname,card->fe.fe_status); + + wan_set_bit(AFT_FRONT_END_UP,&card->u.aft.chip_cfg_status); + return; + } + + if (card->fe.fe_status == FE_CONNECTED){ + if (card->wandev.state != WAN_CONNECTED){ + + port_set_state(card,WAN_CONNECTED); + +#if defined(CONFIG_PRODUCT_WANPIPE_TDM_VOICE) + if (card->wan_tdmv.sc){ + int err; + WAN_TDMV_CALL(state, (card, WAN_CONNECTED), err); + } +#endif + wan_set_bit(AFT_FE_LED,&card->u.aft.port_task_cmd); + /* WAN_TASKQ_SCHEDULE((&card->u.aft.port_task)); */ + + if (card->u.aft.cfg.tdmv_span_no && + !wan_test_bit(0,&card->u.aft.tdmv_master_if_up)){ + DEBUG_EVENT("%s: Skipping AFT Communication wait for MasterIF\n", + card->devname); + return; + } + + enable_data_error_intr(card); + + } + }else{ + if (card->wandev.state == WAN_CONNECTED){ + disable_data_error_intr(card,LINK_DOWN); + port_set_state(card,WAN_DISCONNECTED); + + wan_set_bit(AFT_FE_LED,&card->u.aft.port_task_cmd); + /* WAN_TASKQ_SCHEDULE((&card->u.aft.port_task)); */ + + +#if defined(CONFIG_PRODUCT_WANPIPE_TDM_VOICE) + if (card->wan_tdmv.sc){ + int err; + WAN_TDMV_CALL(state, (card, WAN_DISCONNECTED), err); + } +#endif + } + } + +} + +unsigned char aft_read_cpld(sdla_t *card, unsigned short cpld_off) +{ + return aft_hwdev[card->wandev.card_type].aft_read_cpld(card,cpld_off); +} + +int aft_write_cpld(void *pcard, unsigned short off,unsigned char data) +{ + sdla_t *card = (sdla_t *)pcard; + return aft_hwdev[card->wandev.card_type].aft_write_cpld(card,off,data); +} + +#if 0 +/*============================================================================ + * Read TE1/56K Front end registers + */ +static unsigned char +write_front_end_reg (void* card1, unsigned short off, unsigned char value) +{ + sdla_t* card = (sdla_t*)card1; + + if (card->wandev.card_type == WANOPT_AFT_ANALOG){ + DEBUG_EVENT("%s: Internal Error (%s:%d)\n", + card->devname, __FUNCTION__,__LINE__); + return 0x00; + } + return aft_hwdev[card->wandev.card_type].aft_write_fe(card1,off,value); +} + +/*============================================================================ + * Read TE1/56K Front end registers + */ +static unsigned char +read_front_end_reg (void* card1, unsigned short off) +{ + sdla_t* card = (sdla_t*)card1; + + if (card->wandev.card_type == WANOPT_AFT_ANALOG){ + DEBUG_EVENT("%s: Internal Error (%s:%d)\n", + card->devname, __FUNCTION__,__LINE__); + return 0x00; + } + return aft_hwdev[card->wandev.card_type].aft_read_fe(card1,off); +} +#endif + +static unsigned char +aft_write_ec (void* card1, unsigned short off, unsigned char value) +{ + DEBUG_EVENT("ADEBUG: Write Octasic Offset %04X Value %02X!\n", + off, value); + return 0; +} + +/*============================================================================ + * Read from Octasic board + */ +static unsigned char +aft_read_ec (void* card1, unsigned short off) +{ + u8 value = 0x00; + + DEBUG_EVENT("ADEBUG: Read Octasic offset %04X Value %02X (temp)!\n", + off, value); + return value; +} + + + +static int aft_read(sdla_t *card, wan_cmd_api_t *api_cmd) +{ + if(api_cmd->len == 1){ + if (api_cmd->offset <= 0x3C){ + card->hw_iface.pci_read_config_byte( + card->hw, + api_cmd->offset, + (u8*)&api_cmd->data[0]); + }else{ + card->hw_iface.bus_read_1( + card->hw, + api_cmd->offset, + (u8*)&api_cmd->data[0]); + } + }else if (api_cmd->len == 2){ + if (api_cmd->offset <= 0x3C){ + card->hw_iface.pci_read_config_word( + card->hw, + api_cmd->offset, + (u16*)&api_cmd->data[0]); + }else{ + card->hw_iface.bus_read_2( + card->hw, + api_cmd->offset, + (u16*)&api_cmd->data[0]); + } + }else if (api_cmd->len == 4){ + if (api_cmd->offset <= 0x3C){ + card->hw_iface.pci_read_config_dword(card->hw, + api_cmd->offset, + (u32*)&api_cmd->data[0]); + }else{ + card->hw_iface.bus_read_4( + card->hw, + api_cmd->offset, + (u32*)&api_cmd->data[0]); + } + }else{ + card->hw_iface.peek(card->hw, + api_cmd->offset, + &api_cmd->data[0], + api_cmd->len); + } + +#if defined(DEBUG_REG) + DEBUG_EVENT("%s: Reading Bar%d Offset=0x%X Data=%08X Len=%d\n", + card->devname, + api_cmd->bar, + api_cmd->offset, + *(u32*)&api_cmd->data[0], + api_cmd->len); +#endif + + return 0; +} + +static int aft_fe_read(sdla_t *card, wan_cmd_api_t *api_cmd) +{ + wan_smp_flag_t smp_flags; + + card->hw_iface.hw_lock(card->hw,&smp_flags); + api_cmd->data[0] = (u8)card->fe.read_fe_reg(card, (int)api_cmd->offset); + card->hw_iface.hw_unlock(card->hw,&smp_flags); + +#ifdef DEB_XILINX + DEBUG_EVENT("%s: Reading Bar%d Offset=0x%X Len=%d Val=%02X\n", + card->devname,api_cmd->bar,api_cmd->offset,api_cmd->len, api_cmd->data[0]); +#endif + + return 0; +} + +static int aft_write(sdla_t *card, wan_cmd_api_t *api_cmd) +{ + + if (api_cmd->len == 1){ + card->hw_iface.bus_write_1( + card->hw, + api_cmd->offset, + *(u8*)&api_cmd->data[0]); +#if defined(DEBUG_REG) + DEBUG_EVENT("%s: Write Offset=0x%08X Data=0x%02X\n", + card->devname,api_cmd->offset, + *(u8*)&api_cmd->data[0]); +#endif + }else if (api_cmd->len == 2){ + card->hw_iface.bus_write_2( + card->hw, + api_cmd->offset, + *(u16*)&api_cmd->data[0]); +#if defined(DEBUG_REG) + DEBUG_EVENT("%s: Write Offset=0x%08X Data=0x%04X\n", + card->devname,api_cmd->offset, + *(unsigned short*)&api_cmd->data[0]); +#endif + }else if (api_cmd->len == 4){ + card->hw_iface.bus_write_4( + card->hw, + api_cmd->offset, + *(unsigned int*)&api_cmd->data[0]); +#if defined(DEBUG_REG) + DEBUG_EVENT("ADEBUG: %s: Write Offset=0x%08X Data=0x%08X\n", + card->devname,api_cmd->offset, + *(u32*)&api_cmd->data[0]); +#endif + }else{ + card->hw_iface.poke( + card->hw, + api_cmd->offset, + (u8*)&api_cmd->data[0], + api_cmd->len); +#if 0 + memcpy_toio((unsigned char*)vector, + (unsigned char*)&api_cmd->data[0], api_cmd->len); +#endif + } + + return 0; +} + +static int aft_fe_write(sdla_t *card, wan_cmd_api_t *api_cmd) +{ + wan_smp_flag_t smp_flags; + +#ifdef DEB_XILINX + DEBUG_EVENT("%s: Writting Bar%d Offset=0x%X Len=%d Val=%02X\n", + card->devname, + api_cmd->bar, + api_cmd->offset, + api_cmd->len, + api_cmd->data[0]); +#endif + + + card->hw_iface.hw_lock(card->hw,&smp_flags); + card->fe.write_fe_reg (card, (int)api_cmd->offset, (int)api_cmd->data[0]); + card->hw_iface.hw_unlock(card->hw,&smp_flags); + + return 0; + +} + + + +static int aft_write_bios(sdla_t *card, wan_cmd_api_t *api_cmd) +{ + +#ifdef DEB_XILINX + DEBUG_EVENT("Setting PCI 0xX=0x%08lX 0x3C=0x%08X\n", + (card->wandev.S514_cpu_no[0] == SDLA_CPU_A) ? 0x10 : 0x14, + card->u.aft.bar,card->wandev.irq); +#endif + card->hw_iface.pci_write_config_dword(card->hw, + (card->wandev.S514_cpu_no[0] == SDLA_CPU_A) ? 0x10 : 0x14, + card->u.aft.bar); + card->hw_iface.pci_write_config_dword(card->hw, 0x3C, card->wandev.irq); + card->hw_iface.pci_write_config_dword(card->hw, 0x0C, 0x0000ff00); + + return 0; +} + +#if 0 +extern int OctDrvIoctl(sdla_t*, int cmd, void*); +#endif + +static int aft_hwec(sdla_t *card, wan_cmd_api_t *api_cmd) +{ + +#if 0 + if (api_cmd->offset){ + /* Use direct read/write to/from octasic chip */ + if (api_cmd->len){ + /* Write */ + aft_write_ec (card, api_cmd->offset, api_cmd->data[0]); + }else{ + /* Read */ + api_cmd->data[0] = aft_read_ec (card, api_cmd->offset); + api_cmd->len = 1; + } + }else +#endif + { +#if 0 + OctDrvIoctl(card, api_cmd->cmd, api_cmd->data); +#endif + } + + return 0; +} + +static int aft_devel_ioctl(sdla_t *card, struct ifreq *ifr) +{ + wan_cmd_api_t api_cmd; + int err = -EINVAL; + + if (!ifr || !ifr->ifr_data){ + DEBUG_EVENT("%s: Error: No ifr or ifr_data\n",__FUNCTION__); + return -EFAULT; + } + + if (WAN_COPY_FROM_USER(&api_cmd,ifr->ifr_data,sizeof(wan_cmd_api_t))){ + return -EFAULT; + } + + switch(api_cmd.cmd){ + case SIOC_WAN_READ_REG: + err=aft_read(card, &api_cmd); + break; + case SIOC_WAN_WRITE_REG: + err=aft_write(card, &api_cmd); + break; + + case SIOC_WAN_FE_READ_REG: + err=aft_fe_read(card, &api_cmd); + break; + + case SIOC_WAN_FE_WRITE_REG: + err=aft_fe_write(card, &api_cmd); + break; + + case SIOC_WAN_SET_PCI_BIOS: + err=aft_write_bios(card, &api_cmd); + break; + + case SIOC_WAN_EC_REG: + err = aft_hwec(card, &api_cmd); + break; + } + if (WAN_COPY_TO_USER(ifr->ifr_data,&api_cmd,sizeof(wan_cmd_api_t))){ + return -EFAULT; + } + return err; +} + + +/*========================================= + * enable_data_error_intr + * + * Description: + * + * Run only after the front end comes + * up from down state. + * + * Clean the DMA Tx/Rx pending interrupts. + * (Ignore since we will reconfigure + * all dma descriptors. DMA controler + * was already disabled on link down) + * + * For all channels clean Tx/Rx Fifo + * + * Enable DMA controler + * (This starts the fifo cleaning + * process) + * + * For all channels reprogram Tx/Rx DMA + * descriptors. + * + * Clean the Tx/Rx Error pending interrupts. + * (Since dma fifo's are now empty) + * + * Enable global DMA and Error interrutps. + * + */ + +static void enable_data_error_intr(sdla_t *card) +{ + u32 reg; + int i,err; + + DEBUG_TEST("%s: %s()\n",card->devname,__FUNCTION__); + + + card->hw_iface.bus_read_4(card->hw,AFT_PORT_REG(card,AFT_LINE_CFG_REG), ®); + if (wan_test_bit(AFT_LCFG_FE_IFACE_RESET_BIT,®)){ + DEBUG_EVENT("%s: Warning: Skipping data enable wait for cfg!\n", + card->devname); + return; + } + +#if 0 + aft_list_dma_chain_regs(card); +#endif + + if (card->u.aft.cfg.tdmv_span_no && + !wan_test_bit(0,&card->u.aft.tdmv_master_if_up)){ + DEBUG_EVENT("%s: Critical error: Enable Card while Master If Not up!\n", + card->devname); + } + + if (wan_test_bit(0,&card->u.aft.comm_enabled)){ + disable_data_error_intr(card,LINK_DOWN); + } + + aft_wdt_reset(card); + + /* Clean Tx/Rx DMA interrupts */ + card->hw_iface.bus_read_4(card->hw, + AFT_PORT_REG(card,AFT_TX_DMA_INTR_PENDING_REG), + ®); + + card->hw_iface.bus_read_4(card->hw, + AFT_PORT_REG(card,AFT_RX_DMA_INTR_PENDING_REG), + ®); + + + err=aft_hwdev[card->wandev.card_type].aft_test_sync(card,0); + if (err){ + card->hw_iface.bus_read_4(card->hw,AFT_PORT_REG(card,AFT_LINE_CFG_REG), ®); + DEBUG_EVENT("%s: Error: Front End Interface out of sync! (0x%X)\n", + card->devname,reg); + + /*FIXME: How to recover from here, should never happen */ + } + + + for (i=0; iu.aft.num_of_time_slots;i++){ + private_area_t *chan; + + if (!wan_test_bit(i,&card->u.aft.logic_ch_map)){ + continue; + } + + chan=(private_area_t*)card->u.aft.dev_to_ch_map[i]; + if (!chan){ + continue; + } + + if (!wan_test_bit(0,&chan->up)){ + continue; + } + + + DEBUG_TEST("%s: 1) Free Used DMA CHAINS %s\n", + card->devname,chan->if_name); + + aft_free_rx_complete_list(chan); + aft_free_rx_descriptors(chan); + + DEBUG_TEST("%s: 1) Free UNUSED DMA CHAINS %s\n", + card->devname,chan->if_name); + + wan_clear_bit(TX_INTR_PENDING,&chan->dma_chain_status); + + if (chan->channelized_cfg && !chan->hdlc_eng){ + aft_tx_dma_voice_handler((unsigned long)chan,0,1); + }else{ + aft_tx_dma_chain_handler((unsigned long)chan,0,1); + } + + aft_free_tx_descriptors(chan); + + DEBUG_TEST("%s: 2) Init interface fifo no wait %s\n", + card->devname,chan->if_name); + + aft_tslot_sync_ctrl(card,chan,0); + + aft_init_rx_dev_fifo(card, chan, WP_NO_WAIT); + aft_init_tx_dev_fifo(card, chan, WP_NO_WAIT); + + } + + + /* Enable Global DMA controler, in order to start the + * fifo cleaning */ + card->hw_iface.bus_read_4(card->hw,AFT_PORT_REG(card,AFT_DMA_CTRL_REG),®); + wan_set_bit(AFT_DMACTRL_GLOBAL_INTR_BIT,®); + card->hw_iface.bus_write_4(card->hw,AFT_PORT_REG(card,AFT_DMA_CTRL_REG),reg); + + /* For all channels clean Tx/Rx fifos */ + + for (i=0; iu.aft.num_of_time_slots;i++){ + private_area_t *chan; + + if (!wan_test_bit(i,&card->u.aft.logic_ch_map)){ + continue; + } + + chan=(private_area_t*)card->u.aft.dev_to_ch_map[i]; + if (!chan){ + continue; + } + + if (!wan_test_bit(0,&chan->up)){ + continue; + } + + + DEBUG_TEST("%s: 3) Init interface fifo %s\n", + card->devname,chan->if_name); + + aft_init_rx_dev_fifo(card, chan, WP_WAIT); + aft_init_tx_dev_fifo(card, chan, WP_WAIT); + + DEBUG_TEST("%s: Clearing Fifo and idle_flag %s\n", + card->devname,chan->if_name); + wan_clear_bit(0,&chan->idle_start); + } +#if 0 + aft_list_dma_chain_regs(card); +#endif + /* For all channels, reprogram Tx/Rx DMA descriptors. + * For Tx also make sure that the BUSY flag is clear + * and previoulsy Tx packet is deallocated */ + + for (i=0; iu.aft.num_of_time_slots;i++){ + private_area_t *chan; + + if (!wan_test_bit(i,&card->u.aft.logic_ch_map)){ + continue; + } + + chan=(private_area_t*)card->u.aft.dev_to_ch_map[i]; + if (!chan){ + continue; + } + + if (!wan_test_bit(0,&chan->up)){ + continue; + } + + DEBUG_TEST("%s: 4) Init interface %s\n", + card->devname,chan->if_name); + + chan->dma_index=0; + memset(chan->dma_history,0,sizeof(chan->dma_history)); + + aft_reset_rx_chain_cnt(chan); + +#if 0 + aft_list_descriptors(chan); +#endif + + aft_dma_rx(card,chan); + aft_tslot_sync_ctrl(card,chan,1); + + DEBUG_TEST("%s: DMA RX SETUP %s\n", + card->devname,chan->if_name); +#if 0 + aft_list_descriptors(chan); +#endif + } + + /* Clean Tx/Rx Error interrupts, since fifos are now + * empty, and Tx fifo may generate an underrun which + * we want to ignore :) */ + + + for (i=0; iu.aft.num_of_time_slots;i++){ + private_area_t *chan; + + if (!wan_test_bit(i,&card->u.aft.logic_ch_map)){ + continue; + } + + chan=(private_area_t*)card->u.aft.dev_to_ch_map[i]; + if (!chan){ + continue; + } + + if (!wan_test_bit(0,&chan->up)){ + continue; + } + + if (!chan->hdlc_eng){ + aft_reset_tx_chain_cnt(chan); + aft_dma_tx(card,chan); + } + + if (chan->cfg.ss7_enable){ + aft_clear_ss7_force_rx(card,chan); + } + } + + card->hw_iface.bus_read_4(card->hw, + AFT_PORT_REG(card,AFT_RX_FIFO_INTR_PENDING_REG), + ®); + card->hw_iface.bus_read_4(card->hw, + AFT_PORT_REG(card,AFT_TX_FIFO_INTR_PENDING_REG), + ®); + + /* Enable Global DMA and Error Interrupts */ + card->hw_iface.bus_read_4(card->hw, + AFT_PORT_REG(card,AFT_LINE_CFG_REG), ®); + + wan_set_bit(AFT_LCFG_DMA_INTR_BIT,®); + wan_clear_bit(AFT_LCFG_FIFO_INTR_BIT,®); + if (card->u.aft.cfg.tdmv_span_no){ + wan_set_bit(AFT_LCFG_TDMV_INTR_BIT,®); + } + card->hw_iface.bus_write_4(card->hw, + AFT_PORT_REG(card,AFT_LINE_CFG_REG), reg); + + card->u.aft.lcfg_reg=reg; + + + wan_set_bit(0,&card->u.aft.comm_enabled); + DEBUG_EVENT("%s: AFT communications enabled!\n", + card->devname); + + /* Enable Channelized Driver if configured */ + if (card->u.aft.cfg.tdmv_span_no){ + + card->hw_iface.bus_read_4(card->hw, + AFT_PORT_REG(card,AFT_RX_FIFO_INTR_PENDING_REG), + ®); + card->hw_iface.bus_read_4(card->hw, + AFT_PORT_REG(card,AFT_TX_FIFO_INTR_PENDING_REG), + ®); + + card->hw_iface.bus_read_4(card->hw,AFT_PORT_REG(card,AFT_DMA_CTRL_REG),®); + wan_set_bit(AFT_DMACTRL_TDMV_RX_TOGGLE,®); + wan_set_bit(AFT_DMACTRL_TDMV_TX_TOGGLE,®); + card->hw_iface.bus_write_4(card->hw,AFT_PORT_REG(card,AFT_DMA_CTRL_REG),reg); + } + + +#ifdef AFT_WDT_ENABLE + aft_wdt_set(card,AFT_WDTCTRL_TIMEOUT); +#endif + + DEBUG_TEST("%s: %s() end: reg=0x%X!\n" + ,card->devname,__FUNCTION__,reg); + AFT_FUNC_DEBUG(); + +} + +static void disable_data_error_intr(sdla_t *card, unsigned char event) +{ + u32 reg; + + DEBUG_TEST("%s: Event = %s\n",__FUNCTION__, + event==DEVICE_DOWN?"Device Down": "Link Down"); + + DEBUG_EVENT("%s: AFT communications disabled!\n", + card->devname); + + aft_wdt_reset(card); + + card->hw_iface.bus_read_4(card->hw,AFT_PORT_REG(card,AFT_LINE_CFG_REG), ®); + + wan_clear_bit(AFT_LCFG_DMA_INTR_BIT,®); + wan_clear_bit(AFT_LCFG_FIFO_INTR_BIT,®); + wan_clear_bit(AFT_LCFG_TDMV_INTR_BIT,®); + + if (event==DEVICE_DOWN){ + /* Disable Front End Interface */ + wan_set_bit(AFT_LCFG_FE_IFACE_RESET_BIT,®); + } + card->hw_iface.bus_write_4(card->hw,AFT_PORT_REG(card,AFT_LINE_CFG_REG), reg); + card->u.aft.lcfg_reg=reg; + + card->hw_iface.bus_read_4(card->hw,AFT_PORT_REG(card,AFT_DMA_CTRL_REG),®); + wan_clear_bit(AFT_DMACTRL_GLOBAL_INTR_BIT,®); + card->hw_iface.bus_write_4(card->hw,AFT_PORT_REG(card,AFT_DMA_CTRL_REG),reg); + + + if (event==DEVICE_DOWN){ + wan_set_bit(CARD_DOWN,&card->wandev.critical); + }else{ + if (card->u.aft.cfg.tdmv_span_no){ + DEBUG_EVENT("%s: Starting TDMV 1ms Timer\n", + card->devname); +#ifdef AFT_WDT_ENABLE + aft_wdt_set(card,1); +#endif + } + } + + wan_clear_bit(0,&card->u.aft.comm_enabled); +} + + +/*============================================================================ + * Update communications error and general packet statistics. + */ +static int update_comms_stats(sdla_t* card) +{ + /* 1. On the first timer interrupt, update T1/E1 alarms + * and PMON counters (only for T1/E1 card) (TE1) + */ + + /* TE1 Update T1/E1 alarms */ + if (IS_TE1_CARD(card)) { + wan_smp_flag_t smp_flags; + card->hw_iface.hw_lock(card->hw,&smp_flags); + + card->wandev.fe_iface.read_alarm(&card->fe, 0); + /* TE1 Update T1/E1 perfomance counters */ + card->wandev.fe_iface.read_pmon(&card->fe, 0); + + card->hw_iface.hw_unlock(card->hw,&smp_flags); + + } + + return 0; +} + +static void aft_rx_fifo_over_recover(sdla_t *card, private_area_t *chan) +{ + + if (chan->channelized_cfg && !chan->hdlc_eng){ + return; + } + +#if 0 + if (WAN_NET_RATELIMIT()){ + DEBUG_EVENT("%s:%s Rx Fifo Recovery!\n", + card->devname,chan->if_name); + } +#endif + + aft_channel_rxdma_ctrl(card, chan, 0); + + aft_tslot_sync_ctrl(card,chan,0); + + aft_free_rx_complete_list(chan); + aft_free_rx_descriptors(chan); + + aft_init_rx_dev_fifo(card, chan, WP_NO_WAIT); + + aft_channel_rxdma_ctrl(card, chan, 1); + + aft_init_rx_dev_fifo(card, chan, WP_WAIT); + + chan->dma_index=0; + memset(chan->dma_history,0,sizeof(chan->dma_history)); + + aft_reset_rx_chain_cnt(chan); + aft_dma_rx(card,chan); + + aft_tslot_sync_ctrl(card,chan,1); + +} + +static void aft_tx_fifo_under_recover (sdla_t *card, private_area_t *chan) +{ + + if (chan->channelized_cfg && !chan->hdlc_eng){ + return; + } + +#if 0 + if (WAN_NET_RATELIMIT()){ + DEBUG_EVENT("%s:%s Tx Fifo Recovery!\n", + card->devname,chan->if_name); + } +#endif + /* Enable DMA controler, in order to start the + * fifo cleaning */ + + aft_channel_txdma_ctrl(card, chan, 0); + +#if 0 + aft_list_tx_descriptors(chan); +#endif + aft_dma_tx_complete(card,chan,0, 1); + + aft_free_tx_descriptors(chan); + aft_init_tx_dev_fifo(card,chan,WP_NO_WAIT); + + aft_channel_txdma_ctrl(card, chan, 1); + + aft_init_tx_dev_fifo(card,chan,WP_WAIT); + wan_clear_bit(0,&chan->idle_start); + + aft_reset_tx_chain_cnt(chan); + aft_dma_tx(card,chan); +} + +static int set_chan_state(sdla_t* card, netdevice_t* dev, int state) +{ + private_area_t *chan = wan_netif_priv(dev); + private_area_t *ch_ptr; + + if (!chan){ + DEBUG_EVENT("%s: %s no chan ptr!\n", + card->devname,__FUNCTION__); + return -EINVAL; + } + + chan->common.state = state; + for (ch_ptr=chan; ch_ptr != NULL; ch_ptr=ch_ptr->next){ + ch_ptr->common.state=state; + + if (ch_ptr->tdmv_zaptel_cfg) { + continue; + } + + if (ch_ptr->common.usedby == TDM_VOICE_API || + ch_ptr->common.usedby == TDM_VOICE_DCHAN) { +#ifdef AFT_TDM_API_SUPPORT + if (is_tdm_api(ch_ptr,&ch_ptr->wp_tdm_api_dev)) { + wanpipe_tdm_api_update_state(&ch_ptr->wp_tdm_api_dev, state); + } +#endif + } + } + + if (state == WAN_CONNECTED){ + wan_clear_bit(0,&chan->idle_start); + WAN_NETIF_START_QUEUE(dev); + chan->opstats.link_active_count++; + WAN_NETIF_CARRIER_ON(dev); + WAN_NETIF_WAKE_QUEUE(dev); + }else{ + chan->opstats.link_inactive_modem_count++; + WAN_NETIF_CARRIER_OFF(dev); + WAN_NETIF_STOP_QUEUE(dev); + } + +#if defined(__LINUX__) +# if !defined(CONFIG_PRODUCT_WANPIPE_GENERIC) + if (chan->common.usedby == API) { + wan_update_api_state(chan); + } +#endif +#endif + + if (chan->common.usedby == STACK){ + if (state == WAN_CONNECTED){ + wanpipe_lip_connect(chan,0); + }else{ + wanpipe_lip_disconnect(chan,0); + } + } + return 0; +} + + + +/**SECTION************************************************************* + * + * Protocol API Support Functions + * + **********************************************************************/ + + +static int protocol_init (sdla_t *card, netdevice_t *dev, + private_area_t *chan, + wanif_conf_t* conf) +{ + + chan->common.protocol = conf->protocol; + + DEBUG_TEST("%s: Protocol init 0x%X PPP=0x0%x FR=0x0%X\n", + wan_netif_name(dev), chan->common.protocol, + WANCONFIG_PPP, + WANCONFIG_FR); + +#ifndef CONFIG_PRODUCT_WANPIPE_GENERIC + DEBUG_EVENT("%s: AFT Driver doesn't directly support any protocols!\n", + chan->if_name); + return -1; + +#else + if (chan->common.protocol == WANCONFIG_PPP || + chan->common.protocol == WANCONFIG_CHDLC){ + + struct ifreq ifr; + struct if_settings ifsettings; + + wanpipe_generic_register(card, dev, wan_netif_name(dev)); + chan->common.prot_ptr = dev; + + if (chan->common.protocol == WANCONFIG_CHDLC){ + DEBUG_EVENT("%s: Starting Kernel CISCO HDLC protocol\n", + chan->if_name); + ifsettings.type = IF_PROTO_CISCO; + }else{ + DEBUG_EVENT("%s: Starting Kernel Sync PPP protocol\n", + chan->if_name); + ifsettings.type = IF_PROTO_PPP; + + } + ifr.ifr_data = (caddr_t)&ifsettings; + if (wp_lite_set_proto(dev, &ifr)){ + wanpipe_generic_unregister(dev); + return -EINVAL; + } + + }else if (chan->common.protocol == WANCONFIG_GENERIC){ + chan->common.prot_ptr = dev; + + }else{ + DEBUG_EVENT("%s:%s: Unsupported protocol %d\n", + card->devname,chan->if_name,chan->common.protocol); + return -EPROTONOSUPPORT; + } +#endif + + return 0; +} + + +static int protocol_stop (sdla_t *card, netdevice_t *dev) +{ + private_area_t *chan=wan_netif_priv(dev); + int err = 0; + + if (!chan) + return 0; + + return err; +} + +static int protocol_shutdown (sdla_t *card, netdevice_t *dev) +{ + private_area_t *chan=wan_netif_priv(dev); + + if (!chan) + return 0; + +#ifndef CONFIG_PRODUCT_WANPIPE_GENERIC + + return 0; +#else + + if (chan->common.protocol == WANCONFIG_PPP || + chan->common.protocol == WANCONFIG_CHDLC){ + + chan->common.prot_ptr = NULL; + wanpipe_generic_unregister(dev); + + }else if (chan->common.protocol == WANCONFIG_GENERIC){ + DEBUG_EVENT("%s:%s Protocol shutdown... \n", + card->devname, chan->if_name); + } +#endif + return 0; +} + +void protocol_recv(sdla_t *card, private_area_t *chan, netskb_t *skb) +{ + +#ifdef CONFIG_PRODUCT_WANPIPE_GENERIC + if (chan->common.protocol == WANCONFIG_PPP || + chan->common.protocol == WANCONFIG_CHDLC){ + wanpipe_generic_input(chan->common.dev, skb); + return 0; + } + +#if defined(__LINUX__) + if (chan->common.protocol == WANCONFIG_GENERIC){ + skb->protocol = htons(ETH_P_HDLC); + skb->dev = chan->common.dev; + skb->mac.raw = wan_netif_data(skb); + netif_rx(skb); + return 0; + } +#endif + +#endif + +#if defined(__LINUX__) + skb->protocol = htons(ETH_P_IP); + skb->dev = chan->common.dev; + skb->mac.raw = wan_skb_data(skb); + netif_rx(skb); +#else + DEBUG_EVENT("%s: Action not supported (IP)!\n", + card->devname); + wan_skb_free(skb); +#endif + + return; +} + + +/**SECTION************************************************************* + * + * TE1 Config Code + * + **********************************************************************/ +static int aft_global_chip_configuration(sdla_t *card, wandev_conf_t* conf) +{ + int err=0; + + err = aft_hwdev[card->wandev.card_type].aft_global_chip_config(card); + return err; +} + +static int aft_global_chip_disable(sdla_t *card) +{ + + aft_hwdev[card->wandev.card_type].aft_global_chip_unconfig(card); + + return 0; +} + +/*========================================================= + * aft_chip_configure + * + */ + +static int aft_chip_configure(sdla_t *card, wandev_conf_t* conf) +{ + + return aft_hwdev[card->wandev.card_type].aft_chip_config(card); +} + +static int aft_chip_unconfigure(sdla_t *card) +{ + u32 reg=0; + + AFT_FUNC_DEBUG(); + + wan_set_bit(CARD_DOWN,&card->wandev.critical); + + aft_hwdev[card->wandev.card_type].aft_chip_unconfig(card); + + card->hw_iface.bus_read_4(card->hw,AFT_PORT_REG(card,AFT_LINE_CFG_REG),&card->u.aft.lcfg_reg); + card->u.aft.lcfg_reg=reg; + return 0; +} + + +static int aft_dev_configure(sdla_t *card, private_area_t *chan, wanif_conf_t* conf) +{ + chan->logic_ch_num=-1; + + /* Channel definition section. If not channels defined + * return error */ + if (chan->time_slot_map == 0){ + DEBUG_EVENT("%s: Invalid Channel Selection 0x%lX\n", + card->devname,chan->time_slot_map); + return -EINVAL; + } + + + DEBUG_EVENT("%s: Active Ch Map :0x%08lX\n", + card->devname,chan->time_slot_map); + + + DEBUG_TEST("%s:%d: GOT Logic ch %ld Base 0x%X Size=0x%X\n", + __FUNCTION__,__LINE__,chan->logic_ch_num, + chan->fifo_base_addr, chan->fifo_size_code); + + + return aft_hwdev[card->wandev.card_type].aft_chan_config(card,chan); +} + +static void aft_dev_unconfigure(sdla_t *card, private_area_t *chan) +{ + aft_hwdev[card->wandev.card_type].aft_chan_unconfig(card,chan); + return ; +} + + +#define BIT_DEV_ADDR_CLEAR 0x600 + + + +/**SECTION************************************************************* + * + * TE1 Tx Functions + * DMA Chains + * + **********************************************************************/ + + +/*=============================================== + * aft_tx_dma_voice_handler + * + */ +static void aft_tx_dma_voice_handler(unsigned long data, int wdt, int reset) +{ + private_area_t *chan = (private_area_t *)data; + sdla_t *card = chan->card; + u32 reg,dma_descr,dma_status; + aft_dma_chain_t *dma_chain; + + if (wan_test_and_set_bit(TX_HANDLER_BUSY,&chan->dma_status)){ + DEBUG_EVENT("%s: SMP Critical in %s\n", + chan->if_name,__FUNCTION__); + return; + } + + dma_chain = &chan->tx_dma_chain_table[0]; + + if (reset){ + wan_clear_bit(0,&dma_chain->init); + dma_descr=(chan->logic_ch_num<<4) + AFT_PORT_REG(card,AFT_TX_DMA_HI_DESCR_BASE_REG); + card->hw_iface.bus_write_4(card->hw,dma_descr,0); + goto aft_tx_dma_voice_handler_exit; + } + + /* If the current DMA chain is in use,then + * all chains are busy */ + if (!wan_test_bit(0,&dma_chain->init)){ + goto aft_tx_dma_voice_handler_exit; + } + + dma_descr=(chan->logic_ch_num<<4) + AFT_PORT_REG(card,AFT_TX_DMA_HI_DESCR_BASE_REG); + card->hw_iface.bus_read_4(card->hw,dma_descr,®); + + /* If GO bit is set, then the current DMA chain + * is in process of being transmitted, thus + * all are busy */ + if (wan_test_bit(AFT_TXDMA_HI_GO_BIT,®)){ + goto aft_tx_dma_voice_handler_exit; + } + + dma_status = aft_txdma_hi_get_dma_status(reg); + + if (reg & AFT_TXDMA_HI_DMA_LENGTH_MASK){ + chan->errstats.Tx_dma_len_nonzero++; + chan->errstats.Tx_dma_errors++; + } + + if (dma_status){ + + DEBUG_TEST("%s:%s: Tx DMA Descriptor=0x%X\n", + card->devname,chan->if_name,reg); + + + /* Checking Tx DMA PCI error status. Has to be '0's */ + if (dma_status){ + + chan->errstats.Tx_pci_errors++; + if (wan_test_bit(AFT_TXDMA_HIDMASTATUS_PCI_M_ABRT,&dma_status)){ + if (WAN_NET_RATELIMIT()){ + DEBUG_EVENT("%s:%s: Tx Error: Abort from Master: pci fatal error!\n", + card->devname,chan->if_name); + } + + } + if (wan_test_bit(AFT_TXDMA_HIDMASTATUS_PCI_T_ABRT,&dma_status)){ + if (WAN_NET_RATELIMIT()){ + DEBUG_EVENT("%s:%s: Tx Error: Abort from Target: pci fatal error!\n", + card->devname,chan->if_name); + } + } + if (wan_test_bit(AFT_TXDMA_HIDMASTATUS_PCI_DS_TOUT,&dma_status)){ + DEBUG_TEST("%s:%s: Tx Warning: PCI Latency Timeout!\n", + card->devname,chan->if_name); + chan->errstats.Tx_pci_latency++; + goto aft_tx_dma_voice_handler_exit; + } + if (wan_test_bit(AFT_TXDMA_HIDMASTATUS_PCI_RETRY,&dma_status)){ + if (WAN_NET_RATELIMIT()){ + DEBUG_EVENT("%s:%s: Tx Error: 'Retry' exceeds maximum (64k): pci fatal error!\n", + card->devname,chan->if_name); + } + } + } + chan->if_stats.tx_errors++; + } + + + chan->opstats.Data_frames_Tx_count++; + chan->opstats.Data_bytes_Tx_count+=wan_skb_len(dma_chain->skb); + chan->if_stats.tx_packets++; + chan->if_stats.tx_bytes+=wan_skb_len(dma_chain->skb); + + wan_clear_bit(0,&dma_chain->init); + +aft_tx_dma_voice_handler_exit: + wan_clear_bit(TX_HANDLER_BUSY,&chan->dma_status); + + return; +} + + + +/*=============================================== + * aft_tx_dma_chain_handler + * + */ +static void aft_tx_dma_chain_handler(unsigned long data, int wdt, int reset) +{ + private_area_t *chan = (private_area_t *)data; + sdla_t *card = chan->card; + u32 reg,dma_descr; + aft_dma_chain_t *dma_chain; + + if (wan_test_and_set_bit(TX_HANDLER_BUSY,&chan->dma_status)){ + DEBUG_EVENT("%s: SMP Critical in %s\n", + chan->if_name,__FUNCTION__); + return; + } + + dma_chain = &chan->tx_dma_chain_table[chan->tx_pending_chain_indx]; + + for (;;){ + + /* If the current DMA chain is in use,then + * all chains are busy */ + if (!wan_test_bit(0,&dma_chain->init)){ + break; + } + + dma_descr=(chan->logic_ch_num<<4) + (chan->tx_pending_chain_indx*AFT_DMA_INDEX_OFFSET) + + AFT_PORT_REG(card,AFT_TX_DMA_HI_DESCR_BASE_REG); + + card->hw_iface.bus_read_4(card->hw,dma_descr,®); + + /* If GO bit is set, then the current DMA chain + * is in process of being transmitted, thus + * all are busy */ + if (wan_test_bit(AFT_TXDMA_HI_GO_BIT,®)){ + break; + } + + if (!wan_test_bit(AFT_TXDMA_HI_INTR_DISABLE_BIT,®)){ + wan_clear_bit(TX_INTR_PENDING,&chan->dma_chain_status); + if (wdt){ + DEBUG_TEST("%s:%s TX WDT Timer got Interrtup pkt!\n", + card->devname,chan->if_name); + } + } + + + DEBUG_TEST("%s: TX DMA Handler Chain %d\n",chan->if_name,dma_chain->index); + + if (chan->hdlc_eng){ + if (dma_chain->skb){ + wan_skb_set_csum(dma_chain->skb, reg); + wan_skb_queue_tail(&chan->wp_tx_complete_list,dma_chain->skb); + dma_chain->skb=NULL; + } + }else{ + if (dma_chain->skb != chan->tx_idle_skb){ + + wan_skb_set_csum(dma_chain->skb, reg); + aft_tx_post_complete(chan->card,chan,dma_chain->skb); + + if (chan->channelized_cfg && !chan->hdlc_eng){ + /* Voice code uses the rx buffer to + * transmit! So put the rx buffer back + * into the rx queue */ + aft_init_requeue_free_skb(chan, dma_chain->skb); + }else{ + wan_skb_free(dma_chain->skb); + } + + dma_chain->skb=NULL; + } + } + + aft_tx_dma_chain_init(chan,dma_chain); + + if (chan->single_dma_chain){ + break; + } + + if (++chan->tx_pending_chain_indx >= MAX_AFT_DMA_CHAINS){ + chan->tx_pending_chain_indx=0; + } + + dma_chain = &chan->tx_dma_chain_table[chan->tx_pending_chain_indx]; + + } + + wan_clear_bit(TX_HANDLER_BUSY,&chan->dma_status); + + if (wan_skb_queue_len(&chan->wp_tx_complete_list)){ + WAN_TASKLET_SCHEDULE((&chan->common.bh_task)); + } + + return; +} + +/*=============================================== + * aft_dma_chain_tx + * + */ +static int aft_dma_chain_tx(aft_dma_chain_t *dma_chain,private_area_t *chan, int intr,int fifo) +{ + +#define dma_descr dma_chain->dma_descr +#define reg dma_chain->reg +#define dma_ch_indx dma_chain->index +#define len_align dma_chain->len_align +#define card chan->card + + unsigned int len = dma_chain->dma_len; + unsigned int ss7_ctrl=0; + + dma_descr=(chan->logic_ch_num<<4) + (dma_ch_indx*AFT_DMA_INDEX_OFFSET) + + AFT_PORT_REG(card,AFT_TX_DMA_HI_DESCR_BASE_REG); + + DEBUG_TEST("%s:%d: chan logic ch=%d chain=%ld dma_descr=0x%x set!\n", + __FUNCTION__,__LINE__,chan->logic_ch_num,dma_ch_indx,dma_descr); + + card->hw_iface.bus_read_4(card->hw,dma_descr,®); + + if (wan_test_bit(AFT_TXDMA_HI_GO_BIT,®)){ + DEBUG_EVENT("%s: Error: TxDMA GO Ready bit set on dma (chain=%d) Tx 0x%X\n", + card->devname,dma_ch_indx,reg); + return -EBUSY; + } + + dma_descr=(chan->logic_ch_num<<4) + (dma_ch_indx*AFT_DMA_INDEX_OFFSET) + + AFT_PORT_REG(card,AFT_TX_DMA_LO_DESCR_BASE_REG); + + /* Write the pointer of the data packet to the + * DMA address register */ + reg=dma_chain->dma_addr; + + + if (chan->cfg.ss7_enable){ + ss7_ctrl=wan_skb_csum(dma_chain->skb); + wan_skb_set_csum(dma_chain->skb,0); + if (ss7_ctrl&AFT_SS7_CTRL_LEN_MASK){ + len-=4; + len+=ss7_ctrl&AFT_SS7_CTRL_LEN_MASK; + } + if (!wan_test_bit(AFT_SS7_CTRL_TYPE_BIT,&ss7_ctrl)){ + /*FISU*/ + if (chan->cfg.ss7_mode == WANOPT_SS7_MODE_4096){ + len-=WANOPT_SS7_FISU_4096_SZ; + }else{ + len-=WANOPT_SS7_FISU_128_SZ; + } + }else{ + /*LSSU*/ + len-=chan->cfg.ss7_lssu_size; + } + } + + /* Set the 32bit alignment of the data length. + * Used to pad the tx packet to the 32 bit + * boundary */ + aft_txdma_lo_set_alignment(®,len); + + len_align=0; + if (len&0x03){ + len_align=1; + } + + DEBUG_TEST("%s: TXDMA_LO=0x%X PhyAddr=0x%X DmaDescr=0x%X Len=%i\n", + __FUNCTION__,reg,dma_chain->dma_addr,dma_descr,len); + + card->hw_iface.bus_write_4(card->hw,dma_descr,reg); + + dma_descr=(chan->logic_ch_num<<4) + (dma_ch_indx*AFT_DMA_INDEX_OFFSET) + + AFT_PORT_REG(card,AFT_TX_DMA_HI_DESCR_BASE_REG); + + reg=0; + + if (chan->cfg.ss7_enable){ + if (wan_test_bit(AFT_SS7_CTRL_TYPE_BIT,&ss7_ctrl)){ + wan_set_bit(AFT_TXDMA_HI_SS7_FISU_OR_LSSU_BIT,®); + }else{ + wan_clear_bit(AFT_TXDMA_HI_SS7_FISU_OR_LSSU_BIT,®); + } + if (wan_test_bit(AFT_SS7_CTRL_FORCE_BIT,&ss7_ctrl)){ + wan_set_bit(AFT_TXDMA_HI_SS7_FI_LS_FORCE_TX_BIT,®); + }else{ + wan_clear_bit(AFT_TXDMA_HI_SS7_FI_LS_FORCE_TX_BIT,®); + } + } + + aft_txdma_hi_set_dma_length(®,len,len_align); + + if (chan->single_dma_chain){ + wan_clear_bit(AFT_TXDMA_HI_LAST_DESC_BIT,®); + wan_clear_bit(AFT_TXDMA_HI_INTR_DISABLE_BIT,®); + + if (chan->channelized_cfg && !chan->hdlc_eng){ + wan_set_bit(AFT_TXDMA_HI_LAST_DESC_BIT,®); + } + }else{ + wan_set_bit(AFT_TXDMA_HI_LAST_DESC_BIT,®); + + if (intr){ + DEBUG_TEST("%s: Setting Interrupt on index=%d\n", + chan->if_name,dma_ch_indx); + wan_clear_bit(AFT_TXDMA_HI_INTR_DISABLE_BIT,®); + }else{ + wan_set_bit(AFT_TXDMA_HI_INTR_DISABLE_BIT,®); + } + } + + if (chan->hdlc_eng){ + /* Only enable the Frame Start/Stop on + * non-transparent hdlc configuration */ + wan_set_bit(AFT_TXDMA_HI_START_BIT,®); + wan_set_bit(AFT_TXDMA_HI_EOF_BIT,®); + }else{ + /* Used for transparent time slot + * synchronization */ + if (chan->tslot_sync){ + wan_set_bit(AFT_TXDMA_HI_START_BIT,®); + } + } + + wan_set_bit(AFT_TXDMA_HI_GO_BIT,®); + if (fifo){ + wan_set_bit(AFT_TXDMA_HI_DMA_CMD_BIT,®); + } + + DEBUG_TEST("%s: TXDMA_HI=0x%X DmaDescr=0x%X Len=%d Intr=%d\n", + __FUNCTION__,reg,dma_descr,len,intr); + + card->hw_iface.bus_write_4(card->hw,dma_descr,reg); + +#if 1 + ++chan->tx_attempts; +#endif + + return 0; + +#undef dma_descr +#undef reg +#undef dma_ch_indx +#undef len_align +#undef card +} + +/*=============================================== + * aft_dma_chain_init + * + */ +static void aft_tx_dma_chain_init(private_area_t *chan, aft_dma_chain_t *dma_chain) +{ + + if (dma_chain->dma_addr){ + chan->card->hw_iface.pci_unmap_dma(chan->card->hw, + dma_chain->dma_addr, + dma_chain->dma_len, + PCI_DMA_TODEVICE); + } + + if (dma_chain->skb){ + if (!chan->hdlc_eng){ + if (dma_chain->skb != chan->tx_idle_skb){ + if (chan->channelized_cfg && !chan->hdlc_eng){ + aft_init_requeue_free_skb(chan, dma_chain->skb); + }else{ + wan_skb_free(dma_chain->skb); + } + } + dma_chain->skb=NULL; + }else{ + wan_skb_free(dma_chain->skb); + dma_chain->skb=NULL; + } + } + + dma_chain->dma_addr=0; + dma_chain->dma_len=0; + + wan_clear_bit(0,&dma_chain->init); +} + +static void aft_rx_dma_chain_init(private_area_t *chan, aft_dma_chain_t *dma_chain) +{ + + if (dma_chain->dma_addr){ + chan->card->hw_iface.pci_unmap_dma(chan->card->hw, + dma_chain->dma_addr, + dma_chain->dma_len, + PCI_DMA_FROMDEVICE); + } + + if (dma_chain->skb){ + aft_init_requeue_free_skb(chan,dma_chain->skb); + dma_chain->skb=NULL; + } + + dma_chain->dma_addr=0; + dma_chain->dma_len=0; + + wan_clear_bit(0,&dma_chain->init); +} + + + +static int aft_dma_voice_tx(sdla_t *card, private_area_t *chan) +{ + int err=0; + aft_dma_chain_t *dma_chain; + u32 reg, dma_ram_desc; + + if (wan_test_and_set_bit(TX_DMA_BUSY,&chan->dma_status)){ + DEBUG_EVENT("%s: SMP Critical in %s\n", + chan->if_name,__FUNCTION__); + + return -EBUSY; + } + + dma_chain = &chan->tx_dma_chain_table[0]; + + /* If the current DMA chain is in use,then + * all chains are busy */ + if (wan_test_and_set_bit(0,&dma_chain->init)){ + err=-EBUSY; + goto aft_dma_voice_tx_exit; + } + + if (!dma_chain->skb){ + unsigned char *buf; + + /* Take already preallocated buffer from rx queue. + * We are only using a single buffer for rx and tx */ + dma_chain->skb=wan_skb_dequeue(&chan->wp_rx_free_list); + if (!dma_chain->skb){ + DEBUG_EVENT("%s: Warning Tx chain = %d: no free tx bufs\n", + chan->if_name,dma_chain->index); + wan_clear_bit(0,&dma_chain->init); + err=-EINVAL; + goto aft_dma_voice_tx_exit; + } + + wan_skb_init(dma_chain->skb,16); + wan_skb_trim(dma_chain->skb,0); + + /*NC: We must set the initial value of the + * frist DMA TX transfer to 2*MTU. This is + * to avoid potential Tx FIFO underrun. + * + * This is equivalent of transmitting twice + * very fist time. */ + + buf=wan_skb_put(dma_chain->skb,chan->mtu*2); + memset(buf,chan->idle_flag,chan->mtu*2); + + dma_chain->dma_addr = card->hw_iface.pci_map_dma(card->hw, + wan_skb_data(dma_chain->skb), + wan_skb_len(dma_chain->skb), + PCI_DMA_TODEVICE); + + dma_chain->dma_len = wan_skb_len(dma_chain->skb); + + } + + + dma_ram_desc=chan->logic_ch_num*4 + + AFT_PORT_REG(card,AFT_DMA_CHAIN_RAM_BASE_REG); + card->hw_iface.bus_read_4(card->hw,dma_ram_desc,®); + aft_dmachain_set_tx_dma_addr(®,1); + card->hw_iface.bus_write_4(card->hw,dma_ram_desc,reg); + + /* We set inital TX DMA with FIFO Reset option. This funciton + * will ONLY run once in TDM mode. After the inital TX the + * DMA Reload will be used to tx the Voice frame */ + err=aft_dma_chain_tx(dma_chain,chan,1,1); + if (err){ + DEBUG_EVENT("%s: Tx dma chain %d overrun error: should never happen!\n", + chan->if_name,dma_chain->index); + + /* Drop the tx packet here */ + aft_tx_dma_chain_init(chan,dma_chain); + chan->if_stats.tx_errors++; + err=-EINVAL; + goto aft_dma_voice_tx_exit; + } + +aft_dma_voice_tx_exit: + wan_clear_bit(TX_DMA_BUSY,&chan->dma_status); + + return 0; +} + +/*=============================================== + * aft_dma_tx + * + */ +static int aft_dma_tx (sdla_t *card,private_area_t *chan) +{ + int err=0, intr=0, cnt=0; + aft_dma_chain_t *dma_chain; + netskb_t *skb=NULL; + + if (chan->channelized_cfg && !chan->hdlc_eng){ + return aft_dma_voice_tx(card,chan); + } + + if (wan_test_and_set_bit(TX_DMA_BUSY,&chan->dma_status)){ + DEBUG_EVENT("%s: SMP Critical in %s\n", + chan->if_name,__FUNCTION__); + + return -EBUSY; + } + + if (chan->tx_chain_indx >= MAX_AFT_DMA_CHAINS){ + DEBUG_EVENT("%s: MAJOR ERROR: TE1 Tx: Dma tx chain = %d\n", + chan->if_name,chan->tx_chain_indx); + return -EBUSY; + } + + + /* The cnt is not used, its used only as a + * sanity check. The code below should break + * out of the loop before MAX_TX_BUF runs out! */ + for (cnt=0;cnttx_dma_chain_table[chan->tx_chain_indx]; + + /* FIXME: Reset TX Watchdog */ + /* aft_reset_tx_watchdog(card); */ + + /* If the current DMA chain is in use,then + * all chains are busy */ + if (wan_test_and_set_bit(0,&dma_chain->init)){ + wan_clear_bit(TX_DMA_BUSY,&chan->dma_status); + break; + } + + if(!chan->lip_atm){ + skb=wan_skb_dequeue(&chan->wp_tx_pending_list); + }else{ + skb=atm_tx_skb_dequeue(&chan->wp_tx_pending_list, chan->tx_idle_skb, chan->if_name); + } + + if (!skb){ + if (!chan->hdlc_eng){ + + skb=chan->tx_idle_skb; + if (!skb){ + if (WAN_NET_RATELIMIT()){ + DEBUG_EVENT("%s: Critical Error: Transparent tx no skb!\n", + chan->if_name); + } + break; + } + + ++chan->if_stats.tx_carrier_errors; + }else{ + wan_clear_bit(0,&dma_chain->init); + wan_clear_bit(TX_DMA_BUSY,&chan->dma_status); + break; + } + } + + if ((unsigned long)wan_skb_data(skb) & 0x03){ + + err=aft_realign_skb_pkt(chan,skb); + if (err){ + if (WAN_NET_RATELIMIT()){ + DEBUG_EVENT("%s: Tx Error: Non Aligned packet %p: dropping...\n", + chan->if_name,wan_skb_data(skb)); + } + wan_skb_free(skb); + aft_tx_dma_chain_init(chan,dma_chain); + chan->if_stats.tx_errors++; + chan->opstats.Tx_Data_discard_lgth_err_count++; + continue; + } + } + + + if (!chan->hdlc_eng && (wan_skb_len(skb)%4)){ + + if (WAN_NET_RATELIMIT()){ + DEBUG_EVENT("%s: Tx Error: Tx Length %i not 32bit aligned: dropping...\n", + chan->if_name,wan_skb_len(skb)); + } + wan_skb_free(skb); + aft_tx_dma_chain_init(chan,dma_chain); + chan->if_stats.tx_errors++; + chan->opstats.Tx_Data_discard_lgth_err_count++; + continue; + } + + dma_chain->skb=skb; + + dma_chain->dma_addr = card->hw_iface.pci_map_dma(card->hw, + wan_skb_data(dma_chain->skb), + wan_skb_len(dma_chain->skb), + PCI_DMA_TODEVICE); + + dma_chain->dma_len = wan_skb_len(dma_chain->skb); + + + DEBUG_TEST("%s: DMA Chain %d: Cur=%d Pend=%d\n", + chan->if_name,dma_chain->index, + chan->tx_chain_indx,chan->tx_pending_chain_indx); + + intr=0; + if (!wan_test_bit(TX_INTR_PENDING,&chan->dma_chain_status)){ + int pending_indx=chan->tx_pending_chain_indx; + if (chan->tx_chain_indx >= pending_indx){ + intr = ((MAX_AFT_DMA_CHAINS-(chan->tx_chain_indx - + pending_indx))<=2); + }else{ + intr = ((pending_indx - chan->tx_chain_indx)<=2); + } + + if (intr){ + DEBUG_TEST("%s: Setting tx interrupt on chain=%d\n", + chan->if_name,dma_chain->index); + wan_set_bit(TX_INTR_PENDING,&chan->dma_chain_status); + } + } + + + err=aft_dma_chain_tx(dma_chain,chan,intr,0); + if (err){ + DEBUG_EVENT("%s: Tx dma chain %d overrun error: should never happen!\n", + chan->if_name,dma_chain->index); + + +#if 0 + aft_list_tx_descriptors(chan); + disable_data_error_intr(card,DEVICE_DOWN); + wan_set_bit(CARD_DOWN,&card->wandev.critical); + port_set_state(card,WAN_DISCONNECTED); + break; + +#endif + + /* Drop the tx packet here */ + aft_tx_dma_chain_init(chan,dma_chain); + chan->if_stats.tx_errors++; + break; + } + + if (skb){ + wan_capture_trace_packet(card, &chan->trace_info, skb, TRC_OUTGOING_FRM); + } + + if (chan->single_dma_chain){ + break; + }else{ + if (++chan->tx_chain_indx >= MAX_AFT_DMA_CHAINS){ + chan->tx_chain_indx=0; + } + } + } + + wan_clear_bit(TX_DMA_BUSY,&chan->dma_status); + + return 0; +} + + + +/**SECTION************************************************************* + * + * TE1 Rx Functions + * DMA Chains + * + **********************************************************************/ + +static int aft_dma_chain_rx(aft_dma_chain_t *dma_chain, private_area_t *chan, int intr, int fifo) +{ +#define dma_descr dma_chain->dma_descr +#define reg dma_chain->reg +#define len dma_chain->dma_len +#define dma_ch_indx dma_chain->index +#define len_align dma_chain->len_align +#define card chan->card + + /* Write the pointer of the data packet to the + * DMA address register */ + reg=dma_chain->dma_addr; + + /* Set the 32bit alignment of the data length. + * Since we are setting up for rx, set this value + * to Zero */ + aft_rxdma_lo_set_alignment(®,0); + + dma_descr=(chan->logic_ch_num<<4) + (dma_ch_indx*AFT_DMA_INDEX_OFFSET) + + AFT_PORT_REG(card,AFT_RX_DMA_LO_DESCR_BASE_REG); + + DEBUG_TEST("%s: RxDMA_LO(%d) = 0x%X, DmaDescr=0x%X\n", + __FUNCTION__,chan->logic_ch_num,reg,dma_descr); + + card->hw_iface.bus_write_4(card->hw,dma_descr,reg); + + dma_descr=(chan->logic_ch_num<<4) + (dma_ch_indx*AFT_DMA_INDEX_OFFSET) + + AFT_PORT_REG(card,AFT_RX_DMA_HI_DESCR_BASE_REG); + + reg =0; + + if (chan->single_dma_chain){ + wan_clear_bit(AFT_RXDMA_HI_LAST_DESC_BIT,®); + wan_clear_bit(AFT_RXDMA_HI_INTR_DISABLE_BIT,®); + + if (chan->channelized_cfg && !chan->hdlc_eng){ + wan_set_bit(AFT_RXDMA_HI_LAST_DESC_BIT,®); + } + + }else{ + wan_set_bit(AFT_RXDMA_HI_LAST_DESC_BIT,®); + +#if AFT_IFT_INTR_ENABLE + wan_set_bit(AFT_RXDMA_HI_IFT_INTR_ENB_BIT,®); +#else + wan_clear_bit(AFT_RXDMA_HI_IFT_INTR_ENB_BIT,®); +#endif + + if (intr){ + DEBUG_TEST("%s: Setting Rx Interrupt on index=%d\n", + chan->if_name,dma_ch_indx); + wan_clear_bit(AFT_RXDMA_HI_INTR_DISABLE_BIT,®); + }else{ + wan_set_bit(AFT_RXDMA_HI_INTR_DISABLE_BIT,®); + } + } + + if (chan->hdlc_eng){ + aft_rxdma_hi_set_dma_length(®,chan->dma_mru,1); + }else{ + aft_rxdma_hi_set_dma_length(®,chan->mru,0); + } + + wan_set_bit(AFT_RXDMA_HI_GO_BIT,®); + if (fifo){ + wan_set_bit(AFT_RXDMA_HI_DMA_CMD_BIT,®); + } + + + DEBUG_TEST("%s: RXDMA_HI(%d) = 0x%X, DmaDescr=0x%X\n", + __FUNCTION__,chan->logic_ch_num,reg,dma_descr); + + card->hw_iface.bus_write_4(card->hw,dma_descr,reg); + + return 0; + +#undef dma_descr +#undef reg +#undef len +#undef dma_ch_indx +#undef len_align +#undef card +} + +static int aft_dma_voice_rx(sdla_t *card, private_area_t *chan) +{ + int err=0; + aft_dma_chain_t *dma_chain; + u32 reg, dma_ram_desc; + + if (wan_test_and_set_bit(RX_DMA_BUSY,&chan->dma_status)){ + DEBUG_EVENT("%s: SMP Critical in %s\n", + chan->if_name,__FUNCTION__); + return -EBUSY; + } + + dma_chain = &chan->rx_dma_chain_table[0]; + + DEBUG_TEST("%s: DMA RX: Chain %i Used %i\n", + chan->if_name,dma_chain->index,dma_chain->init); + + /* If the current DMA chain is in use,then + * all chains are busy */ + if (wan_test_and_set_bit(0,&dma_chain->init)){ + DEBUG_TEST("%s: Warning: %s():%d dma chain busy %d!\n", + card->devname, __FUNCTION__, __LINE__, + dma_chain->index); + err=-EBUSY; + goto aft_dma_single_chain_rx_exit; + } + + /* This will only be done on the first time. The dma_chain + * skb will be re-used all the time, thus no need for + * rx_free_list any more */ + if (!dma_chain->skb){ + dma_chain->skb=wan_skb_dequeue(&chan->wp_rx_free_list); + if (!dma_chain->skb){ + DEBUG_EVENT("%s: Warning Rx Voice chain = %d: no free rx bufs\n", + chan->if_name,dma_chain->index); + wan_clear_bit(0,&dma_chain->init); + err=-EINVAL; + goto aft_dma_single_chain_rx_exit; + } + + wan_skb_init(dma_chain->skb,16); + wan_skb_trim(dma_chain->skb,0); + +#if defined(__LINUX__) +#if 0 + dma_chain->dma_addr = cpu_to_le32(pci_map_single(NULL, + wan_skb_tail(dma_chain->skb), + chan->dma_mru, + PCI_DMA_FROMDEVICE)); +#else + dma_chain->dma_addr = card->hw_iface.pci_map_dma(card->hw, + wan_skb_tail(dma_chain->skb), + chan->dma_mru, + PCI_DMA_FROMDEVICE); +#endif +#else + dma_chain->dma_addr = + virt_to_phys(wan_skb_tail(dma_chain->skb)); +#endif + dma_chain->dma_len = chan->dma_mru; + }else{ + wan_skb_init(dma_chain->skb,16); + wan_skb_trim(dma_chain->skb,0); + } + + dma_ram_desc=chan->logic_ch_num*4 + + AFT_PORT_REG(card,AFT_DMA_CHAIN_RAM_BASE_REG); + card->hw_iface.bus_read_4(card->hw,dma_ram_desc,®); + aft_dmachain_set_rx_dma_addr(®,1); + card->hw_iface.bus_write_4(card->hw,dma_ram_desc,reg); + + err=aft_dma_chain_rx(dma_chain,chan,1,1); + if (err){ + DEBUG_EVENT("%s: Rx dma chain %d overrun error: should never happen!\n", + chan->if_name,dma_chain->index); + aft_rx_dma_chain_init(chan,dma_chain); + chan->if_stats.rx_errors++; + } + +aft_dma_single_chain_rx_exit: + + wan_clear_bit(RX_DMA_BUSY,&chan->dma_status); + return err; +} + + +static int aft_dma_rx(sdla_t *card, private_area_t *chan) +{ + int err=0, intr=0; + aft_dma_chain_t *dma_chain; + int cur_dma_ptr, i,max_dma_cnt,free_queue_len; + u32 reg, dma_ram_desc; + + + if (chan->channelized_cfg && !chan->hdlc_eng){ + return aft_dma_voice_rx(card,chan); + } + + if (wan_test_and_set_bit(RX_DMA_BUSY,&chan->dma_status)){ + DEBUG_EVENT("%s: SMP Critical in %s\n", + chan->if_name,__FUNCTION__); + return -EBUSY; + } + + free_queue_len=wan_skb_queue_len(&chan->wp_rx_free_list); + if (!chan->single_dma_chain && + free_queue_len < MAX_AFT_DMA_CHAINS){ + aft_free_rx_complete_list(chan); + free_queue_len=wan_skb_queue_len(&chan->wp_rx_free_list); + if (free_queue_len < MAX_AFT_DMA_CHAINS){ + DEBUG_EVENT("%s: %s() CRITICAL ERROR: No free rx buffers\n", + card->devname,__FUNCTION__); + goto te1rx_skip; + } + } + + dma_ram_desc=chan->logic_ch_num*4 + AFT_PORT_REG(card,AFT_DMA_CHAIN_RAM_BASE_REG); + card->hw_iface.bus_read_4(card->hw,dma_ram_desc,®); + cur_dma_ptr=aft_dmachain_get_rx_dma_addr(reg); + +#if 0 + aft_chain_history(chan,chan->rx_chain_indx, cur_dma_ptr, chan->rx_pending_chain_indx,1); +#endif + max_dma_cnt = MAX_AFT_DMA_CHAINS; + + if (!chan->single_dma_chain && + free_queue_len < max_dma_cnt){ + max_dma_cnt = free_queue_len; + } + + + DEBUG_TEST("%s: DMA RX: CBoardPtr=%d Driver=%d MaxDMA=%d\n", + card->devname,cur_dma_ptr,chan->rx_chain_indx,max_dma_cnt); + + for (i=0;irx_dma_chain_table[chan->rx_chain_indx]; + + /* If the current DMA chain is in use,then + * all chains are busy */ + if (wan_test_and_set_bit(0,&dma_chain->init)){ + DEBUG_TEST("%s: Warning: %s():%d dma chain busy %d!\n", + card->devname, __FUNCTION__, __LINE__, + dma_chain->index); + + err=-EBUSY; + break; + } + + dma_chain->skb=wan_skb_dequeue(&chan->wp_rx_free_list); + if (!dma_chain->skb){ + /* If this ever happends, it means that wp_bh is stuck for some + * reason, thus start using the completed buffers, thus + * overflow the data */ + dma_chain->skb=wan_skb_dequeue(&chan->wp_rx_complete_list); + if (dma_chain->skb) { + chan->if_stats.rx_dropped++; + wan_skb_init(dma_chain->skb,16); + wan_skb_trim(dma_chain->skb,0); + }else{ + DEBUG_EVENT("%s: Critical Rx chain = %d: no free rx bufs (Free=%i Comp=%i)\n", + chan->if_name,dma_chain->index, + wan_skb_queue_len(&chan->wp_rx_free_list), + wan_skb_queue_len(&chan->wp_rx_complete_list)); + wan_clear_bit(0,&dma_chain->init); + disable_data_error_intr(card,DEVICE_DOWN); + wan_set_bit(CARD_DOWN,&card->wandev.critical); + err=-EINVAL; + break; + } + + } + + dma_chain->dma_addr = card->hw_iface.pci_map_dma(card->hw, + wan_skb_tail(dma_chain->skb), + chan->dma_mru, + PCI_DMA_FROMDEVICE); + + dma_chain->dma_len = chan->dma_mru; + + intr=0; + if (!wan_test_bit(RX_INTR_PENDING,&chan->dma_chain_status)){ + + free_queue_len--; + + if (free_queue_len <= 2){ + DEBUG_TEST("%s: DBG: Setting intr queue size low\n", + card->devname); + intr=1; + }else{ + if (chan->rx_chain_indx >= cur_dma_ptr){ + intr = ((MAX_AFT_DMA_CHAINS - + (chan->rx_chain_indx-cur_dma_ptr)) <=4); + }else{ + intr = ((cur_dma_ptr - chan->rx_chain_indx)<=4); + } + } + + if (intr){ + DEBUG_TEST("%s: Setting Rx interrupt on chain=%d\n", + chan->if_name,dma_chain->index); + wan_set_bit(RX_INTR_PENDING,&chan->dma_chain_status); + } + } + + DEBUG_TEST("%s: Setting Buffer on Rx Chain = %d Intr=%d\n", + chan->if_name,dma_chain->index, intr); + + err=aft_dma_chain_rx(dma_chain,chan,intr,0); + if (err){ + DEBUG_EVENT("%s: Rx dma chain %d overrun error: should never happen!\n", + chan->if_name,dma_chain->index); + aft_rx_dma_chain_init(chan,dma_chain); + chan->if_stats.rx_errors++; + break; + } + + if (chan->single_dma_chain){ + break; + }else{ + if (++chan->rx_chain_indx >= MAX_AFT_DMA_CHAINS){ + chan->rx_chain_indx=0; + } + } + } + +#if 0 + aft_chain_history(chan,chan->rx_chain_indx, cur_dma_ptr, chan->rx_pending_chain_indx,2); + + if (chan->rx_chain_indx == cur_dma_ptr && + chan->rx_pending_chain_indx == cur_dma_ptr && + cur_dma_ptr != 0){ + DEBUG_EVENT("%s :Location 1 Listing Descr!\n", + chan->if_name); + aft_list_descriptors(chan); + } +#endif + aft_rx_cur_go_test(chan); + +te1rx_skip: + + wan_clear_bit(RX_DMA_BUSY,&chan->dma_status); + + return err; +} + +/*=============================================== + * aft_rx_dma_chain_handler + * + */ +/*N1*/ +static int aft_rx_dma_chain_handler(private_area_t *chan, int reset) +{ + sdla_t *card = chan->card; + u32 reg,dma_descr; + wp_rx_element_t *rx_el; + aft_dma_chain_t *dma_chain; + int i,max_dma_cnt, cur_dma_ptr; + int rx_data_available=0; + u32 dma_ram_desc; + + if (wan_test_and_set_bit(RX_HANDLER_BUSY,&chan->dma_status)){ + DEBUG_EVENT("%s: SMP Critical in %s\n", + chan->if_name,__FUNCTION__); + return rx_data_available; + } + + dma_ram_desc=chan->logic_ch_num*4 + AFT_PORT_REG(card,AFT_DMA_CHAIN_RAM_BASE_REG); + + card->hw_iface.bus_read_4(card->hw,dma_ram_desc,®); + cur_dma_ptr=aft_dmachain_get_rx_dma_addr(reg); + + max_dma_cnt = MAX_AFT_DMA_CHAINS; + + DEBUG_TEST("%s: DMA RX: CBoardPtr=%d Driver=%d MaxDMA=%d\n", + card->devname, + cur_dma_ptr, + chan->rx_chain_indx,max_dma_cnt); + +#if 0 + aft_chain_history(chan,chan->rx_chain_indx, cur_dma_ptr, chan->rx_pending_chain_indx,3); +#endif + + + for (i=0;irx_dma_chain_table[chan->rx_pending_chain_indx]; + + if (i>0 && chan->rx_pending_chain_indx == cur_dma_ptr){ + break; + } + + if (!dma_chain){ + DEBUG_EVENT("%s:%d Assertion Error !!!!\n", + __FUNCTION__,__LINE__); + break; + } + + /* If the current DMA chain is in use,then + * all chains are busy */ + if (!wan_test_bit(0,&dma_chain->init)){ + DEBUG_TEST("%s: Warning (%s) Pending chain %d empty!\n", + chan->if_name,__FUNCTION__,dma_chain->index); + + break; + } + + dma_descr=(chan->logic_ch_num<<4) + (dma_chain->index*AFT_DMA_INDEX_OFFSET) + + AFT_PORT_REG(card,AFT_RX_DMA_HI_DESCR_BASE_REG); + + card->hw_iface.bus_read_4(card->hw,dma_descr,®); + + /* If GO bit is set, then the current DMA chain + * is in process of being transmitted, thus + * all are busy */ + if (wan_test_bit(AFT_RXDMA_HI_GO_BIT,®)){ + + if (wan_test_bit(WP_FIFO_ERROR_BIT, &chan->pkt_error)){ + break; + } + +#if 0 + if (chan->single_dma_chain){ + DEBUG_EVENT("%s: CRITICAL (%s) Pending chain %d Go bit still set!\n", + chan->if_name,__FUNCTION__,dma_chain->index); + ++chan->if_stats.rx_errors; + }else{ + DEBUG_TEST("%s: Warning (%s) Pending chain %d Go bit still set!\n", + chan->if_name,__FUNCTION__,dma_chain->index); + } +#endif + break; + } + + if (!wan_test_bit(AFT_RXDMA_HI_INTR_DISABLE_BIT,®)){ + wan_clear_bit(RX_INTR_PENDING,&chan->dma_chain_status); + } + + card->hw_iface.pci_unmap_dma(card->hw, + dma_chain->dma_addr, + chan->dma_mru, + PCI_DMA_FROMDEVICE); + + if (sizeof(wp_rx_element_t) > wan_skb_headroom(dma_chain->skb)){ + if (WAN_NET_RATELIMIT()){ + DEBUG_EVENT("%s: Rx error: rx_el=%u > max head room=%u\n", + chan->if_name, + (u32)sizeof(wp_rx_element_t), + (u32)wan_skb_headroom(dma_chain->skb)); + } + + aft_init_requeue_free_skb(chan, dma_chain->skb); + ++chan->if_stats.rx_errors; + goto rx_hndlr_skip_rx; + }else{ + rx_el=(wp_rx_element_t *)wan_skb_push(dma_chain->skb, + sizeof(wp_rx_element_t)); + memset(rx_el,0,sizeof(wp_rx_element_t)); + } +#if 0 + chan->if_stats.rx_frame_errors++; +#endif + + /* Reading Rx DMA descriptor information */ + dma_descr=(chan->logic_ch_num<<4) +(dma_chain->index*AFT_DMA_INDEX_OFFSET) + + AFT_PORT_REG(card,AFT_RX_DMA_LO_DESCR_BASE_REG); + + card->hw_iface.bus_read_4(card->hw,dma_descr, &rx_el->align); + rx_el->align&=AFT_RXDMA_LO_ALIGN_MASK; + + dma_descr=(chan->logic_ch_num<<4) +(dma_chain->index*AFT_DMA_INDEX_OFFSET) + + AFT_PORT_REG(card,AFT_RX_DMA_HI_DESCR_BASE_REG); + + card->hw_iface.bus_read_4(card->hw,dma_descr, &rx_el->reg); + + rx_el->pkt_error= dma_chain->pkt_error; + rx_el->dma_addr = dma_chain->dma_addr; + + wan_skb_queue_tail(&chan->wp_rx_complete_list,dma_chain->skb); + rx_data_available=1; + + DEBUG_TEST("%s: RxInt Pending chain %d Rxlist=%d LO:0x%X HI:0x%X Data=0x%X Len=%d!\n", + chan->if_name,dma_chain->index, + wan_skb_queue_len(&chan->wp_rx_complete_list), + rx_el->align,rx_el->reg, + (*(unsigned char*)wan_skb_data(dma_chain->skb)), + wan_skb_len(dma_chain->skb)); + +rx_hndlr_skip_rx: + dma_chain->skb=NULL; + dma_chain->dma_addr=0; + dma_chain->dma_len=0; + dma_chain->pkt_error=0; + wan_clear_bit(0,&dma_chain->init); + + if (chan->single_dma_chain){ + break; + } + + if (++chan->rx_pending_chain_indx >= MAX_AFT_DMA_CHAINS){ + chan->rx_pending_chain_indx=0; + } + } + + if (reset){ + goto reset_skip_rx_setup; + } + + aft_dma_rx(card,chan); + + + if (wan_skb_queue_len(&chan->wp_rx_complete_list)){ + DEBUG_TEST("%s: Rx Queued list triggering\n",chan->if_name); + WAN_TASKLET_SCHEDULE((&chan->common.bh_task)); + } + +reset_skip_rx_setup: + + wan_clear_bit(RX_HANDLER_BUSY,&chan->dma_status); + + + return rx_data_available; +} + +static int aft_dma_rx_complete(sdla_t *card, private_area_t *chan, int reset) +{ + if (chan->cfg.ss7_enable){ + aft_clear_ss7_force_rx(card,chan); + } + return aft_rx_dma_chain_handler(chan,reset); +} + +/*=============================================== + * TE1 DMA Chains Utility Funcitons + * + */ + + +static void aft_index_tx_rx_dma_chains(private_area_t *chan) +{ + int i; + + for (i=0;itx_dma_chain_table[i].index=i; + chan->rx_dma_chain_table[i].index=i; + } +} + + +static void aft_init_tx_rx_dma_descr(private_area_t *chan) +{ + int i; + u32 reg=0; + sdla_t *card=chan->card; + unsigned long tx_dma_descr,rx_dma_descr; + unsigned int dma_cnt=MAX_AFT_DMA_CHAINS; + + if (chan->single_dma_chain){ + dma_cnt=1; + } + + for (i=0;ilogic_ch_num<<4) + + (i*AFT_DMA_INDEX_OFFSET) + + AFT_PORT_REG(card,AFT_TX_DMA_HI_DESCR_BASE_REG); + + rx_dma_descr=(chan->logic_ch_num<<4) + + (i*AFT_DMA_INDEX_OFFSET) + + AFT_PORT_REG(card,AFT_RX_DMA_HI_DESCR_BASE_REG); + + card->hw_iface.bus_write_4(card->hw,tx_dma_descr,reg); + card->hw_iface.bus_write_4(card->hw,rx_dma_descr,reg); + + aft_tx_dma_chain_init(chan,&chan->tx_dma_chain_table[i]); + aft_tx_dma_chain_init(chan,&chan->rx_dma_chain_table[i]); + } +} + +static void aft_free_rx_complete_list(private_area_t *chan) +{ + void *skb; + + while((skb=wan_skb_dequeue(&chan->wp_rx_complete_list)) != NULL){ + DEBUG_TEST("%s: aft_free_rx_complete_list dropped\n", + chan->if_name); + chan->if_stats.rx_dropped++; + aft_init_requeue_free_skb(chan, skb); + } +} + +static void aft_rx_cur_go_test(private_area_t *chan) +{ +#if 0 + u32 reg,cur_dma_ptr; + sdla_t *card=chan->card; + aft_dma_chain_t *dma_chain; + u32 dma_descr; + int i; + u32 dma_ram_desc; + unsigned int dma_cnt=MAX_AFT_DMA_CHAINS; + + dma_ram_desc=chan->logic_ch_num*4 + AFT_PORT_REG(card,AFT_DMA_CHAIN_RAM_BASE_REG); + card->hw_iface.bus_read_4(card->hw,dma_ram_desc,®); + cur_dma_ptr=aft_dmachain_get_rx_dma_addr(reg); + + dma_descr=(chan->logic_ch_num<<4) +(cur_dma_ptr*AFT_DMA_INDEX_OFFSET) + + AFT_PORT_REG(card,AFT_RX_DMA_HI_DESCR_BASE_REG); + + card->hw_iface.bus_read_4(card->hw,dma_descr,®); + + if (!wan_test_bit(AFT_RXDMA_HI_GO_BIT,®)){ + DEBUG_EVENT("%s: CRITICAL Cur =%d not Got bit set!\n", + chan->if_name, + cur_dma_ptr); + + + aft_list_descriptors(chan); + } +#endif +} + + +#if 0 +static void aft_list_descriptors(private_area_t *chan) +{ + u32 reg,cur_dma_ptr; + sdla_t *card=chan->card; + aft_dma_chain_t *dma_chain; + u32 dma_descr; + int i; + u32 dma_ram_desc; + unsigned int dma_cnt=MAX_AFT_DMA_CHAINS; + + dma_ram_desc=chan->logic_ch_num*4 + AFT_PORT_REG(card,AFT_DMA_CHAIN_RAM_BASE_REG); + card->hw_iface.bus_read_4(card->hw,dma_ram_desc,®); + cur_dma_ptr=aft_dmachain_get_rx_dma_addr(reg); + + DEBUG_EVENT("%s: RX Chain DMA List: End=%d Begin=%d Cur=%d \n", + chan->if_name, + chan->rx_chain_indx, + chan->rx_pending_chain_indx, + cur_dma_ptr); + + if (chan->single_dma_chain){ + dma_cnt=1; + } + + for (i=0;irx_dma_chain_table[i]; + if (!dma_chain){ + DEBUG_EVENT("%s:%d Assertion Error !!!!\n", + __FUNCTION__,__LINE__); + break; + } + + dma_descr=(chan->logic_ch_num<<4) +(dma_chain->index*AFT_DMA_INDEX_OFFSET) + + AFT_PORT_REG(card,AFT_RX_DMA_HI_DESCR_BASE_REG); + + card->hw_iface.bus_read_4(card->hw,dma_descr,®); + + DEBUG_EVENT("%s: DMA=%d : Go=%u Intr=%u Used=%lu A=0%X R=0x%X\n", + chan->if_name, + dma_chain->index, + wan_test_bit(AFT_RXDMA_HI_GO_BIT,®), + !wan_test_bit(AFT_RXDMA_HI_INTR_DISABLE_BIT,®), + dma_chain->init,dma_descr,reg); + } +} +#endif + +#if 0 +static void aft_list_tx_descriptors(private_area_t *chan) +{ + u32 reg,cur_dma_ptr; + sdla_t *card=chan->card; + aft_dma_chain_t *dma_chain; + u32 dma_descr; + int i; + u32 dma_ram_desc; + unsigned int dma_cnt=MAX_AFT_DMA_CHAINS; + + dma_ram_desc=chan->logic_ch_num*4 + AFT_PORT_REG(card,AFT_DMA_CHAIN_RAM_BASE_REG); + card->hw_iface.bus_read_4(card->hw,dma_ram_desc,®); + cur_dma_ptr=aft_dmachain_get_tx_dma_addr(reg); + + + DEBUG_EVENT("%s: TX Chain DMA List: Cur(End)=%d, Pend(Begin)=%d HWCur=%d\n", + chan->if_name, + chan->tx_chain_indx, + chan->tx_pending_chain_indx, + cur_dma_ptr); + + if (chan->single_dma_chain){ + dma_cnt=1; + } + + for (i=0;itx_dma_chain_table[i]; + if (!dma_chain){ + DEBUG_EVENT("%s:%d Assertion Error !!!!\n", + __FUNCTION__,__LINE__); + break; + } + + dma_descr=(chan->logic_ch_num<<4) + + (dma_chain->index*AFT_DMA_INDEX_OFFSET) + + AFT_PORT_REG(card,AFT_TX_DMA_HI_DESCR_BASE_REG); + + card->hw_iface.bus_read_4(card->hw,dma_descr,®); + + DEBUG_EVENT("%s: DMA=%d : Go=%u Intr=%u Used=%lu A=0%X R=0x%08X\n", + chan->if_name, + dma_chain->index, + wan_test_bit(AFT_TXDMA_HI_GO_BIT,®), + wan_test_bit(AFT_TXDMA_HI_INTR_DISABLE_BIT,®) ? 0:1, + dma_chain->init, + dma_descr, + reg); + + } +} +#endif + +#if 0 +static void aft_list_dma_chain_regs(sdla_t *card) +{ + u32 reg; + int i; + u32 dma_ram_desc; + + for (i=0; iu.aft.num_of_time_slots;i++){ + + private_area_t *chan; + + if (!wan_test_bit(i,&card->u.aft.logic_ch_map)){ + continue; + } + + chan=(private_area_t*)card->u.aft.dev_to_ch_map[i]; + if (!chan){ + continue; + } + + if (!wan_test_bit(0,&chan->up)){ + continue; + } + + dma_ram_desc=chan->logic_ch_num*4 + AFT_PORT_REG(card,AFT_DMA_CHAIN_RAM_BASE_REG); + card->hw_iface.bus_read_4(card->hw,dma_ram_desc,®); + + DEBUG_EVENT("%s: DMA CHAIN: %i: 0x%08X\n", + card->devname,i,reg); + + } +} +#endif + + +static void aft_free_rx_descriptors(private_area_t *chan) +{ + u32 reg; + sdla_t *card=chan->card; + aft_dma_chain_t *dma_chain; + u32 dma_descr; + int i; + unsigned int dma_cnt=MAX_AFT_DMA_CHAINS; + + if (chan->single_dma_chain){ + dma_cnt=1; + } + + for (i=0;irx_dma_chain_table[i]; + if (!dma_chain){ + DEBUG_EVENT("%s:%d Assertion Error !!!!\n", + __FUNCTION__,__LINE__); + break; + } + + dma_descr=(chan->logic_ch_num<<4) + + (dma_chain->index*AFT_DMA_INDEX_OFFSET) + + AFT_PORT_REG(card,AFT_RX_DMA_HI_DESCR_BASE_REG); + + DEBUG_TEST("%s:%s: Rx: Freeing Descripors Ch=%ld Desc=0x%X\n", + card->devname,chan->if_name,chan->logic_ch_num,dma_descr); + + card->hw_iface.bus_read_4(card->hw,dma_descr,®); + + /* If GO bit is set, then the current DMA chain + * is in process of being transmitted, thus + * all are busy */ + reg=0; + card->hw_iface.bus_write_4(card->hw,dma_descr,reg); + + card->hw_iface.pci_unmap_dma(card->hw, + dma_chain->dma_addr, + chan->dma_mru, + PCI_DMA_FROMDEVICE); + + if (dma_chain->skb){ + aft_init_requeue_free_skb(chan, dma_chain->skb); + } + + dma_chain->skb=NULL; + dma_chain->dma_addr=0; + dma_chain->dma_len=0; + dma_chain->pkt_error=0; + wan_clear_bit(0,&dma_chain->init); + } + +} + +static void aft_reset_rx_chain_cnt(private_area_t *chan) +{ + u32 dma_ram_desc,reg,cur_dma_ptr; + sdla_t *card=chan->card; + + dma_ram_desc=chan->logic_ch_num*4+ + AFT_PORT_REG(card,AFT_DMA_CHAIN_RAM_BASE_REG); + card->hw_iface.bus_read_4(card->hw,dma_ram_desc,®); + cur_dma_ptr=aft_dmachain_get_rx_dma_addr(reg); + chan->rx_pending_chain_indx = chan->rx_chain_indx = cur_dma_ptr; + DEBUG_TEST("%s: Setting Rx Index to %d\n", + chan->if_name,cur_dma_ptr); + +} + +static void aft_reset_tx_chain_cnt(private_area_t *chan) +{ + u32 dma_ram_desc,reg,cur_dma_ptr; + sdla_t *card=chan->card; + + dma_ram_desc=chan->logic_ch_num*4+ + AFT_PORT_REG(card,AFT_DMA_CHAIN_RAM_BASE_REG); + card->hw_iface.bus_read_4(card->hw,dma_ram_desc,®); + cur_dma_ptr=aft_dmachain_get_tx_dma_addr(reg); + chan->tx_pending_chain_indx = chan->tx_chain_indx = cur_dma_ptr; + DEBUG_TEST("%s: Setting Tx Index to %d\n", + chan->if_name,cur_dma_ptr); + +} + + + +static void aft_free_tx_descriptors(private_area_t *chan) +{ + u32 reg,dma_descr; + sdla_t *card=chan->card; + aft_dma_chain_t *dma_chain; + int i; + void *skb; + unsigned int dma_cnt=MAX_AFT_DMA_CHAINS; + + if (chan->single_dma_chain){ + dma_cnt=1; + } + + DEBUG_TEST("%s:%s: Tx: Freeing Descripors\n",card->devname,chan->if_name); + + for (i=0;itx_dma_chain_table[i]; + if (!dma_chain){ + DEBUG_EVENT("%s:%d Assertion Error !!!!\n", + __FUNCTION__,__LINE__); + break; + } + + dma_descr=(chan->logic_ch_num<<4) +(dma_chain->index*AFT_DMA_INDEX_OFFSET) + + AFT_PORT_REG(card,AFT_TX_DMA_HI_DESCR_BASE_REG); + + DEBUG_TEST("%s:%s: Tx: Freeing Descripors Ch=%ld Desc=0x%X\n", + card->devname,chan->if_name,chan->logic_ch_num,dma_descr); + reg=0; + card->hw_iface.bus_write_4(card->hw,dma_descr,reg); + + aft_tx_dma_chain_init(chan, dma_chain); + } + + chan->tx_chain_indx = chan->tx_pending_chain_indx; + + while((skb=wan_skb_dequeue(&chan->wp_tx_complete_list)) != NULL){ + wan_skb_free(skb); + } +} + + +/*===================================================== + * Chanalization/Logic Channel utilites + * + */ + + + + +void aft_free_logical_channel_num (sdla_t *card, int logic_ch) +{ + wan_clear_bit (logic_ch,&card->u.aft.logic_ch_map); + card->u.aft.dev_to_ch_map[logic_ch]=NULL; + + if (logic_ch >= card->u.aft.top_logic_ch){ + int i; + + card->u.aft.top_logic_ch=AFT_DEFLT_ACTIVE_CH; + + for (i=0;iu.aft.num_of_time_slots;i++){ + if (card->u.aft.dev_to_ch_map[logic_ch]){ + card->u.aft.top_logic_ch=i; + } + } + + aft_dma_max_logic_ch(card); + } + +} + +void aft_dma_max_logic_ch(sdla_t *card) +{ + u32 reg; + + DEBUG_TEST("%s: Maximum Logic Ch set to %d \n", + card->devname,card->u.aft.top_logic_ch); + + reg=0; + card->hw_iface.bus_read_4(card->hw,AFT_PORT_REG(card,AFT_DMA_CTRL_REG),®); + aft_dmactrl_set_max_logic_ch(®,card->u.aft.top_logic_ch); + card->hw_iface.bus_write_4(card->hw,AFT_PORT_REG(card,AFT_DMA_CTRL_REG),reg); +} + +static int aft_tslot_sync_ctrl(sdla_t *card, private_area_t *chan, int mode) +{ + u32 dma_ram_reg,reg; + + if (chan->hdlc_eng){ + return 0; + } + + dma_ram_reg=AFT_PORT_REG(card,AFT_DMA_CHAIN_RAM_BASE_REG); + dma_ram_reg+=(chan->logic_ch_num*4); + + card->hw_iface.bus_read_4(card->hw, dma_ram_reg, ®); + + if (mode){ + wan_set_bit(AFT_DMACHAIN_RX_SYNC_BIT,®); + }else{ + wan_clear_bit(AFT_DMACHAIN_RX_SYNC_BIT,®); + } + + card->hw_iface.bus_write_4(card->hw, dma_ram_reg, reg); + + return 0; +} + + + +static int aft_read_security(sdla_t *card) +{ + int adptr_security; + wan_smp_flag_t flags,smp_flags; + + if (card->adptr_subtype == AFT_SUBTYPE_SHARK){ + /* Shark cards are always channelized */ + card->u.aft.security_id=0x01; + return 0; + } + + card->hw_iface.hw_lock(card->hw,&smp_flags); + wan_spin_lock_irq(&card->wandev.lock,&flags); + adptr_security=aft_read_cpld(card,0x09); + wan_spin_unlock_irq(&card->wandev.lock,&flags); + card->hw_iface.hw_unlock(card->hw,&smp_flags); + + adptr_security=(adptr_security>>2)&0x03; + card->u.aft.security_id=adptr_security; + + if (adptr_security == 0x00){ + DEBUG_EVENT("%s: AFT Security: UnChannelised\n", + card->devname); + }else if (adptr_security == 0x01){ + DEBUG_EVENT("%s: AFT Security: Channelised\n", + card->devname); + }else{ + DEBUG_EVENT("%s: AFT Security: Unknown\n", + card->devname); + return -EINVAL; + } + + card->u.aft.security_cnt=0; + + return 0; +} + + +static int aft_front_end_mismatch_check(sdla_t * card) +{ + u32 reg; + + card->hw_iface.bus_read_4(card->hw,AFT_CHIP_CFG_REG, ®); + + if (IS_T1_CARD(card)){ + if (wan_test_bit(AFT_CHIPCFG_TE1_CFG_BIT,®)){ + DEBUG_EVENT("%s: Global Cfg Error: Inital front end cfg: E1\n", + card->devname); + return -EINVAL; + } + }else{ + if (!wan_test_bit(AFT_CHIPCFG_TE1_CFG_BIT,®)){ + DEBUG_EVENT("%s: Global Cfg Error: Inital front end cfg: T1\n", + card->devname); + return -EINVAL; + } + } + + return 0; +} + +static int aft_realign_skb_pkt(private_area_t *chan, netskb_t *skb) +{ + unsigned char *data=wan_skb_data(skb); + int len = wan_skb_len(skb); + + if (len > chan->dma_mru){ + DEBUG_EVENT("%s: Critical error: Tx unalign pkt(%d) > MTU buf(%d)!\n", + chan->if_name,len,chan->dma_mru); + return -ENOMEM; + } + + if (!chan->tx_realign_buf){ + chan->tx_realign_buf=wan_malloc(chan->dma_mru); + if (!chan->tx_realign_buf){ + DEBUG_EVENT("%s: Error: Failed to allocate tx memory buf\n", + chan->if_name); + return -ENOMEM; + }else{ + DEBUG_EVENT("%s: AFT Realign buffer allocated Len=%d\n", + chan->if_name,chan->dma_mru); + + } + } + + memcpy(chan->tx_realign_buf,data,len); + + wan_skb_init(skb,0); + wan_skb_trim(skb,0); + + if (wan_skb_tailroom(skb) < len){ + DEBUG_EVENT("%s: Critical error: Tx unalign pkt tail room(%i) < unalign len(%i)!\n", + chan->if_name,wan_skb_tailroom(skb),len); + + return -ENOMEM; + } + + data=wan_skb_put(skb,len); + + if ((unsigned long)data & 0x03){ + /* At this point pkt should be realigned. If not + * there is something really wrong! */ + return -EINVAL; + } + + memcpy(data,chan->tx_realign_buf,len); + + chan->opstats.Data_frames_Tx_realign_count++; + + return 0; +} + +void aft_wdt_set(sdla_t *card, unsigned char val) +{ + u8 reg; + u32 wdt_ctrl_reg=AFT_WDT_1TO4_CTRL_REG+card->wandev.comm_port; + + if (card->wandev.comm_port > 3) { + wdt_ctrl_reg=AFT_WDT_4TO8_CTRL_REG+(card->wandev.comm_port%4); + } + + card->hw_iface.bus_read_1(card->hw,wdt_ctrl_reg, ®); + aft_wdt_ctrl_set(®,val); + card->hw_iface.bus_write_1(card->hw,wdt_ctrl_reg, reg); +} +void aft_wdt_reset(sdla_t *card) +{ + u8 reg; + u32 wdt_ctrl_reg=AFT_WDT_1TO4_CTRL_REG+card->wandev.comm_port; + + if (card->wandev.comm_port > 3) { + wdt_ctrl_reg=AFT_WDT_4TO8_CTRL_REG+(card->wandev.comm_port%4); + } + + card->hw_iface.bus_read_1(card->hw, wdt_ctrl_reg, ®); + aft_wdt_ctrl_reset(®); + card->hw_iface.bus_write_1(card->hw, wdt_ctrl_reg, reg); +} + +#if defined(__LINUX__) +static void aft_port_task (void * card_ptr) +#else +static void aft_port_task (void * card_ptr, int arg) +#endif +{ + sdla_t *card = (sdla_t *)card_ptr; + wan_smp_flag_t smp_flags; + + if (wan_test_bit(CARD_DOWN,&card->wandev.critical)){ + return; + } + + DEBUG_TEST("%s: PORT TASK: 0x%X\n", card->devname,card->u.aft.port_task_cmd); + + + if (wan_test_bit(AFT_FE_INTR,&card->u.aft.port_task_cmd)){ + + DEBUG_TEST("%s: PORT TASK: FE INTER\n", card->devname); + + card->hw_iface.hw_lock(card->hw,&smp_flags); + aft_fe_intr_ctrl(card, 0); + front_end_interrupt(card,0,1); + wan_clear_bit(AFT_FE_INTR,&card->u.aft.port_task_cmd); + aft_fe_intr_ctrl(card, 1); + card->hw_iface.hw_unlock(card->hw,&smp_flags); + + } + + if (wan_test_bit(AFT_FE_POLL,&card->u.aft.port_task_cmd)){ + DEBUG_TEST("%s: PORT TASK: FE POLL\n", card->devname); + card->hw_iface.hw_lock(card->hw,&smp_flags); + aft_fe_intr_ctrl(card, 0); + if (card->wandev.fe_iface.polling){ + wan_smp_flag_t smp_irq_flags; + card->wandev.fe_iface.polling(&card->fe); + + wan_spin_lock_irq(&card->wandev.lock,&smp_irq_flags); + handle_front_end_state(card); + wan_spin_unlock_irq(&card->wandev.lock,&smp_irq_flags); + } + wan_clear_bit(AFT_FE_POLL,&card->u.aft.port_task_cmd); + aft_fe_intr_ctrl(card, 1); + card->hw_iface.hw_unlock(card->hw,&smp_flags); + } + + if (wan_test_bit(AFT_FE_LED,&card->u.aft.port_task_cmd)){ + DEBUG_TEST("%s: PORT TASK: FE LED\n", card->devname); + card->hw_iface.hw_lock(card->hw,&smp_flags); + aft_fe_intr_ctrl(card, 0); + if (card->wandev.state == WAN_CONNECTED){ + aft_hwdev[card->wandev.card_type].aft_led_ctrl(card, WAN_AFT_RED, 0,WAN_AFT_OFF); + aft_hwdev[card->wandev.card_type].aft_led_ctrl(card, WAN_AFT_GREEN, 0, WAN_AFT_ON); + }else{ + aft_hwdev[card->wandev.card_type].aft_led_ctrl(card, WAN_AFT_RED, 0,WAN_AFT_ON); + aft_hwdev[card->wandev.card_type].aft_led_ctrl(card, WAN_AFT_GREEN, 0, WAN_AFT_OFF); + } + wan_clear_bit(AFT_FE_LED,&card->u.aft.port_task_cmd); + aft_fe_intr_ctrl(card, 1); + card->hw_iface.hw_unlock(card->hw,&smp_flags); + } + +#ifdef CONFIG_PRODUCT_WANPIPE_TDM_VOICE + if (wan_test_bit(AFT_FE_TDM_RBS,&card->u.aft.port_task_cmd)){ + int err; + DEBUG_TEST("%s: PORT TASK: FE RBS\n", card->devname); + card->hw_iface.hw_lock(card->hw,&smp_flags); + + WAN_TDMV_CALL(rbsbits_poll, (&card->wan_tdmv, card), err); + + wan_clear_bit(AFT_FE_TDM_RBS,&card->u.aft.port_task_cmd); + card->hw_iface.hw_unlock(card->hw,&smp_flags); + } +#endif + +#if defined(CONFIG_WANPIPE_HWEC) + if (wan_test_bit(AFT_FE_EC_POLL,&card->u.aft.port_task_cmd)){ + + DEBUG_TEST("%s: PORT TASK: FE EC INTR\n", card->devname); + + if (card->wandev.ec_dev){ + card->hw_iface.hw_lock(card->hw,&smp_flags); + aft_fe_intr_ctrl(card, 0); + wanpipe_ec_poll(card->wandev.ec_dev, card); + wan_clear_bit(AFT_FE_EC_POLL,&card->u.aft.port_task_cmd); + aft_fe_intr_ctrl(card, 1); + card->hw_iface.hw_unlock(card->hw,&smp_flags); + } + } +#endif + +} + +static void __aft_fe_intr_ctrl(sdla_t *card, int status) +{ + u32 reg; + + card->hw_iface.bus_read_4(card->hw,AFT_CHIP_CFG_REG,®); + if (status){ + wan_set_bit(AFT_CHIPCFG_FE_INTR_CFG_BIT,®); + }else{ + wan_clear_bit(AFT_CHIPCFG_FE_INTR_CFG_BIT,®); + } + card->hw_iface.bus_write_4(card->hw,AFT_CHIP_CFG_REG,reg); + +} + +void aft_fe_intr_ctrl(sdla_t *card, int status) +{ + wan_smp_flag_t smp_flags; + + wan_spin_lock_irq(&card->wandev.lock,&smp_flags); + __aft_fe_intr_ctrl(card,status); + wan_spin_unlock_irq(&card->wandev.lock,&smp_flags); + +} + +static void aft_data_mux_cfg(sdla_t *card) +{ + if (!card->u.aft.cfg.data_mux_map){ + card->u.aft.cfg.data_mux_map=AFT_DEFAULT_DATA_MUX_MAP; + } + + card->hw_iface.bus_write_4(card->hw, AFT_DATA_MUX_REG, + card->u.aft.cfg.data_mux_map); + + DEBUG_EVENT("%s: AFT Data Mux Bit Map: 0x%08X\n", + card->devname,card->u.aft.cfg.data_mux_map); +} + +static void aft_data_mux_get_cfg(sdla_t *card) +{ + card->hw_iface.bus_read_4(card->hw, AFT_DATA_MUX_REG, + &card->u.aft.cfg.data_mux_map); + +} + + +static int aft_ss7_tx_mangle(sdla_t *card,private_area_t *chan, netskb_t *skb) +{ + int ss7_len=0,len=0; + unsigned int ss7_ctrl=0; + unsigned char *buf; + api_tx_hdr_t *tx_hdr = &chan->tx_api_hdr; + + memcpy(&chan->tx_api_hdr,wan_skb_data(skb),sizeof(api_tx_hdr_t)); + wan_skb_pull(skb,sizeof(api_tx_hdr_t)); + + if (!chan->tx_ss7_realign_buf){ + chan->tx_ss7_realign_buf=wan_malloc(chan->dma_mru); + if (!chan->tx_ss7_realign_buf){ + DEBUG_EVENT("%s: Error: Failed to allocate ss7 tx memory buf\n", + chan->if_name); + return -ENOMEM; + }else{ + DEBUG_TEST("%s: AFT SS7 Realign buffer allocated Len=%d\n", + chan->if_name,chan->dma_mru); + } + } + + memset(chan->tx_ss7_realign_buf,0,chan->dma_mru); + memcpy(chan->tx_ss7_realign_buf,wan_skb_data(skb),wan_skb_len(skb)); + len=wan_skb_len(skb); + + /* Align the end of the frame to 32 byte boundary */ + ss7_ctrl=(len%4)&AFT_SS7_CTRL_LEN_MASK; + if (ss7_ctrl != 0){ + len-=len%4; + len+=4; + } + + if (tx_hdr->u.ss7.type == WANOPT_SS7_FISU){ + if (chan->cfg.ss7_mode == WANOPT_SS7_MODE_4096){ + ss7_len=WANOPT_SS7_FISU_4096_SZ; + }else{ + ss7_len=WANOPT_SS7_FISU_128_SZ; + } + wan_clear_bit(AFT_SS7_CTRL_TYPE_BIT,&ss7_ctrl); + }else{ + ss7_len=chan->cfg.ss7_lssu_size; + wan_set_bit(AFT_SS7_CTRL_TYPE_BIT,&ss7_ctrl); + } + + if (tx_hdr->u.ss7.force_tx){ + wan_set_bit(AFT_SS7_CTRL_FORCE_BIT,&ss7_ctrl); + }else{ + wan_clear_bit(AFT_SS7_CTRL_FORCE_BIT,&ss7_ctrl); + } + + DEBUG_TEST("%s: SS7 DATA = 0x%X 0x%X 0x%X\n", + chan->if_name, + tx_hdr->u.ss7.data[0], + tx_hdr->u.ss7.data[1], + tx_hdr->u.ss7.data[2]); + + memcpy(&chan->tx_ss7_realign_buf[len],tx_hdr->u.ss7.data,ss7_len); + + len+=ss7_len; + + wan_skb_init(skb,0); + wan_skb_trim(skb,0); + + if (wan_skb_tailroom(skb) < len){ + DEBUG_EVENT("%s: Critical error: SS7 Tx unalign pkt tail room(%i) < len(%i)!\n", + chan->if_name,wan_skb_tailroom(skb),len); + + return -ENOMEM; + } + + buf=wan_skb_put(skb,len); + memcpy(buf,chan->tx_ss7_realign_buf,len); + + wan_skb_set_csum(skb, ss7_ctrl); + +#if 0 + debug_print_skb_pkt(chan->if_name, wan_skb_data(skb), wan_skb_len(skb), 0); +#endif + return 0; +} + + + + +#if 0 +static void aft_chain_history(private_area_t *chan,u8 end, u8 cur, u8 begin, u8 loc) +{ + dma_history_t *dma_hist = &chan->dma_history[chan->dma_index]; + + dma_hist->loc=loc; + dma_hist->end=end; + dma_hist->cur=cur; + dma_hist->begin=begin; + dma_hist->status=0; + + if (end > begin){ + if (cur > end || + cur < begin){ + DEBUG_TEST("%s: Rx: Critical: RxPendChain=%d HWDMA=%d RxEndChain=%d\n", + chan->if_name,begin,cur,end); + dma_hist->status=1; + } + }else if (end < begin){ + if (cur < begin && + cur > end){ + DEBUG_TEST("%s: Rx: Critical: RxEndChain=%d HWDMA=%d RxPendingChain=%d\n", + chan->if_name,begin,cur,end); + dma_hist->status=1; + + } + } + + if (++chan->dma_index >= MAX_DMA_HIST_SIZE){ + chan->dma_index=0; + } +} +#endif + +#if 0 +static void aft_display_chain_history(private_area_t *chan) +{ + int start=chan->dma_index; + int i; + dma_history_t *dma_hist = &chan->dma_history[start]; + + for (i=0;iloc == 0){ + continue; + } + + DEBUG_EVENT("%s: Loc=%02i End=%02d Cur=%02d Beg=%02d St=%s\n", + chan->if_name, + dma_hist->loc, + dma_hist->end, + dma_hist->cur, + dma_hist->begin, + dma_hist->status?"Error":"Ok"); + + start++; + if (start >= MAX_DMA_HIST_SIZE){ + start=0; + } + dma_hist = &chan->dma_history[start]; + } +} +#endif + +/* + * ****************************************************************** + * Proc FS function + */ +static int wan_aft_get_info(void* pcard, struct seq_file *m, int *stop_cnt) +{ + sdla_t *card = (sdla_t*)pcard; + + if (card->wandev.fe_iface.update_alarm_info){ + m->count = + WAN_FECALL( + &card->wandev, + update_alarm_info, + (&card->fe, m, stop_cnt)); + } + if (card->wandev.fe_iface.update_pmon_info){ + m->count = + WAN_FECALL( + &card->wandev, + update_pmon_info, + (&card->fe, m, stop_cnt)); + } + + return m->count; +} + +static int aft_tdmv_init(sdla_t *card, wandev_conf_t *conf) +{ + + int err; + int valid_firmware_ver=AFT_TDMV_FRM_VER; + + err=0; + DEBUG_EVENT("%s: TDMV Span = %d : %s\n", + card->devname, + card->u.aft.cfg.tdmv_span_no, + card->u.aft.cfg.tdmv_span_no?"Enabled":"Disabled"); + + if (card->u.aft.cfg.tdmv_span_no) { + if (card->wandev.config_id == WANCONFIG_AFT_ANALOG) { + valid_firmware_ver=AFT_MIN_ANALOG_FRMW_VER; + } + + if (card->u.aft.firm_ver < valid_firmware_ver){ + DEBUG_EVENT("%s: Error: Obselete AFT Firmware version: %X\n", + card->devname,card->u.aft.firm_ver); + DEBUG_EVENT("%s: Error: AFT TDMV Support depends on Firmware Ver >= %X\n", + card->devname,valid_firmware_ver); + return -EINVAL; + } + } + + + + return 0; + +} + + +/************************************************************** + * TDMV VOICE Functions + **************************************************************/ + +static int aft_tdmv_free(sdla_t *card) +{ +#if defined(CONFIG_PRODUCT_WANPIPE_TDM_VOICE) + if (card->u.aft.cfg.tdmv_span_no){ + int err; + WAN_TDMV_CALL(remove, (card), err); + } +#endif + return 0; +} + + +static int aft_tdmv_if_init(sdla_t *card, private_area_t *chan, wanif_conf_t *conf) +{ + + if (!chan->channelized_cfg){ + return 0; + } + + if (!card->u.aft.cfg.tdmv_span_no){ + DEBUG_EVENT("%s: Error: TDMV Span No is not set!\n", + card->devname); + return -EINVAL; + } + + if (chan->cfg.tdmv_master_if){ + DEBUG_EVENT("%s: Configuring TDMV Master dev %s\n", + card->devname,chan->if_name); + + /* Initialize a TDM bottom half handler + * Optionally used */ + WAN_TASKLET_INIT((&chan->common.bh_task),0,wp_tdm_bh,chan); + } + + if (conf->hdlc_streaming == 0){ + + int err; + + err=0; + + aft_hwdev[card->wandev.card_type].aft_fifo_adjust(card,AFT_TDMV_FIFO_LEVEL); + + if (chan->common.usedby == TDM_VOICE) { +#ifdef CONFIG_PRODUCT_WANPIPE_TDM_VOICE + WAN_TDMV_CALL(check_mtu, (card, conf->active_ch, &chan->mtu), err); + if (err){ + DEBUG_EVENT("Error: TMDV mtu check failed!"); + return -EINVAL; + } +#endif + } + + if (chan->common.usedby == TDM_VOICE_API) { + if (chan->mtu != 8 && chan->mtu != 16) { + chan->mtu = 16; + } + } + + chan->mru = chan->mtu; + + card->u.aft.tdmv_mtu += chan->mtu; + + if (chan->tdmv_zaptel_cfg){ + chan->cfg.data_mux=1; + } + + conf->hdlc_streaming=0; + chan->tx_realign_buf = NULL; +#ifdef CONFIG_PRODUCT_WANPIPE_TDM_VOICE + card->wan_tdmv.brt_enable=0; +#endif + + }else{ + chan->cfg.data_mux=0; + } + +#ifdef CONFIG_PRODUCT_WANPIPE_TDM_VOICE + if (chan->tdmv_zaptel_cfg){ + + /* The TDMV drivers always starts from number + * ZERO. Wanpipe driver doesn't allow timeslot + * ZERO. Thus, the active_ch map must me adjusted + * before calling tdmv_reg */ + if (IS_E1_CARD(card)){ + conf->active_ch=conf->active_ch>>1; + } + + WAN_TDMV_CALL(reg, (card, conf, chan->common.dev), chan->tdmv_chan); + if (chan->tdmv_chan < 0){ + DEBUG_EVENT("%s: Error: Failed to register TDMV channel!\n", + chan->if_name); + + return -EINVAL; + } + + + if (card->u.aft.tdmv_dchan_cfg_on_master && chan->cfg.tdmv_master_if){ + int dchan=card->u.aft.cfg.tdmv_dchan; + u32 orig_ch=conf->active_ch; + + if (IS_T1_CARD(card)){ + dchan--; + } + + conf->active_ch=0; + wan_set_bit(dchan,&conf->active_ch); + + WAN_TDMV_CALL(reg, (card, conf, chan->common.dev), card->u.aft.tdmv_chan); + if (card->u.aft.tdmv_chan < 0){ + DEBUG_EVENT("%s: Error: Failed to register TDMV channel!\n", + chan->if_name); + + return -EINVAL; + } + + card->u.aft.tdmv_dchan_active_ch=conf->active_ch; + conf->active_ch=orig_ch; + } + } +#endif + + return 0; + +} + + +static int aft_tdmv_if_free(sdla_t *card, private_area_t *chan) +{ +#ifdef CONFIG_PRODUCT_WANPIPE_TDM_VOICE + if (chan->tdmv_zaptel_cfg){ + int err; + WAN_TDMV_CALL(unreg, (card, chan->time_slot_map), err); + if (err){ + return err; + } + + if (card->u.aft.tdmv_dchan_cfg_on_master && chan->cfg.tdmv_master_if){ + DEBUG_EVENT("%s: Card Unregistering DCHAN\n", + card->devname); + WAN_TDMV_CALL(unreg, (card, card->u.aft.tdmv_dchan_active_ch), err); + card->u.aft.tdmv_dchan_cfg_on_master=0; + } + } +#endif + return 0; +} + +#if 0 +/* NCDEBUG */ +static int gtmp_cnt=0; +static void aft_set_channel(sdla_t *card, int ch) +{ + aft_dma_chain_t *tx_dma_chain; + u8 *buf; + private_area_t *chan=(private_area_t*)card->u.aft.dev_to_ch_map[ch]; + + if (!chan) return; + + tx_dma_chain = &chan->tx_dma_chain_table[0]; + if (!tx_dma_chain){ + return; + } + buf = (u8*)wan_skb_data(tx_dma_chain->skb); + buf[0]=gtmp_cnt++; + buf[1]=gtmp_cnt++; + buf[2]=gtmp_cnt++; + buf[3]=gtmp_cnt++; + buf[4]=gtmp_cnt++; + buf[5]=gtmp_cnt++; + buf[6]=gtmp_cnt++; + buf[7]=gtmp_cnt++; + + card->wandev.stats.tx_packets++; +} +#endif + +static int aft_dma_rx_tdmv(sdla_t *card, private_area_t *chan) +{ + int err; + + aft_dma_chain_t *tx_dma_chain = &chan->tx_dma_chain_table[0]; + aft_dma_chain_t *rx_dma_chain = &chan->rx_dma_chain_table[0]; + + err=0; + + if (!tx_dma_chain || !rx_dma_chain){ + DEBUG_EVENT("%s: %s:%d ASSERT ERROR TxDma=%p RxDma=%p\n", + card->devname,__FUNCTION__,__LINE__, + tx_dma_chain,rx_dma_chain); + return -EINVAL; + } + + if (!rx_dma_chain->skb || !tx_dma_chain->skb){ + DEBUG_TEST("%s: %s:%d ASSERT ERROR TxSkb=%p RxSkb=%p\n", + card->devname,__FUNCTION__,__LINE__, + rx_dma_chain->skb,tx_dma_chain->skb); + return -EINVAL; + } + +#if 0 + /*Measure the round trip delay*/ + if (!chan->tdmv_rx_delay_cfg){ + int i; + unsigned char *buf=(unsigned char*)wan_skb_data(rx_dma_chain->skb); + for (i=0;i<8;i++){ + if (buf[i]==0xFF){ + chan->tdmv_rx_delay_cfg=1; + DEBUG_EVENT("%s: Chan=%ld Delay=%d\n", + chan->if_name,chan->logic_ch_num, + chan->tdmv_rx_delay); + break; + } + chan->tdmv_rx_delay++; + } + } +#endif + + + if (chan->tdmv_zaptel_cfg){ +#ifdef CONFIG_PRODUCT_WANPIPE_TDM_VOICE + if (card->wan_tdmv.sc){ + +#if defined(AFT_TDMV_BH_ENABLE) + aft_dma_chain_t *tx_bh_dma_chain = &chan->tx_dma_chain_table[1]; + aft_dma_chain_t *rx_bh_dma_chain = &chan->rx_dma_chain_table[1]; + + if (!rx_bh_dma_chain->skb){ + rx_bh_dma_chain->skb=wan_skb_dequeue(&chan->wp_rx_free_list); + if (!rx_bh_dma_chain->skb){ + if (WAN_NET_RATELIMIT()){ + DEBUG_EVENT("%s: Critical TDM BH no free skb\n", + chan->if_name); + goto aft_tdm_bh_skip; + } + } + wan_skb_init(rx_bh_dma_chain->skb,16); + wan_skb_trim(rx_bh_dma_chain->skb,0); + } + + if (!tx_bh_dma_chain->skb){ + tx_bh_dma_chain->skb=wan_skb_dequeue(&chan->wp_rx_free_list); + if (!tx_bh_dma_chain->skb){ + if (WAN_NET_RATELIMIT()){ + DEBUG_EVENT("%s: Critical TDM BH no free skb\n", + chan->if_name); + goto aft_tdm_bh_skip; + } + } + wan_skb_init(tx_bh_dma_chain->skb,16); + wan_skb_trim(tx_bh_dma_chain->skb,0); + } + + memcpy(wan_skb_data(rx_bh_dma_chain->skb), + wan_skb_data(rx_dma_chain->skb),8); + + memcpy(wan_skb_data(tx_dma_chain->skb), + wan_skb_data(tx_bh_dma_chain->skb),8); + + rx_dma_chain=rx_bh_dma_chain; + tx_dma_chain=tx_bh_dma_chain; +aft_tdm_bh_skip: +#endif + + DEBUG_TEST ("%s: Calling Rx Chan=%i TdmvChan=%i\n", + card->devname,chan->logic_ch_num, + chan->tdmv_chan); + WAN_TDMV_CALL(rx_chan, + (&card->wan_tdmv,chan->tdmv_chan, + wan_skb_data(rx_dma_chain->skb), + wan_skb_data(tx_dma_chain->skb)), err); + +#if 0 + if (((u8*)wan_skb_data(tx_dma_chain->skb))[0] != 0xFF && + ((u8*)wan_skb_data(tx_dma_chain->skb))[0] != 0x7F && + tx_debug_cnt < 500){ + DEBUG_EVENT("%s: %02X %02X %02X %02X %02X %02X %02X %02X\n", + card->devname, + ((u8*)wan_skb_data(tx_dma_chain->skb))[0], + ((u8*)wan_skb_data(tx_dma_chain->skb))[1], + ((u8*)wan_skb_data(tx_dma_chain->skb))[2], + ((u8*)wan_skb_data(tx_dma_chain->skb))[3], + ((u8*)wan_skb_data(tx_dma_chain->skb))[4], + ((u8*)wan_skb_data(tx_dma_chain->skb))[5], + ((u8*)wan_skb_data(tx_dma_chain->skb))[6], + ((u8*)wan_skb_data(tx_dma_chain->skb))[7]); + tx_debug_cnt++; + } +#endif + }else{ + return 1; + } +#endif + }else{ + +#ifdef AFT_TDM_API_SUPPORT + wanpipe_tdm_api_rx_tx(&chan->wp_tdm_api_dev, + wan_skb_data(rx_dma_chain->skb), + wan_skb_data(tx_dma_chain->skb), + chan->mtu); +#endif + } + + if (chan->cfg.tdmv_master_if){ + u32 reg; + int err; + err=0; +#ifdef CONFIG_PRODUCT_WANPIPE_TDM_VOICE + if (chan->tdmv_zaptel_cfg){ + DEBUG_TEST ("%s: Calling Master Rx Tx Chan=%i\n", + card->devname,chan->logic_ch_num); +#if defined(AFT_TDMV_BH_ENABLE) +#warning "AFT A104: TDM Driver compiled in BH mode!" + + if (WAN_TASKLET_RUNNING((&chan->common.bh_task))){ + if (WAN_NET_RATELIMIT()){ + DEBUG_EVENT("%s: Critical Error: TDMV BH Overrun!\n", + card->devname); + } + } + + WAN_WP_TASKLET_SCHEDULE_PER_CPU((&chan->common.bh_task), + card->u.aft.cfg.tdmv_span_no); + + card->hw_iface.bus_read_4(card->hw,AFT_PORT_REG(card,AFT_DMA_CTRL_REG),®); + wan_set_bit(AFT_DMACTRL_TDMV_RX_TOGGLE,®); + wan_set_bit(AFT_DMACTRL_TDMV_TX_TOGGLE,®); + card->hw_iface.bus_write_4(card->hw,AFT_PORT_REG(card,AFT_DMA_CTRL_REG),reg); + +#else + WAN_TDMV_CALL(rx_tx_span, (card), err); + + card->hw_iface.bus_read_4(card->hw,AFT_PORT_REG(card,AFT_DMA_CTRL_REG),®); + wan_set_bit(AFT_DMACTRL_TDMV_RX_TOGGLE,®); + wan_set_bit(AFT_DMACTRL_TDMV_TX_TOGGLE,®); + card->hw_iface.bus_write_4(card->hw,AFT_PORT_REG(card,AFT_DMA_CTRL_REG),reg); + + if (card->wan_tdmv.sc){ + WAN_TDMV_CALL(is_rbsbits, (&card->wan_tdmv), err); + if (err == 1){ + wan_set_bit(AFT_FE_TDM_RBS,&card->u.aft.port_task_cmd); + WAN_TASKQ_SCHEDULE((&card->u.aft.port_task)); + } + } +#endif + }else{ +#else + if (!chan->tdmv_zaptel_cfg){ +#endif + card->hw_iface.bus_read_4(card->hw,AFT_PORT_REG(card,AFT_DMA_CTRL_REG),®); + wan_set_bit(AFT_DMACTRL_TDMV_RX_TOGGLE,®); + wan_set_bit(AFT_DMACTRL_TDMV_TX_TOGGLE,®); + card->hw_iface.bus_write_4(card->hw,AFT_PORT_REG(card,AFT_DMA_CTRL_REG),reg); + + } + + DEBUG_TEST("%s: Master device tx rx %i!\n", + card->devname,chan->logic_ch_num); + } + + chan->opstats.Data_frames_Rx_count++; + chan->opstats.Data_bytes_Rx_count+=chan->mru; + chan->opstats.Data_frames_Tx_count++; + chan->opstats.Data_bytes_Tx_count+=chan->mtu; + chan->if_stats.rx_packets++; + chan->if_stats.rx_bytes += chan->mru; + chan->if_stats.tx_packets++; + chan->if_stats.tx_bytes += chan->mtu; + + return 0; +} + +static int aft_fifo_intr_ctrl(sdla_t *card, int ctrl) +{ + u32 reg; + card->hw_iface.bus_read_4(card->hw, + AFT_PORT_REG(card,AFT_RX_FIFO_INTR_PENDING_REG), + ®); + + card->hw_iface.bus_read_4(card->hw, + AFT_PORT_REG(card,AFT_TX_FIFO_INTR_PENDING_REG), + ®); + + card->hw_iface.bus_read_4(card->hw, + AFT_PORT_REG(card,AFT_LINE_CFG_REG), ®); + + if (ctrl){ + wan_set_bit(AFT_LCFG_FIFO_INTR_BIT,®); + }else{ + wan_clear_bit(AFT_LCFG_FIFO_INTR_BIT,®); + } + + card->hw_iface.bus_write_4(card->hw, + AFT_PORT_REG(card,AFT_LINE_CFG_REG), reg); + + card->u.aft.lcfg_reg=reg; + + + if (!ctrl){ + card->hw_iface.bus_read_4(card->hw, + AFT_PORT_REG(card,AFT_RX_FIFO_INTR_PENDING_REG), + ®); + + card->hw_iface.bus_read_4(card->hw, + AFT_PORT_REG(card,AFT_TX_FIFO_INTR_PENDING_REG), + ®); + } + + return 0; +} + +static int aft_tdm_intr_ctrl(sdla_t *card, int ctrl) +{ + u32 reg; + card->hw_iface.bus_read_4(card->hw, + AFT_PORT_REG(card,AFT_LINE_CFG_REG), ®); + + if (ctrl){ + wan_set_bit(AFT_LCFG_TDMV_INTR_BIT,®); + + }else{ + wan_clear_bit(AFT_LCFG_TDMV_INTR_BIT,®); + } + + card->hw_iface.bus_write_4(card->hw, + AFT_PORT_REG(card,AFT_LINE_CFG_REG), reg); + + card->u.aft.lcfg_reg=reg; + + return 0; +} + +static int wan_aft_api_ioctl(sdla_t *card, private_area_t *chan, char *user_data) +{ + api_tx_hdr_t tx_hdr; + wan_event_ctrl_t event_ctrl; + int err = -EINVAL; + + if (WAN_COPY_FROM_USER(&tx_hdr, user_data, sizeof(api_tx_hdr_t))){ + DEBUG_EVENT("%s: Failed to copy data from user space!\n", + card->devname); + return -EFAULT; + } + memset(&event_ctrl, 0, sizeof(wan_event_ctrl_t)); + switch(tx_hdr.api_tx_hdr_event_type){ + case WP_API_EVENT_DTMF: + DEBUG_TEST("%s: %s HW DTMF event!\n", + card->devname, + (tx_hdr.api_tx_hdr_event_mode==WP_API_EVENT_ENABLE)? + "Enable": "Disable"); +#if 1 + if (tx_hdr.api_tx_hdr_event_mode == WP_API_EVENT_ENABLE){ + card->wandev.event_callback.dtmf = wan_aft_api_dtmf; + event_ctrl.type = WAN_EVENT_ENABLE|WAN_EVENT_EC_DTMF; + }else{ + card->wandev.event_callback.dtmf = NULL; + event_ctrl.type = WAN_EVENT_DISABLE|WAN_EVENT_EC_DTMF; + } + err = aft_event_ctrl(chan, &event_ctrl); + return 0; +#else + if (tx_hdr.api_tx_hdr_event_mode == WP_API_EVENT_ENABLE){ + event_ctrl.type = WAN_EVENT_ENABLE|WAN_EVENT_EC_DTMF; + }else{ + event_ctrl.type = WAN_EVENT_DISABLE|WAN_EVENT_EC_DTMF; + } + if (tx_hdr.wp_api_tx_hdr_event_dtmf_type & WP_API_EVENT_DTMF_SOUT){ + event_ctrl.ec_dtmf_port |= WAN_EVENT_DTMF_TYPE_SOUT; + } + if (tx_hdr.wp_api_tx_hdr_event_dtmf_type & WP_API_EVENT_DTMF_ROUT){ + event_ctrl.ec_dtmf_port |= WAN_EVENT_DTMF_TYPE_ROUT; + } + if (tx_hdr.wp_api_tx_hdr_event_channel){ + event_ctrl.ts_map = (1 << tx_hdr.wp_api_tx_hdr_event_channel); + }else{ + if (IS_T1_CARD(card) || IS_FXOFXS_CARD(card)){ + // Convert active_ch bit map to user + event_ctrl.ts_map = chan->time_slot_map << 1; + }else{ + event_ctrl.ts_map = chan->time_slot_map; + } + } + err = aft_event_ctrl(chan, &event_ctrl); +#endif + break; + + case WP_API_EVENT_RXHOOK: + case WP_API_EVENT_RING: + default: + DEBUG_EVENT("%s: Unsupported event type %d!\n", + card->devname, + tx_hdr.u.event.type); + err = -EINVAL; + break; + } + + return err; +} + +static void wan_aft_api_dtmf (void* card_id, wan_event_t *event) +{ + sdla_t *card = (sdla_t*)card_id; + private_area_t *chan = NULL; + netskb_t *new_skb = NULL; + api_rx_hdr_t *rx_hdr; + int i; + + if (event->type & WAN_EVENT_EC_DTMF){ + DEBUG_EVENT("ADBG: %s: Received DTMF Event at AFT API (%d:%c:%s:%s)!\n", + card->devname, + event->channel, + event->digit, + (event->dtmf_port == WAN_EC_CHANNEL_PORT_ROUT)?"ROUT":"SOUT", + (event->dtmf_type == WAN_EC_TONE_PRESENT)?"PRESENT":"STOP"); + }else if (event->type & WAN_EVENT_RM_DTMF){ + DEBUG_EVENT("%s: Received DTMF Event at AFT API (%d:%c)!\n", + card->devname, + event->channel, + event->digit); + } + + for (i=0;iu.aft.num_of_time_slots;i++){ + if (wan_test_bit(i,&card->u.aft.logic_ch_map)){ + unsigned long ts_map; + chan=(private_area_t*)card->u.aft.dev_to_ch_map[i]; + ts_map = chan->time_slot_map; + if (IS_T1_CARD(card) || IS_FXOFXS_CARD(card)){ + /* Convert active_ch bit map to user */ + ts_map = ts_map << 1; + } + if (wan_test_bit(event->channel,&ts_map)){ + break; + } + chan = NULL; + } + } + if (chan == NULL){ + DEBUG_EVENT("%s: Failed to find channel device (channel=%d)!\n", + card->devname, event->channel); + return; + } +#if defined(__LINUX__) + new_skb=wan_skb_alloc(sizeof(api_rx_element_t)); + if (new_skb == NULL) return; + + rx_hdr=(api_rx_hdr_t*)wan_skb_put(new_skb,sizeof(api_rx_element_t)); + memset(rx_hdr,0,sizeof(api_rx_hdr_t)); + + rx_hdr->error_flag = 0; + rx_hdr->event_type = WP_API_EVENT_DTMF; + rx_hdr->wp_api_rx_hdr_event_channel = event->channel; + rx_hdr->wp_api_rx_hdr_event_dtmf_digit = event->digit; + rx_hdr->wp_api_rx_hdr_event_dtmf_type = event->dtmf_type; + rx_hdr->wp_api_rx_hdr_event_dtmf_port = event->dtmf_port; + + new_skb->protocol = htons(PVC_PROT); + new_skb->mac.raw = new_skb->data; + new_skb->dev = chan->common.dev; + new_skb->pkt_type = WAN_PACKET_DATA; + + if (wan_api_rx_dtmf(chan,new_skb) != 0){ + wan_skb_free(new_skb); +DEBUG_EVENT("ADBG> %s: Failed to send DTMF event!\n", card->devname); + }else{ +DEBUG_EVENT("ADBG> %s: Sent up DTMF event!\n", card->devname); + } +#else + DEBUG_EVENT("%s:%s: DTMF Event report is not supported!\n", + card->devname, chan->if_name); + new_skb = NULL; + rx_hdr = NULL; +#endif + return; +} + + +#if 0 +static void wp_tdmv_api_chan_rx_tx(sdla_t *card, + private_area_t *chan, + unsigned char *rxdata, unsigned char *txdata) +{ +#if defined(__LINUX__) + unsigned char *buf; + + if (!card->u.aft.tdmv_api_rx){ + card->u.aft.tdmv_api_rx=wan_skb_alloc(card->u.aft.tdmv_mtu); + if (!card->u.aft.tdmv_api_rx){ + ++chan->if_stats.rx_errors; + goto wp_tdmv_api_rx_tx_chan_skip_rx; + } + } + + if (wan_skb_len(card->u.aft.tdmv_api_rx) > (card->u.aft.tdmv_mtu-chan->mru)){ + /* CRITICAL ERROR: We cannot fit the all timeslots into this + * packet */ + ++chan->if_stats.rx_errors; + goto wp_tdmv_api_rx_tx_chan_skip_rx; + } + + buf=wan_skb_put(card->u.aft.tdmv_api_rx, chan->mru); + memcpy(buf,rxdata,chan->mru); + ++chan->if_stats.rx_dropped; + +wp_tdmv_api_rx_tx_chan_skip_rx: + + if (!card->u.aft.tdmv_api_tx){ + card->u.aft.tdmv_api_tx=wan_skb_dequeue(&card->u.aft.tdmv_api_tx_list); + if (!card->u.aft.tdmv_api_tx){ + /* No tx packet, send idle frames */ + ++chan->if_stats.tx_carrier_errors; + memset(txdata,chan->idle_flag,chan->mtu); + return; + } + } + + if (wan_skb_len(card->u.aft.tdmv_api_tx) < chan->mtu){ + /* CRITICAL ERROR: + * The tx api packet must have info for all + * timeslots */ + memset(txdata,chan->idle_flag,chan->mtu); + ++chan->if_stats.tx_errors; + return; + } + + buf=wan_skb_data(card->u.aft.tdmv_api_tx); + memcpy(txdata,buf,chan->mtu); + wan_skb_pull(card->u.aft.tdmv_api_tx,chan->mtu); + ++chan->if_stats.tx_dropped; + +#endif + return; +} + +/*================================================ + * wp_tdmv_api_rx_tx + * + * + */ + +static void wp_tdmv_api_rx_tx (sdla_t *card, private_area_t *chan) +{ +#if defined(__LINUX__) + chan=(private_area_t*)wan_netif_priv(chan->common.dev); + + if (!card->u.aft.tdmv_api_rx){ + /* CRITICAL ERROR: + * There should be an rx api packet here */ + goto wp_tdmv_api_rx_tx_skip_rx; + } + + if (wan_skb_len(card->u.aft.tdmv_api_rx) != card->u.aft.tdmv_mtu){ + wan_skb_free(card->u.aft.tdmv_api_rx); + card->u.aft.tdmv_api_rx=NULL; + goto wp_tdmv_api_rx_tx_skip_rx; + } + + if (wan_skb_headroom(card->u.aft.tdmv_api_rx) >= sizeof(api_rx_hdr_t)){ + api_rx_hdr_t *rx_hdr= + (api_rx_hdr_t*)skb_push(card->u.aft.tdmv_api_rx, + sizeof(api_rx_hdr_t)); + memset(rx_hdr,0,sizeof(api_rx_hdr_t)); + }else{ + wan_skb_free(card->u.aft.tdmv_api_rx); + card->u.aft.tdmv_api_rx=NULL; + goto wp_tdmv_api_rx_tx_skip_rx; + } + + card->u.aft.tdmv_api_rx->protocol = htons(PVC_PROT); + card->u.aft.tdmv_api_rx->mac.raw = card->u.aft.tdmv_api_rx->data; + card->u.aft.tdmv_api_rx->dev = chan->common.dev; + card->u.aft.tdmv_api_rx->pkt_type = WAN_PACKET_DATA; + + if (wan_api_rx(chan,card->u.aft.tdmv_api_rx) != 0){ + wan_skb_free(card->u.aft.tdmv_api_rx); + } + + card->u.aft.tdmv_api_rx=NULL; + +wp_tdmv_api_rx_tx_skip_rx: + + if (card->u.aft.tdmv_api_tx){ + + if (wan_skb_len(card->u.aft.tdmv_api_tx) != 0){ + /*CRITICAL ERROR: + * Length must be zero, because we pulled + * all timeslots out*/ + } + + wan_skb_free(card->u.aft.tdmv_api_tx); + card->u.aft.tdmv_api_tx=NULL; + + if (WAN_NETIF_QUEUE_STOPPED(chan->common.dev)){ + WAN_NETIF_WAKE_QUEUE(chan->common.dev); + wan_wakeup_api(chan); + } + } +#endif + return; +} +#endif + +#if defined(__LINUX__) +/*============================================= + * aft_set_ss7_force_rx + * + * Force the firmware to pass up a single + * ss7 packet. Otherwise, the ss7 engine + * will wait for the next different packet. + */ +static void aft_set_ss7_force_rx(sdla_t *card, private_area_t *chan) +{ + u32 reg, dma_ram_desc; + + if (wan_test_and_set_bit(0,&chan->ss7_force_rx)){ + DEBUG_TEST("%s: FORCE BUSY RX\n",card->devname); + return; + } + + dma_ram_desc=chan->logic_ch_num*4+AFT_PORT_REG(card,AFT_DMA_CHAIN_RAM_BASE_REG); + card->hw_iface.bus_read_4(card->hw,dma_ram_desc,®); + if (wan_test_bit(AFT_DMACHAIN_SS7_FORCE_RX,®)){ + wan_clear_bit(AFT_DMACHAIN_SS7_FORCE_RX,®); + }else{ + wan_set_bit(AFT_DMACHAIN_SS7_FORCE_RX,®); + } + card->hw_iface.bus_write_4(card->hw,dma_ram_desc,reg); + + DEBUG_TEST("%s: FORCE RX\n",card->devname); +} +#endif + +/*============================================= + * aft_clear_ss7_force_rx + * + * Reset the ss7 force rx logic. + * This must be done before trying to enable + * force rx again. + * Note: That first_time_slot must be cleared LAST. + * Thus the reverse clear order. + */ +static void aft_clear_ss7_force_rx(sdla_t *card, private_area_t *chan) +{ + wan_clear_bit(0,&chan->ss7_force_rx); +} + + +static int aft_event_ctrl(void *chan_ptr, wan_event_ctrl_t *event_ctrl) +{ + sdla_t *card = NULL; + private_area_t *chan = (private_area_t *)chan_ptr; + int err = -EINVAL; + + card = chan->card; + if (event_ctrl->type & WAN_EVENT_EC_DTMF){ + +#if defined(CONFIG_WANPIPE_HWEC) + DEBUG_TEST("%s: Event control request EC_DTMF...\n", + chan->if_name); + err = wanpipe_ec_event_ctrl(card->wandev.ec_dev, card, event_ctrl); +#endif + }else if (chan->card->wandev.fe_iface.event_ctrl){ + + DEBUG_TEST("%s: FE Event control request...\n", + chan->if_name); + err = chan->card->wandev.fe_iface.event_ctrl( + &chan->card->fe, event_ctrl); + }else{ + DEBUG_TEST("%s: Unsupported event control request (%lX)\n", + chan->if_name, event_ctrl->type); + } + + return err; +} + +#ifdef AFT_TDM_API_SUPPORT +static int aft_read_rbs_bits(void *chan_ptr, u32 ch, u8 *rbs_bits) +{ + private_area_t *chan = (private_area_t *)chan_ptr; + wan_smp_flag_t flags; + + if (!chan_ptr){ + return -EINVAL; + } + + chan->card->hw_iface.hw_lock(chan->card->hw,&flags); + *rbs_bits = chan->card->wandev.fe_iface.read_rbsbits( + &chan->card->fe, + chan->logic_ch_num+1, + WAN_TE_RBS_UPDATE); + chan->card->hw_iface.hw_unlock(chan->card->hw,&flags); + + return 0; + +} + +static int aft_write_rbs_bits(void *chan_ptr, u32 ch, u8 rbs_bits) +{ + private_area_t *chan = (private_area_t *)chan_ptr; + wan_smp_flag_t flags; + int err; + + if (!chan_ptr){ + return -EINVAL; + } + + chan->card->hw_iface.hw_lock(chan->card->hw,&flags); + err = chan->card->wandev.fe_iface.set_rbsbits(&chan->card->fe, + chan->logic_ch_num+1, + rbs_bits); + chan->card->hw_iface.hw_unlock(chan->card->hw,&flags); + + return err; +} + + +static int aft_write_hdlc_frame(void *chan_ptr, netskb_t *skb) +{ + private_area_t *chan = (private_area_t *)chan_ptr; + sdla_t *card=chan->card; + wan_smp_flag_t smp_flags; + int err=-EINVAL; + + if (!chan_ptr || !chan->common.dev || !card){ + WAN_ASSERT(1); + return -EINVAL; + } + + if (wan_skb_len(skb) > chan->mtu) { + return -EINVAL; + } + + wan_spin_lock_irq(&card->wandev.lock, &smp_flags); + + if (wan_skb_queue_len(&chan->wp_tx_pending_list) > chan->max_tx_bufs){ + aft_dma_tx(card,chan); + wan_spin_unlock_irq(&card->wandev.lock, &smp_flags); + return -EBUSY; + + } + + wan_skb_unlink(skb); + wan_skb_queue_tail(&chan->wp_tx_pending_list,skb); + aft_dma_tx(card,chan); + + + err=0; + wan_spin_unlock_irq(&card->wandev.lock, &smp_flags); + + + return err; +} +#endif +/****** End ****************************************************************/ diff -Nur linux.org/drivers/net/wan/sdla_aft_te3.c linux-2.6.17/drivers/net/wan/sdla_aft_te3.c --- linux.org/drivers/net/wan/sdla_aft_te3.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/drivers/net/wan/sdla_aft_te3.c 2006-08-30 10:07:16.000000000 +0000 @@ -0,0 +1,5774 @@ +/***************************************************************************** +* sdla_aft_te3.c WANPIPE(tm) AFT Xilinx Hardware Support +* +* Authors: Nenad Corbic +* +* Copyright: (c) 2003 Sangoma Technologies Inc. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version +* 2 of the License, or (at your option) any later version. +* ============================================================================ +* Jan 07, 2003 Nenad Corbic Initial version. +*****************************************************************************/ +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) +# include +# include +# include +# include /* Socket Driver common area */ +# include +# include +# if defined(CONFIG_PRODUCT_WANPIPE_GENERIC) +# include +# endif +# include +#else +# include +# include +# include +# include +# include +# include /* Socket Driver common area */ +# include +# include +# include +# if defined(CONFIG_PRODUCT_WANPIPE_GENERIC) +# include +# endif +# include +#endif + +//#define XILINX_A010 1 + +/****** Defines & Macros ****************************************************/ + +/* Private critical flags */ +enum { + POLL_CRIT = PRIV_CRIT, + CARD_DOWN +}; + +enum { + LINK_DOWN, + DEVICE_DOWN +}; + +enum { + TX_DMA_BUSY, + TX_HANDLER_BUSY, + TX_INTR_PENDING, + TX_DATA_READY, + + RX_HANDLER_BUSY, + RX_DMA_BUSY, + RX_INTR_PENDING, + RX_DATA_READY, + + RX_WTD_SKIP, +}; + +enum { + AFT_FE_CFG_ERR, + AFT_FE_CFG, + AFT_FE_INTR, + AFT_FE_POLL + +}; + +#define MAX_IP_ERRORS 10 + +#define PORT(x) (x == 0 ? "PRIMARY" : "SECONDARY" ) + +#undef DEB_XILINX + +#if 0 +# define AFT_XTEST_DEBUG 1 +#else +# undef AFT_XTEST_DEBUG +#endif + +#if 1 +# define TRUE_FIFO_SIZE 1 +#else +# undef TRUE_FIFO_SIZE +# define HARD_FIFO_CODE 0x01 +#endif + + +#if 0 +#define AFT_T3_SINGLE_DMA_CHAIN 1 +#else +#undef AFT_T3_SINGLE_DMA_CHAIN +#endif + +#define MAX_AFT_DMA_CHAINS 16 +#define MAX_TX_BUF (MAX_AFT_DMA_CHAINS)+1 +#define MAX_RX_BUF ((MAX_AFT_DMA_CHAINS)*4)+1 +#define MAX_RX_SCHAIN_BUF (MAX_RX_BUF)*2 + + +#define AFT_MAX_CHIP_SECURITY_CNT 100 +/* Remove HDLC Address + * 1=Remove Enabled + * 0=Remove Disabled + */ + +static int aft_rx_copyback=1000; + +/******Data Structures*****************************************************/ + +/* This structure is placed in the private data area of the device structure. + * The card structure used to occupy the private area but now the following + * structure will incorporate the card structure along with Protocol specific data + */ + +typedef struct aft_dma_chain +{ + unsigned long init; + u32 dma_addr; + u32 dma_len; + netskb_t *skb; + u32 index; + + u32 dma_descr; + u32 len_align; + u32 reg; + + u8 pkt_error; +}aft_dma_chain_t; + +typedef struct private_area +{ + wanpipe_common_t common; + sdla_t *card; + netdevice_t *dev; + + wan_skb_queue_t wp_tx_free_list; + wan_skb_queue_t wp_tx_pending_list; + wan_skb_queue_t wp_tx_complete_list; + netskb_t *tx_dma_skb; + u8 tx_dma_cnt; + + wan_skb_queue_t wp_rx_free_list; + wan_skb_queue_t wp_rx_complete_list; + + unsigned long time_slot_map; + unsigned char num_of_time_slots; + long logic_ch_num; + + unsigned char hdlc_eng; + unsigned long dma_status; + unsigned char protocol; + unsigned char ignore_modem; + + struct net_device_stats if_stats; + +#if 1 + int tracing_enabled; /* For enabling Tracing */ + unsigned long router_start_time; + unsigned long trace_timeout; + + unsigned char route_status; + unsigned char route_removed; + unsigned long tick_counter; /* For 5s timeout counter */ + unsigned long router_up_time; + + unsigned char mc; /* Mulitcast support on/off */ + unsigned char udp_pkt_src; /* udp packet processing */ + unsigned short timer_int_enabled; + + unsigned char interface_down; + + /* Polling task queue. Each interface + * has its own task queue, which is used + * to defer events from the interrupt */ + wan_taskq_t poll_task; + wan_timer_info_t poll_delay_timer; + + u8 gateway; + u8 true_if_encoding; + + //FIXME: add driver stats as per frame relay! +#endif + +#if defined(__LINUX__) + /* Entry in proc fs per each interface */ + struct proc_dir_entry *dent; +#endif + + unsigned char udp_pkt_data[sizeof(wan_udp_pkt_t)+10]; + atomic_t udp_pkt_len; + + char if_name[WAN_IFNAME_SZ+1]; + + u8 idle_flag; + u16 max_idle_size; + u8 idle_start; + + u8 pkt_error; + u8 rx_fifo_err_cnt; + + int first_time_slot; + + netskb_t *tx_idle_skb; + unsigned char rx_dma; + unsigned char pci_retry; + + unsigned char fifo_size_code; + unsigned char fifo_base_addr; + unsigned char fifo_size; + + int dma_mtu; + + void * prot_ch; + int prot_state; + + wan_trace_t trace_info; + + /* TE3 Specific Dma Chains */ + unsigned char tx_chain_indx,tx_pending_chain_indx; + aft_dma_chain_t tx_dma_chain_table[MAX_AFT_DMA_CHAINS]; + + unsigned char rx_chain_indx, rx_pending_chain_indx; + aft_dma_chain_t rx_dma_chain_table[MAX_AFT_DMA_CHAINS]; + int rx_no_data_cnt; + + unsigned long dma_chain_status; + unsigned long up; + + unsigned char *tx_realign_buf; + unsigned int single_dma_chain; + unsigned int dma_bufs; + +}private_area_t; + +/* Route Status options */ +#define NO_ROUTE 0x00 +#define ADD_ROUTE 0x01 +#define ROUTE_ADDED 0x02 +#define REMOVE_ROUTE 0x03 + +#define WP_WAIT 0 +#define WP_NO_WAIT 1 + +/* variable for keeping track of enabling/disabling FT1 monitor status */ +//static int rCount; + +extern void disable_irq(unsigned int); +extern void enable_irq(unsigned int); + +/**SECTOIN************************************************** + * + * Function Prototypes + * + ***********************************************************/ + +int wp_aft_te3_default_devcfg(sdla_t* card, wandev_conf_t* conf); +int wp_aft_te3_default_ifcfg(sdla_t* card, wanif_conf_t* conf); + +/* WAN link driver entry points. These are called by the WAN router module. */ +static int update (wan_device_t* wandev); +static int new_if (wan_device_t* wandev, netdevice_t* dev, wanif_conf_t* conf); +static int del_if(wan_device_t *wandev, netdevice_t *dev); + +/* Network device interface */ +#if defined(__LINUX__) +static int if_init (netdevice_t* dev); +#endif +static int if_open (netdevice_t* dev); +static int if_close (netdevice_t* dev); +static int if_do_ioctl(netdevice_t *dev, struct ifreq *ifr, int cmd); + +static struct net_device_stats* if_stats (netdevice_t* dev); + +#if defined(__LINUX__) +static int if_send (netskb_t* skb, netdevice_t* dev); +#else +static int if_send(netdevice_t *dev, netskb_t *skb, struct sockaddr *dst,struct rtentry *rt); +#endif + +static void handle_front_end_state(void* card_id); +static void enable_timer(void* card_id); +static void if_tx_timeout (netdevice_t *dev); + +/* Miscellaneous Functions */ +static void port_set_state (sdla_t *card, int); + +static void disable_comm (sdla_t *card); + +/* Interrupt handlers */ +static void wp_aft_te3_isr (sdla_t* card); + +/* Bottom half handlers */ +#if defined(__LINUX__) +static void wp_bh (unsigned long); +#else +static void wp_bh (void*, int); +#endif + +/* Miscellaneous functions */ +static int process_udp_mgmt_pkt(sdla_t* card, netdevice_t* dev, + private_area_t*, + int local_dev); + +static int xilinx_t3_exar_chip_configure(sdla_t *card); +static int xilinx_t3_exar_dev_configure(sdla_t *card, private_area_t *chan); +static void xilinx_t3_exar_dev_unconfigure(sdla_t *card, private_area_t *chan); +static void xilinx_t3_exar_chip_unconfigure(sdla_t *card); +static void xilinx_t3_exar_transparent_config(sdla_t *card,private_area_t *chan); + +static int xilinx_dma_rx(sdla_t *card, private_area_t *chan, int gcur_ptr); +static void xilinx_dev_enable(sdla_t *card, private_area_t *chan); +static void xilinx_dev_close(sdla_t *card, private_area_t *chan); +static void xilinx_dma_tx_complete (sdla_t *card, private_area_t *chan,int wtd); +static void xilinx_dma_rx_complete (sdla_t *card, private_area_t *chan, int wtd); +static int xilinx_init_rx_dev_fifo(sdla_t *card, private_area_t *chan, unsigned char); +static void xilinx_init_tx_dma_descr(sdla_t *card, private_area_t *chan); +static int xilinx_init_tx_dev_fifo(sdla_t *card, private_area_t *chan, unsigned char); +static void xilinx_tx_post_complete (sdla_t *card, private_area_t *chan, netskb_t *skb); +static void xilinx_rx_post_complete (sdla_t *card, private_area_t *chan, + netskb_t *skb, + netskb_t **new_skb, + unsigned char *pkt_error); + + + + +#if 0 +//FIXME: Not used check with M.F. if still needed +static unsigned char read_cpld(sdla_t *card, unsigned short cpld_off); +#endif +static int write_cpld(void *pcard, unsigned short cpld_off,unsigned char cpld_data); + +static int aft_devel_ioctl(sdla_t *card,struct ifreq *ifr); +static int xilinx_write_bios(sdla_t *card, wan_cmd_api_t *api_cmd); +static int xilinx_write(sdla_t *card, wan_cmd_api_t *api_cmd); +static int xilinx_read(sdla_t *card, wan_cmd_api_t *api_cmd); + +static void front_end_interrupt(sdla_t *card, unsigned long reg); +static void enable_data_error_intr(sdla_t *card); +static void disable_data_error_intr(sdla_t *card, unsigned char); + +static void xilinx_tx_fifo_under_recover (sdla_t *card, private_area_t *chan); + +static int xilinx_write_ctrl_hdlc(sdla_t *card, u32 timeslot, u8 reg_off, u32 data); + +static int set_chan_state(sdla_t* card, netdevice_t* dev, int state); + +static int update_comms_stats(sdla_t* card); + +static int protocol_init (sdla_t*card,netdevice_t *dev, + private_area_t *chan, wanif_conf_t* conf); +static int protocol_stop (sdla_t *card, netdevice_t *dev); +static int protocol_start (sdla_t *card, netdevice_t *dev); +static int protocol_shutdown (sdla_t *card, netdevice_t *dev); +static void protocol_recv(sdla_t *card, private_area_t *chan, netskb_t *skb); + +static int aft_alloc_rx_dma_buff(sdla_t *card, private_area_t *chan, int num); +static int aft_init_requeue_free_skb(private_area_t *chan, netskb_t *skb); + +static int write_framer(void *pcard,unsigned short framer_off,unsigned short framer_data); +static unsigned int read_framer(void *pcard,unsigned short framer_off); +#if 0 +//FIXME to be taken out check with M.F. +static void framer_reset(sdla_t *card); +#endif + +static int xilinx_dma_te3_tx (sdla_t *card,private_area_t *chan,netskb_t *skb); +static void aft_tx_dma_chain_handler(unsigned long data); +static void aft_tx_dma_chain_init(private_area_t *chan, aft_dma_chain_t *); +static void aft_rx_dma_chain_init(private_area_t *chan, aft_dma_chain_t *); +static void aft_index_tx_rx_dma_chains(private_area_t *chan); +static void aft_rx_dma_chain_handler(private_area_t *chan, int wtd, int reset); +#if 0 +//FIXME: Currently not used... +static void aft_dma_te3_set_intr(aft_dma_chain_t *dma_chain, private_area_t *chan); +#endif +static void aft_init_tx_rx_dma_descr(private_area_t *chan); +static void aft_pending_tx(sdla_t *card, private_area_t *chan); +static void aft_free_rx_complete_list(private_area_t *chan); +static void aft_list_descriptors(private_area_t *chan); +static void aft_free_rx_descriptors(private_area_t *chan); +static void aft_te3_led_ctrl(sdla_t *card, int color, int led_pos, int on); +static void aft_list_tx_descriptors(private_area_t *chan); +static void aft_free_tx_descriptors(private_area_t *chan); + +#if defined(__LINUX__) +static void aft_port_task (void * card_ptr); +#else +static void aft_port_task (void * card_ptr, int arg); +#endif +static void aft_fe_intr_ctrl(sdla_t *card, int status); +static void __aft_fe_intr_ctrl(sdla_t *card, int status); + + +/* TE1 Control registers */ +//static WRITE_FRONT_END_REG_T write_front_end_reg; +//static READ_FRONT_END_REG_T read_front_end_reg; + +/* Procfs functions */ +static int wan_aft3_get_info(void* pcard, struct seq_file* m, int* stop_cnt); + +/* Function interface between WANPIPE layer and kernel */ +extern wan_iface_t wan_iface; + +static void xilinx_delay(int sec) +{ +#if 0 + unsigned long timeout=SYSTEM_TICKS; + while ((SYSTEM_TICKS-timeout)<(sec*HZ)){ + schedule(); + } +#endif +} + +/**SECTION********************************************************* + * + * Public Functions + * + ******************************************************************/ + +int wp_aft_te3_default_devcfg(sdla_t* card, wandev_conf_t* conf) +{ + conf->config_id = WANCONFIG_AFT_TE3; + conf->u.xilinx.dma_per_ch = MAX_RX_BUF; + conf->u.xilinx.mru = 1500; + return 0; +} + +int wp_aft_te3_default_ifcfg(sdla_t* card, wanif_conf_t* conf) +{ + conf->protocol = WANCONFIG_HDLC; + memcpy(conf->usedby, "WANPIPE", 7); + conf->if_down = 0; + conf->ignore_dcd = WANOPT_NO; + conf->ignore_cts = WANOPT_NO; + conf->hdlc_streaming = WANOPT_NO; + conf->mc = 0; + conf->gateway = 0; + conf->active_ch = ENABLE_ALL_CHANNELS; + + return 0; +} + +/*============================================================================ + * wp_xilinx_init - Cisco HDLC protocol initialization routine. + * + * @card: Wanpipe card pointer + * @conf: User hardware/firmware/general protocol configuration + * pointer. + * + * This routine is called by the main WANPIPE module + * during setup: ROUTER_SETUP ioctl(). + * + * At this point adapter is completely initialized + * and firmware is running. + * o read firmware version (to make sure it's alive) + * o configure adapter + * o initialize protocol-specific fields of the adapter data space. + * + * Return: 0 o.k. + * < 0 failure. + */ + +int wp_aft_te3_init (sdla_t* card, wandev_conf_t* conf) +{ + int err; + + /* Verify configuration ID */ + wan_clear_bit(CARD_DOWN,&card->wandev.critical); + if (card->wandev.config_id != WANCONFIG_AFT_TE3) { + DEBUG_EVENT( "%s: invalid configuration ID %u!\n", + card->devname, card->wandev.config_id); + return -EINVAL; + } + + if (conf == NULL){ + DEBUG_EVENT("%s: Bad configuration structre!\n", + card->devname); + return -EINVAL; + } + +#if defined(WAN_DEBUG_MEM) + DEBUG_EVENT("%s: Total Mem %d\n",__FUNCTION__,wan_atomic_read(&wan_debug_mem)); +#endif + + + /* Obtain hardware configuration parameters */ + card->wandev.clocking = conf->clocking; + card->wandev.ignore_front_end_status = conf->ignore_front_end_status; + card->wandev.ttl = conf->ttl; + card->wandev.interface = conf->interface; + card->wandev.comm_port = conf->comm_port; + card->wandev.udp_port = conf->udp_port; + card->wandev.new_if_cnt = 0; + wan_atomic_set(&card->wandev.if_cnt,0); + card->u.aft.chip_security_cnt=0; + + memcpy(&card->u.xilinx.cfg,&conf->u.xilinx,sizeof(wan_xilinx_conf_t)); + + card->u.xilinx.cfg.dma_per_ch = MAX_RX_BUF; + + /* TE1 Make special hardware initialization for T1/E1 board */ + if (IS_TE3(&conf->fe_cfg)){ + + memcpy(&card->fe.fe_cfg, &conf->fe_cfg, sizeof(sdla_fe_cfg_t)); + sdla_te3_iface_init(&card->wandev.fe_iface); + card->fe.name = card->devname; + card->fe.card = card; + card->fe.write_cpld = write_cpld; +// card->fe.read_cpld = read_cpld; + card->fe.write_framer = write_framer; + card->fe.read_framer = read_framer; + +// card->wandev.write_front_end_reg = write_front_end_reg; +// card->wandev.read_front_end_reg = read_front_end_reg; + card->wandev.fe_enable_timer = enable_timer; + card->wandev.te_link_state = handle_front_end_state; +//ALEX conf->interface = +// IS_T1_CARD(card) ? WANOPT_V35 : WANOPT_RS232; + + if (card->wandev.comm_port == WANOPT_PRI){ + conf->clocking = WANOPT_EXTERNAL; + } + + }else{ + DEBUG_EVENT("%s: Invalid Front-End media type!!\n", + card->devname); + return -EINVAL; + } + + if (card->wandev.ignore_front_end_status == WANOPT_NO){ + DEBUG_EVENT( + "%s: Enabling front end link monitor\n", + card->devname); + }else{ + DEBUG_EVENT( + "%s: Disabling front end link monitor\n", + card->devname); + } + + /* WARNING: After this point the init function + * must return with 0. The following bind + * functions will cause problems if structures + * below are not initialized */ + + card->wandev.update = &update; + card->wandev.new_if = &new_if; + card->wandev.del_if = &del_if; + card->disable_comm = &disable_comm; + +#ifdef WANPIPE_ENABLE_PROC_FILE_HOOKS + /* Proc fs functions hooks */ + card->wandev.get_config_info = &get_config_info; + card->wandev.get_status_info = &get_status_info; + card->wandev.get_dev_config_info= &get_dev_config_info; + card->wandev.get_if_info = &get_if_info; + card->wandev.set_dev_config = &set_dev_config; + card->wandev.set_if_info = &set_if_info; +#endif + card->wandev.get_info = &wan_aft3_get_info; + + /* Setup Port Bps */ + if(card->wandev.clocking) { + card->wandev.bps = conf->bps; + }else{ + card->wandev.bps = 0; + } + + /* For Primary Port 0 */ + card->wandev.mtu = + (conf->mtu >= MIN_WP_PRI_MTU) ? + wp_min(conf->mtu, MAX_WP_PRI_MTU) : DEFAULT_WP_PRI_MTU; + + + if (!card->u.xilinx.cfg.mru){ + card->u.xilinx.cfg.mru = card->wandev.mtu; + } + + + DEBUG_TEST("%s: Set MTU size to %d!\n", + card->devname, card->wandev.mtu); + + card->hw_iface.getcfg(card->hw, SDLA_BASEADDR, &card->u.xilinx.bar); + + xilinx_delay(1); + port_set_state(card,WAN_DISCONNECTED); + aft_te3_led_ctrl(card, WAN_AFT_RED, 0,WAN_AFT_ON); + aft_te3_led_ctrl(card, WAN_AFT_GREEN, 0, WAN_AFT_OFF); + + WAN_TASKQ_INIT((&card->u.aft.port_task),0,aft_port_task,card); + + + err=xilinx_t3_exar_chip_configure(card); + if (err){ + return err; + } + card->isr = &wp_aft_te3_isr; + + xilinx_delay(1); + + /* Set protocol link state to disconnected, + * After seting the state to DISCONNECTED this + * function must return 0 i.e. success */ + + DEBUG_EVENT( "%s: Init Done.\n",card->devname); + return 0; +} + + + + +/**SECTION************************************************************** + * + * WANPIPE Device Driver Entry Points + * + * *********************************************************************/ + + + +/*============================================================================ + * update - Update wanpipe device status & statistics + * + * @wandev: Wanpipe device pointer + * + * This procedure is called when updating the PROC file system. + * It returns various communications statistics. + * + * cat /proc/net/wanrouter/wanpipe# (where #=1,2,3...) + * + * These statistics are accumulated from 3 + * different locations: + * 1) The 'if_stats' recorded for the device. + * 2) Communication error statistics on the adapter. + * 3) Operational statistics on the adapter. + * + * The board level statistics are read during a timer interrupt. + * Note that we read the error and operational statistics + * during consecitive timer ticks so as to minimize the time + * that we are inside the interrupt handler. + * + */ +static int update (wan_device_t* wandev) +{ + sdla_t* card = wandev->private; + netdevice_t* dev; + volatile private_area_t* chan; + + /* sanity checks */ + if((wandev == NULL) || (wandev->private == NULL)) + return -EFAULT; + + if(wandev->state == WAN_UNCONFIGURED) + return -ENODEV; + + if(wan_test_bit(PERI_CRIT, (void*)&card->wandev.critical)) + return -EAGAIN; + + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + if(dev == NULL) + return -ENODEV; + + if((chan=wan_netif_priv(dev)) == NULL) + return -ENODEV; + + if(card->update_comms_stats){ + return -EAGAIN; + } + + DEBUG_TEST("%s: Chain Dma Status=0x%lX, TxCur=%i, TxPend=%i RxCur=%i RxPend=%i\n", + chan->if_name, + chan->dma_chain_status, + chan->tx_chain_indx, + chan->tx_pending_chain_indx, + chan->rx_chain_indx, + chan->rx_pending_chain_indx); + + + update_comms_stats(card); + + return 0; +} + + + +/*============================================================================ + * new_if - Create new logical channel. + * + * &wandev: Wanpipe device pointer + * &dev: Network device pointer + * &conf: User configuration options pointer + * + * This routine is called by the ROUTER_IFNEW ioctl, + * in wanmain.c. The ioctl passes us the user configuration + * options which we use to configure the driver and + * firmware. + * + * This functions main purpose is to allocate the + * private structure for protocol and bind it + * to dev->priv pointer. + * + * Also the dev->init pointer should also be initialized + * to the if_init() function. + * + * Any allocation necessary for the private strucutre + * should be done here, as well as proc/ file initializetion + * for the network interface. + * + * o parse media- and hardware-specific configuration + * o make sure that a new channel can be created + * o allocate resources, if necessary + * o prepare network device structure for registaration. + * o add network interface to the /proc/net/wanrouter + * + * The opposite of this function is del_if() + * + * Return: 0 o.k. + * < 0 failure (channel will not be created) + */ +static int new_if (wan_device_t* wandev, netdevice_t* dev, wanif_conf_t* conf) +{ + sdla_t* card = wandev->private; + private_area_t* chan; + int err = 0; + netskb_t *skb; + + DEBUG_EVENT( "%s: Configuring Interface: %s\n", + card->devname, wan_netif_name(dev)); + + if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)){ + DEBUG_EVENT( "%s: Invalid interface name!\n", + card->devname); + return -EINVAL; + } + + /* allocate and initialize private data */ + chan = wan_malloc(sizeof(private_area_t)); + if(chan == NULL){ + WAN_MEM_ASSERT(card->devname); + return -ENOMEM; + } + memset(chan, 0, sizeof(private_area_t)); + + chan->first_time_slot=-1; + chan->single_dma_chain=0; + +#ifdef AFT_T3_SINGLE_DMA_CHAIN + chan->single_dma_chain=1; +#endif + + strncpy(chan->if_name, wan_netif_name(dev), WAN_IFNAME_SZ); + + chan->card = card; + + wan_skb_queue_init(&chan->wp_tx_free_list); + wan_skb_queue_init(&chan->wp_tx_pending_list); + wan_skb_queue_init(&chan->wp_tx_complete_list); + + wan_skb_queue_init(&chan->wp_rx_free_list); + wan_skb_queue_init(&chan->wp_rx_complete_list); + + wan_trace_info_init(&chan->trace_info,MAX_TRACE_QUEUE); + + /* Initiaize Tx/Rx DMA Chains */ + aft_index_tx_rx_dma_chains(chan); + + /* Initialize the socket binding information + * These hooks are used by the API sockets to + * bind into the network interface */ + + WAN_TASKLET_INIT((&chan->common.bh_task),0,wp_bh,chan); + chan->common.dev = dev; + chan->tracing_enabled = 0; + chan->route_status = NO_ROUTE; + chan->route_removed = 0; + + /* Setup interface as: + * WANPIPE = IP over Protocol (Firmware) + * API = Raw Socket access to Protocol (Firmware) + * BRIDGE = Ethernet over Protocol, no ip info + * BRIDGE_NODE = Ethernet over Protocol, with ip info + */ + if(strcmp(conf->usedby, "WANPIPE") == 0) { + + DEBUG_EVENT( "%s: Running in WANPIPE mode\n", + wandev->name); + chan->common.usedby = WANPIPE; + + /* Option to bring down the interface when + * the link goes down */ + if (conf->if_down){ + wan_set_bit(DYN_OPT_ON,&chan->interface_down); + DEBUG_EVENT( + "%s:%s: Dynamic interface configuration enabled\n", + card->devname,chan->if_name); + } + + if (conf->protocol != WANOPT_NO){ + wan_netif_set_priv(dev,chan); + if ((err=protocol_init(card,dev,chan,conf)) != 0){ + wan_netif_set_priv(dev, chan); + goto new_if_error; + } + + if (conf->ignore_dcd == WANOPT_YES || conf->ignore_cts == WANOPT_YES){ + DEBUG_EVENT( "%s: Ignore modem changes DCD/CTS\n",card->devname); + chan->ignore_modem=1; + }else{ + DEBUG_EVENT( "%s: Restart protocol on modem changes DCD/CTS\n", + card->devname); + } + } + + } else if( strcmp(conf->usedby, "API") == 0) { + chan->common.usedby = API; + DEBUG_EVENT( "%s:%s: Running in API mode\n", + wandev->name,chan->if_name); + wan_reg_api(chan, dev, card->devname); + + }else if (strcmp(conf->usedby, "BRIDGE") == 0) { + chan->common.usedby = BRIDGE; + DEBUG_EVENT( "%s:%s: Running in WANPIPE (BRIDGE) mode.\n", + card->devname,chan->if_name); + + }else if (strcmp(conf->usedby, "BRIDGE_N") == 0) { + chan->common.usedby = BRIDGE_NODE; + DEBUG_EVENT( "%s:%s: Running in WANPIPE (BRIDGE_NODE) mode.\n", + card->devname,chan->if_name); + + }else if (strcmp(conf->usedby, "STACK") == 0) { + chan->common.usedby = STACK; + if (chan->hdlc_eng){ + card->wandev.mtu+=32; + } + DEBUG_EVENT( "%s:%s: Running in Stack mode.\n", + card->devname,chan->if_name); + + + }else{ + DEBUG_EVENT( "%s:%s: Error: Invalid operation mode [WANPIPE|API|BRIDGE|BRIDGE_NODE]\n", + card->devname,chan->if_name); + err=-EINVAL; + goto new_if_error; + } + + xilinx_delay(1); + + chan->hdlc_eng = conf->hdlc_streaming; + + if (!chan->hdlc_eng){ + if (card->wandev.mtu&0x03){ + DEBUG_EVENT("%s:%s: Error, Transparent MTU must be word aligned!\n", + card->devname,chan->if_name); + err = -EINVAL; + goto new_if_error; + } + } + chan->time_slot_map=conf->active_ch; + + err=xilinx_t3_exar_dev_configure(card,chan); + if (err){ + goto new_if_error; + } + + xilinx_delay(1); + + + if (!chan->hdlc_eng){ + unsigned char *buf; + + if (!chan->max_idle_size){ + chan->max_idle_size=card->wandev.mtu; + } + + DEBUG_EVENT("%s:%s: Config for Transparent mode: Idle=%X Len=%u\n", + card->devname,chan->if_name, + chan->idle_flag,chan->max_idle_size); + + chan->idle_flag=0x7E; + + chan->tx_idle_skb = wan_skb_alloc(chan->max_idle_size); + if (!chan->tx_idle_skb){ + err=-ENOMEM; + goto new_if_error; + } + buf=wan_skb_put(chan->tx_idle_skb,chan->max_idle_size); + memset(buf,chan->idle_flag,chan->max_idle_size); + } + + chan->dma_mtu = card->wandev.mtu >= card->u.xilinx.cfg.mru? + card->wandev.mtu:card->u.xilinx.cfg.mru; + + chan->dma_mtu = xilinx_valid_mtu(chan->dma_mtu); + if (!chan->dma_mtu){ + DEBUG_EVENT("%s:%s: Error invalid MTU %i mru %i\n", + card->devname, + chan->if_name, + card->wandev.mtu,card->u.xilinx.cfg.mru); + err= -EINVAL; + goto new_if_error; + } + + chan->dma_bufs=card->u.xilinx.cfg.dma_per_ch; + if (chan->single_dma_chain){ + chan->dma_bufs=MAX_RX_SCHAIN_BUF; + } + + DEBUG_EVENT("%s:%s: Allocating %i dma len=%i Chains=%s\n", + card->devname,chan->if_name, + chan->dma_bufs, + chan->dma_mtu, + chan->single_dma_chain ? "Off":"On"); + + + err=aft_alloc_rx_dma_buff(card, chan, chan->dma_bufs); + if (err){ + goto new_if_error; + } + + /* If gateway option is set, then this interface is the + * default gateway on this system. We must know that information + * in case DYNAMIC interface configuration is enabled. + * + * I.E. If the interface is brought down by the driver, the + * default route will also be removed. Once the interface + * is brought back up, we must know to re-astablish the + * default route. + */ + if ((chan->gateway = conf->gateway) == WANOPT_YES){ + DEBUG_EVENT( "%s: Interface %s is set as a gateway.\n", + card->devname,chan->if_name); + } + + /* Get Multicast Information from the user + * FIXME: This option is not clearly defined + */ + chan->mc = conf->mc; + + + /* The network interface "dev" has been passed as + * an argument from the above layer. We must initialize + * it so it can be registered into the kernel. + * + * The "dev" structure is the link between the kernel + * stack and the wanpipe driver. It contains all + * access hooks that kernel uses to communicate to + * the our driver. + * + * For now, just set the "dev" name to the user + * defined name and initialize: + * dev->if_init : function that will be called + * to further initialize + * dev structure on "ifconfig up" + * + * dev->priv : private structure allocated above + * + */ + +#if 0 + /* Create interface file in proc fs. + * Once the proc file system is created, the new_if() function + * should exit successfuly. + * + * DO NOT place code under this function that can return + * anything else but 0. + */ + err = wanrouter_proc_add_interface(wandev, + &chan->dent, + chan->if_name, + dev); + if (err){ + DEBUG_EVENT( + "%s: can't create /proc/net/router/frmw/%s entry!\n", + card->devname, chan->if_name); + goto new_if_error; + } +#endif + /* Only setup the dev pointer once the new_if function has + * finished successfully. DO NOT place any code below that + * can return an error */ + wan_netif_set_priv(dev,chan); +#if defined(__LINUX__) + dev->init = &if_init; +# ifdef WANPIPE_GENERIC + if_init(dev); +# endif +#else + chan->common.is_netdev = 1; + chan->common.iface.open = &if_open; + chan->common.iface.close = &if_close; + chan->common.iface.output = &if_send; + chan->common.iface.ioctl = &if_do_ioctl; + chan->common.iface.get_stats = &if_stats; + chan->common.iface.tx_timeout = &if_tx_timeout; + if (wan_iface.attach){ + if (!ifunit(wan_netif_name(dev))){ + wan_iface.attach(dev, NULL, chan->common.is_netdev); + } + }else{ + DEBUG_EVENT("%s: Failed to attach network interface %s!\n", + card->devname, wan_netif_name(dev)); + wan_netif_set_priv(dev, NULL); + err = -EINVAL; + goto new_if_error; + } + wan_netif_set_mtu(dev, card->wandev.mtu); +#endif + + /* Increment the number of network interfaces + * configured on this card. + */ + wan_atomic_inc(&card->wandev.if_cnt); + + chan->common.state = WAN_CONNECTING; + + DEBUG_EVENT( "\n"); + + return 0; + +new_if_error: + + while ((skb=wan_skb_dequeue(&chan->wp_tx_free_list)) != NULL){ + wan_skb_free(skb); + } + + while ((skb=wan_skb_dequeue(&chan->wp_rx_free_list)) != NULL){ + wan_skb_free(skb); + } + + WAN_TASKLET_KILL(&chan->common.bh_task); + + if (chan->common.usedby == API){ + wan_unreg_api(chan, card->devname); + } + + if (chan->tx_idle_skb){ + wan_skb_free(chan->tx_idle_skb); + chan->tx_idle_skb=NULL; + } + + wan_free(chan); + + wan_netif_set_priv(dev,NULL); + + return err; +} + +/*============================================================================ + * del_if - Delete logical channel. + * + * @wandev: Wanpipe private device pointer + * @dev: Netowrk interface pointer + * + * This function is called by ROUTER_DELIF ioctl call + * to deallocate the network interface. + * + * The network interface and the private structure are + * about to be deallocated by the upper layer. + * We have to clean and deallocate any allocated memory. + * + * NOTE: DO NOT deallocate dev->priv here! It will be + * done by the upper layer. + * + */ +static int del_if (wan_device_t* wandev, netdevice_t* dev) +{ + private_area_t* chan = wan_netif_priv(dev); + sdla_t* card = chan->card; + netskb_t *skb; + wan_smp_flag_t flags; + + xilinx_t3_exar_dev_unconfigure(card,chan); + + WAN_TASKLET_KILL(&chan->common.bh_task); + + if (chan->common.usedby == API){ + wan_unreg_api(chan, card->devname); + } + + protocol_shutdown(card,dev); + + + wan_spin_lock_irq(&card->wandev.lock,&flags); + + while ((skb=wan_skb_dequeue(&chan->wp_rx_free_list)) != NULL){ + wan_skb_free(skb); + } + + while ((skb=wan_skb_dequeue(&chan->wp_rx_complete_list)) != NULL){ + wan_skb_free(skb); + } + + while ((skb=wan_skb_dequeue(&chan->wp_tx_free_list)) != NULL){ + wan_skb_free(skb); + } + while ((skb=wan_skb_dequeue(&chan->wp_tx_pending_list)) != NULL){ + wan_skb_free(skb); + } + + + if (chan->tx_realign_buf){ + wan_free(chan->tx_realign_buf); + chan->tx_realign_buf=NULL; + } + + wan_spin_unlock_irq(&card->wandev.lock,&flags); + + /* Delete interface name from proc fs. */ +#if 0 + wanrouter_proc_delete_interface(wandev, chan->if_name); +#endif + + /* Decrement the number of network interfaces + * configured on this card. + */ + wan_atomic_dec(&card->wandev.if_cnt); + + DEBUG_SUB_MEM(sizeof(private_area_t)); + return 0; +} + + +/**SECTION*********************************************************** + * + * KERNEL Device Entry Interfaces + * + ********************************************************************/ + + + +/*============================================================================ + * if_init - Initialize Linux network interface. + * + * @dev: Network interface pointer + * + * During "ifconfig up" the upper layer calls this function + * to initialize dev access pointers. Such as transmit, + * stats and header. + * + * It is called only once for each interface, + * during Linux network interface registration. + * + * Returning anything but zero will fail interface + * registration. + */ +#if defined(__LINUX__) +static int if_init (netdevice_t* dev) +{ + private_area_t* chan = wan_netif_priv(dev); + sdla_t* card = chan->card; + wan_device_t* wandev = &card->wandev; +#ifdef WANPIPE_GENERIC + hdlc_device* hdlc; +#endif + + /* Initialize device driver entry points */ + dev->open = &if_open; + dev->stop = &if_close; +#ifdef WANPIPE_GENERIC + hdlc = dev_to_hdlc(dev); + hdlc->xmit = if_send; +#else + dev->hard_start_xmit = &if_send; +#endif + dev->get_stats = &if_stats; +#if defined(LINUX_2_4)||defined(LINUX_2_6) + dev->tx_timeout = &if_tx_timeout; + dev->watchdog_timeo = 2*HZ; +#endif + dev->do_ioctl = if_do_ioctl; + + if (chan->common.usedby == BRIDGE || + chan->common.usedby == BRIDGE_NODE){ + + /* Setup the interface for Bridging */ + int hw_addr=0; + ether_setup(dev); + + /* Use a random number to generate the MAC address */ + memcpy(dev->dev_addr, "\xFE\xFC\x00\x00\x00\x00", 6); + get_random_bytes(&hw_addr, sizeof(hw_addr)); + *(int *)(dev->dev_addr + 2) += hw_addr; + + }else{ + + if (chan->protocol != WANCONFIG_PPP && + chan->protocol != WANCONFIG_CHDLC){ + dev->flags |= IFF_POINTOPOINT; + dev->flags |= IFF_NOARP; + dev->type = ARPHRD_PPP; + dev->mtu = card->wandev.mtu; + dev->hard_header_len = 16; + dev->hard_header = NULL; + dev->rebuild_header = NULL; + dev->addr_len = 0; + } + + if (chan->common.usedby == API){ + dev->mtu = card->wandev.mtu+sizeof(api_tx_hdr_t); + } + + /* Enable Mulitcasting if user selected */ + if (chan->mc == WANOPT_YES){ + dev->flags |= IFF_MULTICAST; + } + + if (chan->true_if_encoding){ + dev->type = ARPHRD_HDLC; /* This breaks the tcpdump */ + }else{ + dev->type = ARPHRD_PPP; + } + } + + /* Initialize hardware parameters */ + dev->irq = wandev->irq; + dev->dma = wandev->dma; + dev->base_addr = wandev->ioport; + card->hw_iface.getcfg(card->hw, SDLA_MEMBASE, &dev->mem_start); + card->hw_iface.getcfg(card->hw, SDLA_MEMEND, &dev->mem_end); + + /* Set transmit buffer queue length + * If too low packets will not be retransmitted + * by stack. + */ + dev->tx_queue_len = 100; + + return 0; +} +#endif + +/*============================================================================ + * if_open - Open network interface. + * + * @dev: Network device pointer + * + * On ifconfig up, this function gets called in order + * to initialize and configure the private area. + * Driver should be configured to send and receive data. + * + * This functions starts a timer that will call + * frmw_config() function. This function must be called + * because the IP addresses could have been changed + * for this interface. + * + * Return 0 if O.k. or errno. + */ +static int if_open (netdevice_t* dev) +{ + private_area_t* chan = wan_netif_priv(dev); + sdla_t* card = chan->card; + wan_smp_flag_t flags; + +#if defined(__LINUX__) + /* Only one open per interface is allowed */ + if (open_dev_check(dev)){ + DEBUG_EVENT("%s: Open dev check failed!\n", + wan_netif_name(dev)); + return -EBUSY; + } +#endif + + /* Initialize the router start time. + * Used by wanpipemon debugger to indicate + * how long has the interface been up */ + wan_getcurrenttime(&chan->router_start_time, NULL); + + WAN_NETIF_START_QUEUE(dev); + + /* If FRONT End is down, it means that the DMA + * is disabled. In this case don't try to + * reset fifo. Let the enable_data_error_intr() + * function do this, after front end has come up */ + + wan_spin_lock_irq(&card->wandev.lock,&flags); + if (card->wandev.state == WAN_CONNECTED){ + DEBUG_TEST("%s: OPEN reseting fifo\n", + wan_netif_name(dev)); + xilinx_init_rx_dev_fifo(card,chan,WP_WAIT); + xilinx_init_tx_dev_fifo(card,chan,WP_WAIT); + xilinx_init_tx_dma_descr(card,chan); + + xilinx_dma_rx(card,chan,-1); + } + + /* Check for transparent HDLC mode */ + if (!chan->hdlc_eng){ + /* The Transparent HDLC engine is + * enabled. The Rx dma has already + * been setup above. Now setup + * TX DMA and enable the HDLC engine */ + + DEBUG_CFG("%s: Transparent Tx Enabled!\n", + wan_netif_name(dev)); + + xilinx_t3_exar_transparent_config(card,chan); + } + + xilinx_dev_enable(card,chan); + + wan_set_bit(0,&chan->up); + wan_spin_unlock_irq(&card->wandev.lock,&flags); + + chan->ignore_modem=0x0F; + + /* Increment the module usage count */ + wanpipe_open(card); + + if (card->wandev.state == WAN_CONNECTED){ + /* If Front End is connected already set interface + * state to Connected too */ + set_chan_state(card, dev, WAN_CONNECTED); + } + + protocol_start(card,dev); + + /* Wait for the front end interrupt + * before enabling the card */ + return 0; +} + +/*============================================================================ + * if_close - Close network interface. + * + * @dev: Network device pointer + * + * On ifconfig down, this function gets called in order + * to cleanup interace private area. + * + * IMPORTANT: + * + * No deallocation or unconfiguration should ever occur in this + * function, because the interface can come back up + * (via ifconfig up). + * + * Furthermore, in dynamic interfacace configuration mode, the + * interface will come up and down to reflect the protocol state. + * + * Any deallocation and cleanup can occur in del_if() + * function. That function is called before the dev interface + * itself is deallocated. + * + * Thus, we should only stop the net queue and decrement + * the wanpipe usage counter via wanpipe_close() function. + */ + +static int if_close (netdevice_t* dev) +{ + private_area_t* chan = wan_netif_priv(dev); + sdla_t* card = chan->card; + wan_smp_flag_t smp_flags; + + wan_clear_bit(0,&chan->up); + + WAN_NETIF_STOP_QUEUE(dev); + +#if defined(LINUX_2_1) + dev->start=0; +#endif + protocol_stop(card,dev); + + chan->common.state = WAN_DISCONNECTED; + + wan_spin_lock_irq(&card->wandev.lock,&smp_flags); + xilinx_dev_close(card,chan); + wan_spin_unlock_irq(&card->wandev.lock,&smp_flags); + + chan->ignore_modem=0x00; + + wanpipe_close(card); + return 0; +} + + +/*============================================================= + * disable_comm - Main shutdown function + * + * @card: Wanpipe device pointer + * + * The command 'wanrouter stop' has been called + * and the whole wanpipe device is going down. + * This is the last function called to disable + * all comunications and deallocate any memory + * that is still allocated. + * + * o Disable communications, turn off interrupts + * o Deallocate memory used, if any + * o Unconfigure TE1 card + */ + +static void disable_comm (sdla_t *card) +{ + wan_smp_flag_t flags; + + /* Unconfiging, only on shutdown */ + if (IS_TE3(&card->fe.fe_cfg)) { + if (card->wandev.fe_iface.unconfig){ + card->wandev.fe_iface.unconfig(&card->fe); + } + } + + wan_spin_lock_irq(&card->wandev.lock,&flags); + + card->isr=NULL; + + /* Disable DMA ENGINE before we perform + * core reset. Otherwise, we will receive + * rx fifo errors on subsequent resetart. */ + disable_data_error_intr(card,DEVICE_DOWN); + + wan_set_bit(CARD_DOWN,&card->wandev.critical); + + wan_spin_unlock_irq(&card->wandev.lock,&flags); + + WP_DELAY(10); + + xilinx_t3_exar_chip_unconfigure(card); + + return; +} + + + +/*============================================================================ + * if_tx_timeout + * + * Kernel networking stack calls this function in case + * the interface has been stopped for TX_TIMEOUT seconds. + * + * This would occur if we lost TX interrupts or the + * card has stopped working for some reason. + * + * Handle transmit timeout event from netif watchdog + */ +static void if_tx_timeout (netdevice_t *dev) +{ + private_area_t* chan = wan_netif_priv(dev); + sdla_t *card = chan->card; + unsigned int cur_dma_ptr; + u32 reg; + wan_smp_flag_t smp_flags; + + /* If our device stays busy for at least 5 seconds then we will + * kick start the device by making dev->tbusy = 0. We expect + * that our device never stays busy more than 5 seconds. So this + * is only used as a last resort. + */ + + ++chan->if_stats.collisions; + + DEBUG_EVENT( "%s: Transmit timed out on %s\n", + card->devname,wan_netif_name(dev)); + +// DEBUG_EVENT("%s: TxStatus=0x%X DMAADDR=0x%lX DMALEN=%i \n", +// chan->if_name, +// chan->dma_status, +// chan->tx_dma_addr, +// chan->tx_dma_len); + + card->hw_iface.bus_read_4(card->hw,AFT_TE3_CRNT_DMA_DESC_ADDR_REG,®); + cur_dma_ptr=get_current_tx_dma_ptr(reg); + + DEBUG_EVENT("%s: Chain TxIntrPend=%i, TxBusy=%i TxCur=%i, TxPend=%i HwCur=%i TxErr=%li\n", + chan->if_name, + wan_test_bit(TX_INTR_PENDING,&chan->dma_chain_status), + wan_test_bit(TX_DMA_BUSY,&chan->dma_status), + chan->tx_chain_indx, + chan->tx_pending_chain_indx, + cur_dma_ptr, + chan->if_stats.tx_fifo_errors); + + /* The Interrupt didn't trigger. + * Clear the interrupt pending flag and + * let watch dog, clean up the tx chain */ + + wan_spin_lock_irq(&card->wandev.lock, &smp_flags); + aft_list_tx_descriptors(chan); + xilinx_tx_fifo_under_recover(card,chan); + wan_spin_unlock_irq(&card->wandev.lock, &smp_flags); + + aft_enable_tx_watchdog(card,AFT_TX_TIMEOUT); +} + + +/*============================================================================ + * if_send - Send a packet on a network interface. + * + * @dev: Network interface pointer + * @skb: Packet obtained from the stack or API + * that should be sent out the port. + * + * o Mark interface as stopped + * (marks start of the transmission) to indicate + * to the stack that the interface is busy. + * + * o Check link state. + * If link is not up, then drop the packet. + * + * o Copy the tx packet into the protocol tx buffers on + * the adapter. + * + * o If tx successful: + * Free the skb buffer and mark interface as running + * and return 0. + * + * o If tx failed, busy: + * Keep interface marked as busy + * Do not free skb buffer + * Enable Tx interrupt (which will tell the stack + * that interace is not busy) + * Return a non-zero value to tell the stack + * that the tx should be retried. + * + * Return: 0 complete (socket buffer must be freed) + * non-0 packet may be re-transmitted + * + */ +#if defined(__LINUX__) +static int if_send (netskb_t* skb, netdevice_t* dev) +#else +static int if_send(netdevice_t *dev, netskb_t *skb, struct sockaddr *dst,struct rtentry *rt) +#endif +{ + + private_area_t *chan = wan_netif_priv(dev); + sdla_t *card = chan->card; + wan_smp_flag_t smp_flags; + + /* Mark interface as busy. The kernel will not + * attempt to send any more packets until we clear + * this condition */ + + if (skb == NULL){ + /* This should never happen. Just a sanity check. + */ + DEBUG_EVENT( "%s: interface %s got kicked!\n", + card->devname, wan_netif_name(dev)); + + WAN_NETIF_WAKE_QUEUE(dev); + return 0; + } + + /* Non 2.4 kernels used to call if_send() + * after TX_TIMEOUT seconds have passed of interface + * being busy. Same as if_tx_timeout() in 2.4 kernels */ +#if defined(LINUX_2_1) + if (dev->tbusy){ + + /* If our device stays busy for at least 5 seconds then we will + * kick start the device by making dev->tbusy = 0. We expect + * that our device never stays busy more than 5 seconds. So this + * is only used as a last resort. + */ + ++chan->if_stats.collisions; + if((SYSTEM_TICKS - chan->tick_counter) < (5 * HZ)) { + return 1; + } + + if_tx_timeout(dev); + } +#endif + + if (chan->common.state != WAN_CONNECTED){ + WAN_NETIF_STOP_QUEUE(dev); + if (WAN_NETIF_CARRIER_OK(dev)){ + DEBUG_EVENT("%s: Critical Error: Carrier on on tx dev down\n", + chan->if_name); + } + wan_netif_set_ticks(dev, SYSTEM_TICKS); + ++chan->if_stats.tx_carrier_errors; + return 1; + + }else if (wan_skb_queue_len(&chan->wp_tx_pending_list)){ + DEBUG_EVENT("%s: Critical Error: Tx Pending List Full\n", + chan->if_name); + WAN_NETIF_STOP_QUEUE(dev); + return 1; + + }else { + int err=0; + + if (chan->common.usedby == API){ + if (sizeof(api_tx_hdr_t) >= wan_skb_len(skb)){ + wan_skb_free(skb); + ++chan->if_stats.tx_errors; + WAN_NETIF_START_QUEUE(dev); + goto if_send_exit_crit; + } + wan_skb_pull(skb,sizeof(api_tx_hdr_t)); + } + + wan_spin_lock_irq(&card->wandev.lock, &smp_flags); + + err=xilinx_dma_te3_tx(card,chan,skb); + + switch (err){ + + case 0: + WAN_NETIF_START_QUEUE(dev); + wan_netif_set_ticks(dev, SYSTEM_TICKS); + err=0; + break; + + case -EBUSY: + WAN_NETIF_STOP_QUEUE(dev); + err=1; + break; + + default: + + /* The packet was dropped + * by the tx chain handler. + * The tx_dropped stat was updated, + * thus all is left for us is + * to start the interface again. + * This SHOULD NEVER happen */ + if (WAN_NET_RATELIMIT()){ + DEBUG_EVENT("%s: TE3 Failed to send: Should never happend!\n", + chan->if_name); + } + WAN_NETIF_START_QUEUE(dev); + wan_netif_set_ticks(dev, SYSTEM_TICKS); + err=0; + } + wan_spin_unlock_irq(&card->wandev.lock, &smp_flags); + + return err; + } + +if_send_exit_crit: + + return 0; +} + + +/*============================================================================ + * if_stats + * + * Used by /proc/net/dev and ifconfig to obtain interface + * statistics. + * + * Return a pointer to struct net_device_stats. + */ +static struct net_device_stats* if_stats (netdevice_t* dev) +{ + private_area_t* chan; + + if ((chan=wan_netif_priv(dev)) == NULL) + return NULL; + +#if 0 +{ + sdla_t *card; + card=chan->card; + + + u8 *base_addr=card->u.xilinx.rx_dma_ptr; + u8 *base_addr_tx=card->u.xilinx.tx_dma_ptr; + u8 *addr=(u8*)wan_dma_get_vaddr(card,base_addr); + u8 *addrtx=(u8*)wan_dma_get_vaddr(card,base_addr_tx); + u8 *addr1, *addr0; + + addr+=chan->logic_ch_num*card->u.xilinx.dma_mtu_off; + + addr0=addr+0*card->u.xilinx.dma_mtu; + addr1=addr+1*card->u.xilinx.dma_mtu; + + DEBUG_EVENT("%s: Buf 0: 0x%02X 1: 0x%02X Txbuf: 0x%02X RxCompList=%i RxFreeList=%i TxList=%i\n", + wan_netif_name(dev),addr0[0],addr1[0],addrtx[0], + wan_skb_queue_len(&chan->wp_rx_complete_list), + wan_skb_queue_len(&chan->wp_rx_free_list), + wan_skb_queue_len(&chan->wp_tx_pending_list)); +} +#endif + + +#if 0 + DEBUG_EVENT("%s: RxCompList=%i RxFreeList=%i TxList=%i\n", + wan_netif_name(dev), + wan_skb_queue_len(&chan->wp_rx_complete_list), + wan_skb_queue_len(&chan->wp_rx_free_list), + wan_skb_queue_len(&chan->wp_tx_pending_list)); +#endif + + + return &chan->if_stats; +} + + + + +/*======================================================================== + * + * if_do_ioctl - Ioctl handler for fr + * + * @dev: Device subject to ioctl + * @ifr: Interface request block from the user + * @cmd: Command that is being issued + * + * This function handles the ioctls that may be issued by the user + * to control or debug the protocol or hardware . + * + * It does both busy and security checks. + * This function is intended to be wrapped by callers who wish to + * add additional ioctl calls of their own. + * + * Used by: SNMP Mibs + * wanpipemon debugger + * + */ +static int if_do_ioctl(netdevice_t *dev, struct ifreq *ifr, int cmd) +{ + private_area_t* chan= (private_area_t*)wan_netif_priv(dev); + sdla_t *card; +#if defined(__LINUX__) + wan_smp_flag_t smp_flags; +#endif + wan_udp_pkt_t *wan_udp_pkt; + int err=0; + + if (!chan){ + return -ENODEV; + } + card=chan->card; + + NET_ADMIN_CHECK(); + + switch(cmd) + { +#if defined(__LINUX__) + case SIOC_WANPIPE_BIND_SK: + if (!ifr){ + err= -EINVAL; + break; + } + + wan_spin_lock_irq(&card->wandev.lock, &smp_flags); + err=wan_bind_api_to_svc(chan,ifr->ifr_data); + chan->if_stats.rx_dropped=0; + wan_spin_unlock_irq(&card->wandev.lock, &smp_flags); + break; + + case SIOC_WANPIPE_UNBIND_SK: + if (!ifr){ + err= -EINVAL; + break; + } + + wan_spin_lock_irq(&card->wandev.lock, &smp_flags); + err=wan_unbind_api_from_svc(chan,ifr->ifr_data); + wan_spin_unlock_irq(&card->wandev.lock, &smp_flags); + + break; + + case SIOC_WANPIPE_CHECK_TX: + case SIOC_ANNEXG_CHECK_TX: + err=0; + break; + + case SIOC_WANPIPE_DEV_STATE: + err = chan->common.state; + break; + + case SIOC_ANNEXG_KICK: + err=0; + break; +#endif + case SIOC_WAN_DEVEL_IOCTL: + err = aft_devel_ioctl(card, ifr); + break; + + case SIOC_AFT_CUSTOMER_ID: + err=0; + break; + + case SIOC_WANPIPE_PIPEMON: + + if (wan_atomic_read(&chan->udp_pkt_len) != 0){ + return -EBUSY; + } + + wan_atomic_set(&chan->udp_pkt_len,MAX_LGTH_UDP_MGNT_PKT); + + /* For performance reasons test the critical + * here before spin lock */ + if (wan_test_bit(0,&card->in_isr)){ + wan_atomic_set(&chan->udp_pkt_len,0); + return -EBUSY; + } + + + wan_udp_pkt=(wan_udp_pkt_t*)chan->udp_pkt_data; + if (WAN_COPY_FROM_USER(&wan_udp_pkt->wan_udp_hdr,ifr->ifr_data,sizeof(wan_udp_hdr_t))){ + wan_atomic_set(&chan->udp_pkt_len,0); + return -EFAULT; + } + + /* We have to check here again because we don't know + * what happened during spin_lock */ + if (wan_test_bit(0,&card->in_isr)) { + DEBUG_EVENT( "%s:%s Pipemon command failed, Driver busy: try again.\n", + card->devname, + wan_netif_name(chan->common.dev)); + wan_atomic_set(&chan->udp_pkt_len,0); + return -EBUSY; + } + + process_udp_mgmt_pkt(card,dev,chan,1); + + /* This area will still be critical to other + * PIPEMON commands due to udp_pkt_len + * thus we can release the irq */ + + if (wan_atomic_read(&chan->udp_pkt_len) > sizeof(wan_udp_pkt_t)){ + DEBUG_EVENT( "%s: Error: Pipemon buf too bit on the way up! %i\n", + card->devname,wan_atomic_read(&chan->udp_pkt_len)); + wan_atomic_set(&chan->udp_pkt_len,0); + return -EINVAL; + } + + if (WAN_COPY_TO_USER(ifr->ifr_data,&wan_udp_pkt->wan_udp_hdr,sizeof(wan_udp_hdr_t))){ + wan_atomic_set(&chan->udp_pkt_len,0); + return -EFAULT; + } + + wan_atomic_set(&chan->udp_pkt_len,0); + return 0; + + default: +#ifndef WANPIPE_GENERIC + DEBUG_EVENT("%s: Command %x not supported!\n", + card->devname,cmd); + return -EOPNOTSUPP; +#else + if (card->wandev.ioctl){ + err = card->wandev.hdlc_ioctl(card, dev, ifr, cmd); + } +#endif + } + + return err; +} + + +/**SECTION********************************************************** + * + * FIRMWARE Specific Interface Functions + * + *******************************************************************/ + + +#define FIFO_RESET_TIMEOUT_CNT 1000 +#define FIFO_RESET_TIMEOUT_US 10 +static int xilinx_init_rx_dev_fifo(sdla_t *card, private_area_t *chan, unsigned char wait) +{ + + u32 reg; + u32 dma_descr; + u8 timeout=1; + u16 i; + unsigned int cur_dma_ptr; + + /* Clean RX DMA fifo */ + if (chan->single_dma_chain){ + card->hw_iface.bus_read_4(card->hw,AFT_TE3_CRNT_DMA_DESC_ADDR_REG,®); + set_current_rx_dma_ptr(®,0); + card->hw_iface.bus_write_4(card->hw,AFT_TE3_CRNT_DMA_DESC_ADDR_REG,reg); + cur_dma_ptr=0; + }else{ + card->hw_iface.bus_read_4(card->hw,AFT_TE3_CRNT_DMA_DESC_ADDR_REG,®); + cur_dma_ptr=get_current_rx_dma_ptr(reg); + } + + + dma_descr=(unsigned long)(cur_dma_ptr<<4) + XILINX_RxDMA_DESCRIPTOR_HI; + reg=0; + wan_set_bit(INIT_DMA_FIFO_CMD_BIT,®); + + DEBUG_TEST("%s: Clearing RX Fifo %s DmaDescr=(0x%X) Reg=(0x%X)\n", + __FUNCTION__,chan->if_name, + dma_descr,reg); + + card->hw_iface.bus_write_4(card->hw,dma_descr,reg); + + if (wait == WP_WAIT){ + for(i=0;ihw_iface.bus_read_4(card->hw,dma_descr,®); + if (wan_test_bit(INIT_DMA_FIFO_CMD_BIT,®)){ + WP_DELAY(FIFO_RESET_TIMEOUT_US); + continue; + } + timeout=0; + break; + } + + if (timeout){ + DEBUG_EVENT("%s:%s: Error: Rx fifo reset timedout %u us\n", + card->devname,chan->if_name,i*FIFO_RESET_TIMEOUT_US); + }else{ + DEBUG_TEST("%s:%s: Rx Fifo Reset Successful\n", + card->devname,chan->if_name); + } + }else{ + timeout=0; + } + + return timeout; +} + +static int xilinx_init_tx_dev_fifo(sdla_t *card, private_area_t *chan, unsigned char wait) +{ + u32 reg; + u32 dma_descr; + u8 timeout=1; + u16 i; + unsigned int cur_dma_ptr; + + if (chan->single_dma_chain){ + card->hw_iface.bus_read_4(card->hw,AFT_TE3_CRNT_DMA_DESC_ADDR_REG,®); + set_current_tx_dma_ptr(®,0); + card->hw_iface.bus_write_4(card->hw,AFT_TE3_CRNT_DMA_DESC_ADDR_REG,reg); + cur_dma_ptr=0; + }else{ + card->hw_iface.bus_read_4(card->hw,AFT_TE3_CRNT_DMA_DESC_ADDR_REG,®); + cur_dma_ptr=get_current_tx_dma_ptr(reg); + } + + /* Clean TX DMA fifo */ + dma_descr=(unsigned long)(cur_dma_ptr<<4) + XILINX_TxDMA_DESCRIPTOR_HI; + reg=0; + wan_set_bit(INIT_DMA_FIFO_CMD_BIT,®); + + DEBUG_TEST("%s: Clearing TX Fifo %s DmaDescr=(0x%X) Reg=(0x%X)\n", + __FUNCTION__,chan->if_name, + dma_descr,reg); + + card->hw_iface.bus_write_4(card->hw,dma_descr,reg); + + if (wait == WP_WAIT){ + for(i=0;ihw_iface.bus_read_4(card->hw,dma_descr,®); + if (wan_test_bit(INIT_DMA_FIFO_CMD_BIT,®)){ + WP_DELAY(FIFO_RESET_TIMEOUT_US); + continue; + } + timeout=0; + break; + } + + if (timeout){ + DEBUG_EVENT("%s:%s: Error: Tx fifo reset timedout %u us\n", + card->devname,chan->if_name,i*FIFO_RESET_TIMEOUT_US); + }else{ + DEBUG_TEST("%s:%s: Tx Fifo Reset Successful\n", + card->devname,chan->if_name); + } + }else{ + timeout=0; + } + + return timeout; +} + + +static void xilinx_dev_enable(sdla_t *card, private_area_t *chan) +{ + u32 reg; + + DEBUG_TEST("%s: Enabling Global Inter Mask !\n",chan->if_name); + + /* Enable Logic Channel Interrupts for DMA and fifo */ + card->hw_iface.bus_read_4(card->hw, + XILINX_GLOBAL_INTER_MASK, ®); + wan_set_bit(chan->logic_ch_num,®); + + card->hw_iface.bus_write_4(card->hw, + XILINX_GLOBAL_INTER_MASK, reg); + + wan_set_bit(chan->logic_ch_num,&card->u.xilinx.active_ch_map); +} + + + +static void xilinx_dev_close(sdla_t *card, private_area_t *chan) +{ + u32 reg; + + DEBUG_CFG("-- Close Xilinx device. --\n"); + + /* Disable Logic Channel Interrupts for DMA and fifo */ + card->hw_iface.bus_read_4(card->hw, + XILINX_GLOBAL_INTER_MASK, ®); + + wan_clear_bit(chan->logic_ch_num,®); + wan_clear_bit(chan->logic_ch_num,&card->u.xilinx.active_ch_map); + + /* We are masking the chan interrupt. + * Lock to make sure that the interrupt is + * not running */ + card->hw_iface.bus_write_4(card->hw, + XILINX_GLOBAL_INTER_MASK, reg); + + + aft_reset_rx_watchdog(card); + aft_reset_tx_watchdog(card); + + reg=0; + + /* Select an HDLC logic channel for configuration */ + card->hw_iface.bus_read_4(card->hw, XILINX_TIMESLOT_HDLC_CHAN_REG, ®); + + reg&=~HDLC_LOGIC_CH_BIT_MASK; + reg&= HDLC_LCH_TIMESLOT_MASK; /* mask not valid bits */ + + card->hw_iface.bus_write_4(card->hw, + XILINX_TIMESLOT_HDLC_CHAN_REG, + (reg|(chan->logic_ch_num&HDLC_LOGIC_CH_BIT_MASK))); + + + reg=0; + xilinx_write_ctrl_hdlc(card, + chan->first_time_slot, + XILINX_HDLC_CONTROL_REG, + reg); + + /* Initialize DMA descriptors and DMA Chains */ + aft_init_tx_rx_dma_descr(chan); + +} + +/**SECTION************************************************************* + * + * TX Handlers + * + **********************************************************************/ + + +/*=============================================== + * xilinx_dma_tx_complete + * + */ +static void xilinx_dma_tx_complete (sdla_t *card, private_area_t *chan, int wtd) +{ + DEBUG_TEST("%s: Tx interrupt wtd=%d\n",chan->if_name,wtd); + + aft_reset_tx_watchdog(card); + + if (!wtd){ + wan_clear_bit(TX_INTR_PENDING,&chan->dma_chain_status); + } + + aft_tx_dma_chain_handler((unsigned long)chan); + + + if (wan_skb_queue_len(&chan->wp_tx_pending_list)){ + aft_pending_tx(card,chan); + } + + + if (WAN_NETIF_QUEUE_STOPPED(chan->common.dev)){ + WAN_NETIF_WAKE_QUEUE(chan->common.dev); +#ifndef CONFIG_PRODUCT_WANPIPE_GENERIC + if (chan->common.usedby == API){ + wan_wakeup_api(chan); + }else if (chan->common.usedby == STACK){ + wanpipe_lip_kick(chan,0); + } +#endif + } + + if (!chan->single_dma_chain){ + aft_enable_tx_watchdog(card,AFT_TX_TIMEOUT); + } + + return; +} + +/*=============================================== + * xilinx_tx_post_complete + * + */ +static void xilinx_tx_post_complete (sdla_t *card, private_area_t *chan, netskb_t *skb) +{ + unsigned long reg = wan_skb_csum(skb); + + if ((wan_test_bit(TxDMA_HI_DMA_GO_READY_BIT,®)) || + (reg & TxDMA_HI_DMA_DATA_LENGTH_MASK) || + (reg&TxDMA_HI_DMA_PCI_ERROR_MASK)){ + + DEBUG_EVENT("%s:%s: Tx DMA Descriptor=0x%lX\n", + card->devname,chan->if_name,reg); + + /* Checking Tx DMA Go bit. Has to be '0' */ + if (wan_test_bit(TxDMA_HI_DMA_GO_READY_BIT,®)){ + DEBUG_TEST("%s:%s: Error: TxDMA Intr: GO bit set on Tx intr\n", + card->devname,chan->if_name); + } + + if (reg & TxDMA_HI_DMA_DATA_LENGTH_MASK){ + DEBUG_TEST("%s:%s: Error: TxDMA Length not equal 0 \n", + card->devname,chan->if_name); + } + + /* Checking Tx DMA PCI error status. Has to be '0's */ + if (reg&TxDMA_HI_DMA_PCI_ERROR_MASK){ + + if (reg & TxDMA_HI_DMA_PCI_ERROR_M_ABRT){ + DEBUG_EVENT("%s:%s: Tx Error: Abort from Master: pci fatal error!\n", + card->devname,chan->if_name); + } + if (reg & TxDMA_HI_DMA_PCI_ERROR_T_ABRT){ + DEBUG_EVENT("%s:%s: Tx Error: Abort from Target: pci fatal error!\n", + card->devname,chan->if_name); + } + if (reg & TxDMA_HI_DMA_PCI_ERROR_DS_TOUT){ + DEBUG_EVENT("%s:%s: Tx Warning: PCI Latency Timeout!\n", + card->devname,chan->if_name); + goto tx_post_ok; + } + if (reg & TxDMA_HI_DMA_PCI_ERROR_RETRY_TOUT){ + DEBUG_EVENT("%s:%s: Tx Error: 'Retry' exceeds maximum (64k): pci fatal error!\n", + card->devname,chan->if_name); + } + } + chan->if_stats.tx_errors++; + goto tx_post_exit; + } + +tx_post_ok: + + chan->if_stats.tx_packets++; + chan->if_stats.tx_bytes+=wan_skb_len(skb); + + /* Indicate that the first tx frame went + * out on the transparent link */ + wan_set_bit(0,&chan->idle_start); + + wan_capture_trace_packet(card, &chan->trace_info, skb, TRC_OUTGOING_FRM); + +tx_post_exit: + + return; +} + + + +/**SECTION************************************************************* + * + * RX Handlers + * + **********************************************************************/ + +/*=============================================== + * xilinx_dma_rx_complete + * + */ +static void xilinx_dma_rx_complete (sdla_t *card, private_area_t *chan, int wtd) +{ + aft_reset_rx_watchdog(card); + aft_rx_dma_chain_handler(chan,wtd,0); +} + +/*=============================================== + * xilinx_rx_post_complete + * + */ +static void xilinx_rx_post_complete (sdla_t *card, private_area_t *chan, + netskb_t *skb, + netskb_t **new_skb, + unsigned char *pkt_error) +{ + + unsigned int len,data_error = 0; + unsigned char *buf; + +#if 0 + wp_rx_element_t *rx_el=(wp_rx_element_t *)&skb->cb[0]; +#else + wp_rx_element_t *rx_el; + rx_el=(wp_rx_element_t *)wan_skb_data(skb); +#endif + DEBUG_RX("%s:%s: RX HI=0x%X LO=0x%X\n DMA=0x%lX", + __FUNCTION__,chan->if_name,rx_el->reg,rx_el->align,rx_el->dma_addr); + +#if 0 + chan->if_stats.rx_errors++; +#endif + + rx_el->align&=RxDMA_LO_ALIGNMENT_BIT_MASK; + *pkt_error=0; + *new_skb=NULL; + + + /* Checking Rx DMA Go bit. Has to be '0' */ + if (wan_test_bit(RxDMA_HI_DMA_GO_READY_BIT,&rx_el->reg)){ + DEBUG_TEST("%s:%s: Error: RxDMA Intr: GO bit set on Rx intr\n", + card->devname,chan->if_name); + chan->if_stats.rx_errors++; + goto rx_comp_error; + } + + /* Checking Rx DMA PCI error status. Has to be '0's */ + if (rx_el->reg&RxDMA_HI_DMA_PCI_ERROR_MASK){ + + if (rx_el->reg & RxDMA_HI_DMA_PCI_ERROR_M_ABRT){ + DEBUG_EVENT("%s:%s: Rx Error: Abort from Master: pci fatal error!\n", + card->devname,chan->if_name); + } + if (rx_el->reg & RxDMA_HI_DMA_PCI_ERROR_T_ABRT){ + DEBUG_EVENT("%s:%s: Rx Error: Abort from Target: pci fatal error!\n", + card->devname,chan->if_name); + } + if (rx_el->reg & RxDMA_HI_DMA_PCI_ERROR_DS_TOUT){ + DEBUG_EVENT("%s:%s: Rx Error: No 'DeviceSelect' from target: pci fatal error!\n", + card->devname,chan->if_name); + } + if (rx_el->reg & RxDMA_HI_DMA_PCI_ERROR_RETRY_TOUT){ + DEBUG_EVENT("%s:%s: Rx Error: 'Retry' exceeds maximum (64k): pci fatal error!\n", + card->devname,chan->if_name); + } + + DEBUG_EVENT("%s: RXDMA PCI ERROR = 0x%x\n",chan->if_name,rx_el->reg); + chan->if_stats.rx_errors++; + goto rx_comp_error; + } + + if (chan->hdlc_eng){ + + /* Checking Rx DMA Frame start bit. (information for api) */ + if (!wan_test_bit(RxDMA_HI_DMA_FRAME_START_BIT,&rx_el->reg)){ + DEBUG_TEST("%s:%s RxDMA Intr: Start flag missing: MTU Mismatch! Reg=0x%X\n", + card->devname,chan->if_name,rx_el->reg); + chan->if_stats.rx_frame_errors++; + goto rx_comp_error; + } + + /* Checking Rx DMA Frame end bit. (information for api) */ + if (!wan_test_bit(RxDMA_HI_DMA_FRAME_END_BIT,&rx_el->reg)){ + DEBUG_TEST("%s:%s: RxDMA Intr: End flag missing: MTU Mismatch! Reg=0x%X\n", + card->devname,chan->if_name,rx_el->reg); + chan->if_stats.rx_frame_errors++; + goto rx_comp_error; + + } else { /* Check CRC error flag only if this is the end of Frame */ + + if (wan_test_bit(RxDMA_HI_DMA_CRC_ERROR_BIT,&rx_el->reg)){ + DEBUG_TEST("%s:%s: RxDMA Intr: CRC Error! Reg=0x%X Len=%i\n", + card->devname,chan->if_name,rx_el->reg, + (rx_el->reg&RxDMA_HI_DMA_DATA_LENGTH_MASK)>>2); + chan->if_stats.rx_frame_errors++; + wan_set_bit(WP_CRC_ERROR_BIT,&rx_el->pkt_error); + data_error = 1; + } + + /* Check if this frame is an abort, if it is + * drop it and continue receiving */ + if (wan_test_bit(RxDMA_HI_DMA_FRAME_ABORT_BIT,&rx_el->reg)){ + DEBUG_TEST("%s:%s: RxDMA Intr: Abort! Reg=0x%X\n", + card->devname,chan->if_name,rx_el->reg); + chan->if_stats.rx_frame_errors++; + wan_set_bit(WP_ABORT_ERROR_BIT,&rx_el->pkt_error); + data_error = 1; + } + + if (chan->common.usedby != API && data_error){ + goto rx_comp_error; + } + } + } + + len=rx_el->reg&RxDMA_HI_DMA_DATA_LENGTH_MASK; + + if (chan->hdlc_eng){ + /* In HDLC mode, calculate rx length based + * on alignment value, received from DMA */ + len=((((chan->dma_mtu>>2)-1)-len)<<2) - (~(rx_el->align)&RxDMA_LO_ALIGNMENT_BIT_MASK); + }else{ + /* In Transparent mode, our RX buffer will always be + * aligned to the 32bit (word) boundary, because + * the RX buffers are all of equal length */ + len=(((card->wandev.mtu>>2)-len)<<2) - (~(0x03)&RxDMA_LO_ALIGNMENT_BIT_MASK); + } + + *pkt_error=rx_el->pkt_error; + + /* After a RX FIFO overflow, we must mark max 7 + * subsequent frames since firmware, cannot + * guarantee the contents of the fifo */ + + if (wan_test_bit(WP_FIFO_ERROR_BIT,&rx_el->pkt_error)){ + if (++chan->rx_fifo_err_cnt >= WP_MAX_FIFO_FRAMES){ + chan->rx_fifo_err_cnt=0; + } + wan_set_bit(WP_FIFO_ERROR_BIT,pkt_error); + }else{ + if (chan->rx_fifo_err_cnt){ + if (++chan->rx_fifo_err_cnt >= WP_MAX_FIFO_FRAMES){ + chan->rx_fifo_err_cnt=0; + } + wan_set_bit(WP_FIFO_ERROR_BIT,pkt_error); + } + } + +// wan_skb_pull(skb, sizeof(wp_rx_element_t)); + + + if (len > aft_rx_copyback){ + /* The rx size is big enough, thus + * send this buffer up the stack + * and allocate another one */ +#if 0 + memset(&skb->cb[0],0,sizeof(wp_rx_element_t)); +#endif + + memset(wan_skb_data(skb),0,sizeof(wp_rx_element_t)); + wan_skb_put(skb,len); + wan_skb_pull(skb, sizeof(wp_rx_element_t)); + *new_skb=skb; + + aft_alloc_rx_dma_buff(card,chan,1); + }else{ + + /* The rx packet is very + * small thus, allocate a new + * buffer and pass it up */ + *new_skb=wan_skb_alloc(len + 20); + if (!*new_skb){ + DEBUG_EVENT("%s:%s: Failed to allocate rx skb pkt (len=%i)!\n", + card->devname,chan->if_name,(len+20)); + chan->if_stats.rx_dropped++; + goto rx_comp_error; + } + + buf=wan_skb_put((*new_skb),len); + memcpy(buf,wan_skb_tail(skb),len); + + aft_init_requeue_free_skb(chan, skb); + } + + return; + +rx_comp_error: + + aft_init_requeue_free_skb(chan, skb); + return; +} + + + +/**SECTION************************************************** + * + * Logic Channel Registration Support and + * Utility funcitons + * + **********************************************************/ + +static int aft_init_requeue_free_skb(private_area_t *chan, netskb_t *skb) +{ + wan_skb_init(skb,16); + wan_skb_trim(skb,0); +#if 0 + memset(&skb->cb[0],0,sizeof(wp_rx_element_t)); +#endif + wan_skb_queue_tail(&chan->wp_rx_free_list,skb); + + return 0; +} + +static int aft_alloc_rx_dma_buff(sdla_t *card, private_area_t *chan, int num) +{ + int i; + netskb_t *skb; + + for (i=0;idma_mtu); + if (!skb){ + DEBUG_EVENT("%s: %s no memory\n", + chan->if_name,__FUNCTION__); + return -ENOMEM; + } + wan_skb_queue_tail(&chan->wp_rx_free_list,skb); + } + + return 0; +} + + +/*============================================================================ + * Enable timer interrupt + */ +static void enable_timer (void* card_id) +{ + sdla_t* card = (sdla_t*)card_id; + + DEBUG_TEST("%s: %s Sdla Polling!\n",__FUNCTION__,card->devname); + +#if defined(__LINUX__) + wan_set_bit(AFT_FE_POLL,&card->u.aft.port_task_cmd); + WAN_TASKQ_SCHEDULE((&card->u.aft.port_task)); +#else + { + wan_smp_flag_t smp_flags, smp_flags1; + wan_spin_lock_irq(&card->wandev.lock, &smp_flags); + card->hw_iface.hw_lock(card->hw,&smp_flags1); + WAN_FECALL(&card->wandev, polling, (&card->fe)); + card->hw_iface.hw_unlock(card->hw,&smp_flags1); + wan_spin_unlock_irq(&card->wandev.lock, &smp_flags); + } +#endif + return; +} + +/**SECTION************************************************** + * + * API Bottom Half Handlers + * + **********************************************************/ + +#if defined(__LINUX__) +static void wp_bh (unsigned long data) +#else +static void wp_bh (void* data, int dummy) +#endif +{ + private_area_t* chan = (private_area_t *)data; + netskb_t *new_skb,*skb; + unsigned char pkt_error; + unsigned long timeout=SYSTEM_TICKS; + + DEBUG_TEST("%s: ------------ BEGIN --------------: %lu\n", + __FUNCTION__,SYSTEM_TICKS); + + if (!wan_test_bit(0,&chan->up)){ + DEBUG_EVENT("%s: wp_bh() chan not up!\n", + chan->if_name); + WAN_TASKLET_END((&chan->common.bh_task)); + return; + } + + + while((skb=wan_skb_dequeue(&chan->wp_rx_complete_list)) != NULL){ + +#if 0 + chan->if_stats.rx_errors++; +#endif + + if (SYSTEM_TICKS-timeout > 3){ + chan->if_stats.rx_errors++; +#if 0 + if (WAN_NET_RATELIMIT()){ + DEBUG_EVENT("%s: BH Squeeze!\n",chan->if_name); + } +#endif + wan_skb_queue_head(&chan->wp_rx_complete_list,skb); + break; + } + + if (chan->common.usedby == API && chan->common.sk == NULL){ + DEBUG_TEST("%s: No sock bound to channel rx dropping!\n", + chan->if_name); + chan->if_stats.rx_dropped++; + aft_init_requeue_free_skb(chan, skb); + + continue; + } + + new_skb=NULL; + pkt_error=0; + + /* The post function will take care + * of the skb and new_skb buffer. + * If new_skb buffer exists, driver + * must pass it up the stack, or free it */ + xilinx_rx_post_complete (chan->card, chan, + skb, + &new_skb, + &pkt_error); + if (new_skb){ + + int len=wan_skb_len(new_skb); + + wan_capture_trace_packet(chan->card, &chan->trace_info, + new_skb,TRC_INCOMING_FRM); + + if (chan->common.usedby == API){ +#if defined(__LINUX__) +# ifndef CONFIG_PRODUCT_WANPIPE_GENERIC + + /* Only for API, we insert packet status + * byte to indicate a packet error. Take + * this byte and put it in the api header */ + + if (wan_skb_headroom(new_skb) >= sizeof(api_rx_hdr_t)){ + api_rx_hdr_t *rx_hdr= + (api_rx_hdr_t*)skb_push(new_skb,sizeof(api_rx_hdr_t)); + memset(rx_hdr,0,sizeof(api_rx_hdr_t)); + rx_hdr->error_flag=pkt_error; + }else{ + DEBUG_EVENT("%s: Error Rx pkt headroom %i < %i\n", + chan->if_name, + wan_skb_headroom(new_skb), + sizeof(api_rx_hdr_t)); + ++chan->if_stats.rx_dropped; + wan_skb_free(new_skb); + continue; + } + + new_skb->protocol = htons(PVC_PROT); + new_skb->mac.raw = new_skb->data; + new_skb->dev = chan->common.dev; + new_skb->pkt_type = WAN_PACKET_DATA; +#if 0 + chan->if_stats.rx_frame_errors++; +#endif + if (wan_api_rx(chan,new_skb) != 0){ + DEBUG_TEST("%s: Error: Rx Socket busy!\n", + chan->if_name); + ++chan->if_stats.rx_dropped; + wan_skb_free(new_skb); + continue; + } +# endif +#endif + + }else if (chan->common.usedby == STACK){ + + if (wanpipe_lip_rx(chan,new_skb) != 0){ + ++chan->if_stats.rx_dropped; + wan_skb_free(new_skb); + continue; + } + + }else{ + protocol_recv(chan->card,chan,new_skb); + } + + chan->if_stats.rx_packets++; + chan->if_stats.rx_bytes+=len; + } + + if (SYSTEM_TICKS-timeout > 3){ + chan->if_stats.rx_errors++; +#if 0 + if (WAN_NET_RATELIMIT()){ + DEBUG_EVENT("%s: BH Squeeze! %i\n", + chan->if_name,SYSTEM_TICKS-timeout); + } +#endif + break; + } + } + + while((skb=wan_skb_dequeue(&chan->wp_tx_complete_list)) != NULL){ + xilinx_tx_post_complete (chan->card,chan,skb); + wan_skb_free(skb); + } + + + WAN_TASKLET_END((&chan->common.bh_task)); +#if 1 + { + int len; + if ((len=wan_skb_queue_len(&chan->wp_rx_complete_list))){ + DEBUG_TEST("%s: Triggering from bh rx=%i\n",chan->if_name,len); + WAN_TASKLET_SCHEDULE((&chan->common.bh_task)); + }else if ((len=wan_skb_queue_len(&chan->wp_tx_complete_list))){ + DEBUG_TEST("%s: Triggering from bh tx=%i\n",chan->if_name,len); + WAN_TASKLET_SCHEDULE((&chan->common.bh_task)); + } + } +#endif + + DEBUG_TEST("%s: ------------ END -----------------: %lu\n", + __FUNCTION__,SYSTEM_TICKS); + + return; +} + +/**SECTION************************************************** + * + * Interrupt Support Functions + * + **********************************************************/ + +static int fifo_error_interrupt(sdla_t *card, u32 reg, u32 tx_status, u32 rx_status) +{ + u32 err=0; + u32 i; + private_area_t *chan; + int num_of_logic_ch; + + + if (card->wandev.state != WAN_CONNECTED){ + DEBUG_EVENT("%s: Warning: Ignoring Error Intr: link disc!\n", + card->devname); + return 0; + } + + if (IS_TE3(&card->fe.fe_cfg)){ + num_of_logic_ch=1; + }else{ + num_of_logic_ch=card->u.xilinx.num_of_time_slots; + } + + if (tx_status != 0){ + for (i=0;iu.xilinx.logic_ch_map)){ + + chan=(private_area_t*)card->u.xilinx.dev_to_ch_map[i]; + if (!chan){ + DEBUG_EVENT("Warning: ignoring tx error intr: no dev!\n"); + continue; + } + + if (!wan_test_bit(0,&chan->up)){ + DEBUG_EVENT("%s: Warning: ignoring tx error intr: dev down 0x%X UP=0x%X!\n", + wan_netif_name(chan->common.dev),chan->common.state,chan->ignore_modem); + continue; + } + + if (chan->common.state != WAN_CONNECTED){ + DEBUG_EVENT("%s: Warning: ignoring tx error intr: dev disc!\n", + wan_netif_name(chan->common.dev)); + continue; + } + + if (!chan->hdlc_eng && !wan_test_bit(0,&chan->idle_start)){ + DEBUG_EVENT("%s: Warning: ignoring tx error intr: dev init error!\n", + wan_netif_name(chan->common.dev)); + if (chan->hdlc_eng){ + xilinx_tx_fifo_under_recover(card,chan); + } + continue; + } + DEBUG_TEST("%s:%s: Warning TX Fifo Error on LogicCh=%li Slot=%i!\n", + card->devname,chan->if_name,chan->logic_ch_num,i); + + xilinx_tx_fifo_under_recover(card,chan); + ++chan->if_stats.tx_fifo_errors; + err=-EINVAL; + } + } + } + + + if (rx_status != 0){ + for (i=0;iu.xilinx.logic_ch_map)){ + chan=(private_area_t*)card->u.xilinx.dev_to_ch_map[i]; + if (!chan){ + continue; + } + + if (!wan_test_bit(0,&chan->up)){ + DEBUG_EVENT("%s: Warning: ignoring rx error intr: dev down 0x%X UP=0x%X!\n", + wan_netif_name(chan->common.dev),chan->common.state,chan->ignore_modem); + continue; + } + + if (chan->common.state != WAN_CONNECTED){ + DEBUG_EVENT("%s: Warning: ignoring rx error intr: dev disc!\n", + wan_netif_name(chan->common.dev)); + continue; + } + + DEBUG_TEST("%s:%s: Warning RX Fifo Error on LCh=%li Slot=%i RxCL=%i RxFL=%i RxDMA=%i\n", + card->devname,chan->if_name,chan->logic_ch_num,i, + wan_skb_queue_len(&chan->wp_rx_complete_list), + wan_skb_queue_len(&chan->wp_rx_free_list), + chan->rx_dma); + + ++chan->if_stats.rx_fifo_errors; +#if 0 +{ + unsigned long dma_descr; + unsigned int reg; + dma_descr=(chan->logic_ch_num<<4) + XILINX_RxDMA_DESCRIPTOR_HI; + card->hw_iface.bus_read_4(card->hw, dma_descr, ®); + DEBUG_EVENT("%s: Hi Descriptor 0x%X\n",chan->if_name,reg); +} +#endif + + wan_set_bit(WP_FIFO_ERROR_BIT, &chan->pkt_error); + + err=-EINVAL; + } + } + } + + return err; +} + + +static void front_end_interrupt(sdla_t *card, unsigned long reg) +{ + /* FIXME: To be filled by ALEX :) */ + DEBUG_TE3("%s: front_end_interrupt!\n",card->devname); + +// wp_debug_func_add(__FUNCTION__); + + if (IS_TE3(&card->fe.fe_cfg)){ + /* FIXME HANDLE T3 Interrupt */ + WAN_FECALL(&card->wandev, isr, (&card->fe)); + }else{ + DEBUG_EVENT("%s: Internal Error (Never should happened)!\n", + card->devname); + } + + handle_front_end_state(card); + return; +} + +/**SECTION*************************************************************** + * + * HARDWARE Interrupt Handlers + * + ***********************************************************************/ + + +/*============================================================================ + * wpfw_isr + * + * Main interrupt service routine. + * Determin the interrupt received and handle it. + * + */ +static void wp_aft_te3_isr (sdla_t* card) +{ + int i; + u32 reg; + u32 dma_tx_reg,dma_rx_reg,rx_fifo_status=0,tx_fifo_status=0; + private_area_t *chan; + int skip_rx_wtd=0; + + if (wan_test_bit(CARD_DOWN,&card->wandev.critical)){ + return; + } + + wan_set_bit(0,&card->in_isr); + + /* -----------------2/6/2003 9:02AM------------------ + * Disable all chip Interrupts (offset 0x040) + * -- "Transmit/Receive DMA Engine" interrupt disable + * -- "FiFo/Line Abort Error" interrupt disable + * --------------------------------------------------*/ + card->hw_iface.bus_read_4(card->hw,XILINX_CHIP_CFG_REG, ®); + + DEBUG_TEST("\n"); + DEBUG_TEST("%s: ISR (0x%X) = 0x%08X \n", + card->devname,XILINX_CHIP_CFG_REG,reg); + + if (wan_test_bit(ENABLE_TE3_FRACTIONAL,®)){ + unsigned int frc_crc; + u32 freg; + + card->hw_iface.bus_read_4(card->hw,TE3_FRACT_ENCAPSULATION_REG, &freg); + frc_crc=get_te3_rx_fract_crc_cnt(freg); + if (frc_crc){ + if (WAN_NET_RATELIMIT()){ + DEBUG_EVENT("%s: TE3 Frac CRC Cnt = %i 0x%08X\n", + card->devname, frc_crc,reg); + } + } + } + + if (wan_test_bit(SECURITY_STATUS_FLAG,®)){ + if (++card->u.aft.chip_security_cnt > + AFT_MAX_CHIP_SECURITY_CNT){ + +#if 1 + if (WAN_NET_RATELIMIT()){ + DEBUG_EVENT("%s: Critical: Chip Security Compromised: Disabling Driver (%i)!\n", + card->devname,card->u.aft.chip_security_cnt); + } + card->u.aft.chip_security_cnt=0; +#else + + DEBUG_EVENT("%s: Critical: Chip Security Compromised: Disabling Driver (%i)!\n", + card->devname,card->u.aft.chip_security_cnt); + DEBUG_EVENT("%s: Please call Sangoma Tech Support (www.sangoma.com)!\n", + card->devname); + + disable_data_error_intr(card,DEVICE_DOWN); + port_set_state(card,WAN_DISCONNECTED); + goto isr_end; +#endif + } + }else{ + card->u.aft.chip_security_cnt=0; + } + + /* Note: If interrupts are received without pending + * flags, it usually indicates that the interrupt + * is being shared. (Check 'cat /proc/interrupts') + */ + + if (wan_test_bit(FRONT_END_INTR_ENABLE_BIT,®)){ + if (wan_test_bit(FRONT_END_INTR_FLAG,®)){ +#if defined(__LINUX__) + wan_set_bit(AFT_FE_INTR,&card->u.aft.port_task_cmd); + WAN_TASKQ_SCHEDULE((&card->u.aft.port_task)); + + __aft_fe_intr_ctrl(card,0); +#else + front_end_interrupt(card,reg); +#endif + } + } + + /* Test Fifo Error Interrupt, + * If set shutdown all interfaces and + * reconfigure */ + if (wan_test_bit(ERROR_INTR_ENABLE_BIT,®)){ + if (wan_test_bit(ERROR_INTR_FLAG,®)){ + + card->hw_iface.bus_read_4(card->hw,XILINX_HDLC_TX_INTR_PENDING_REG,&tx_fifo_status); + card->hw_iface.bus_read_4(card->hw,XILINX_HDLC_RX_INTR_PENDING_REG,&rx_fifo_status); + + rx_fifo_status&=card->u.aft.active_ch_map; + tx_fifo_status&=card->u.aft.active_ch_map; + + fifo_error_interrupt(card,reg,tx_fifo_status,rx_fifo_status); + } + } + + /* -----------------2/6/2003 9:37AM------------------ + * Checking for Interrupt source: + * 1. Receive DMA Engine + * 2. Transmit DMA Engine + * 3. Error conditions. + * --------------------------------------------------*/ + if (wan_test_bit(GLOBAL_INTR_ENABLE_BIT,®) && + (wan_test_bit(DMA_INTR_FLAG,®) || rx_fifo_status)){ + + int num_of_logic_ch; + + if (IS_TE3(&card->fe.fe_cfg)){ + num_of_logic_ch=1; + }else{ + num_of_logic_ch=card->u.xilinx.num_of_time_slots; + } + + /* Receive DMA Engine */ + card->hw_iface.bus_read_4(card->hw, + XILINX_DMA_RX_INTR_PENDING_REG, + &dma_rx_reg); + + + DEBUG_TEST("%s: DMA_RX_INTR_REG(0x%X) = 0x%X ActCH=0x%lX\n", + card->devname, + XILINX_DMA_RX_INTR_PENDING_REG,dma_rx_reg, + card->u.xilinx.active_ch_map); + + dma_rx_reg&=card->u.xilinx.active_ch_map; + + if (dma_rx_reg == 0 && rx_fifo_status == 0){ + goto isr_skb_rx; + } + + for (i=0; iu.xilinx.logic_ch_map)){ + + chan=(private_area_t*)card->u.xilinx.dev_to_ch_map[i]; + if (!chan){ + DEBUG_EVENT("%s: Error: No Dev for Rx logical ch=%i\n", + card->devname,i); + continue; + } + + if (!wan_test_bit(0,&chan->up)){ + DEBUG_EVENT("%s: Error: Dev not up for Rx logical ch=%i\n", + card->devname,i); + continue; + } + +#if 0 + chan->if_stats.rx_frame_errors++; +#endif + + DEBUG_ISR("%s: RX Interrupt pend. \n", + card->devname); + xilinx_dma_rx_complete(card,chan,0); + skip_rx_wtd=1; + } + } +isr_skb_rx: + + /* Transmit DMA Engine */ + + card->hw_iface.bus_read_4(card->hw, + XILINX_DMA_TX_INTR_PENDING_REG, + &dma_tx_reg); + + dma_tx_reg&=card->u.xilinx.active_ch_map; + + DEBUG_TEST("%s: DMA_TX_INTR_REG(0x%X) = 0x%X, ChMap=0x%lX NumofCh=%i\n", + card->devname, + XILINX_DMA_TX_INTR_PENDING_REG, + dma_tx_reg, + card->u.xilinx.active_ch_map, + num_of_logic_ch); + + if (dma_tx_reg == 0){ + goto isr_skb_tx; + } + + for (i=0; iu.xilinx.logic_ch_map)){ + chan=(private_area_t*)card->u.xilinx.dev_to_ch_map[i]; + if (!chan){ + DEBUG_EVENT("%s: Error: No Dev for Tx logical ch=%i\n", + card->devname,i); + continue; + } + + if (!wan_test_bit(0,&chan->up)){ + DEBUG_EVENT("%s: Error: Dev not up for Tx logical ch=%i\n", + card->devname,i); + continue; + } + + + DEBUG_TEST("---- TX Interrupt pend. --\n"); + xilinx_dma_tx_complete(card,chan,0); + + }else{ + DEBUG_EVENT("Failed Testing for Tx Timeslot %i TxReg=0x%X ChMap=0x%lX\n",i, + dma_tx_reg,card->u.xilinx.logic_ch_map); + } + } + } + +isr_skb_tx: + + DEBUG_ISR("---- ISR SKB TX end.-------------------\n"); + + if (wan_test_bit(AFT_TE3_TX_WDT_INTR_PND,®)){ + aft_reset_tx_watchdog(card); + chan=(private_area_t*)card->u.xilinx.dev_to_ch_map[0]; + if (chan && wan_test_bit(0,&chan->up)){ +#if 0 + ++chan->if_stats.tx_dropped; +#endif + xilinx_dma_tx_complete (card,chan,1); + } + DEBUG_TEST("%s: Tx WatchDog Expired!\n",card->devname); + aft_reset_tx_watchdog(card); + } + + if (wan_test_bit(AFT_TE3_RX_WDT_INTR_PND,®)){ + aft_reset_rx_watchdog(card); + chan=(private_area_t*)card->u.xilinx.dev_to_ch_map[0]; + if (!skip_rx_wtd && chan && wan_test_bit(0,&chan->up)){ +#if 0 + chan->if_stats.rx_dropped++; +#endif + xilinx_dma_rx_complete (card,chan,1); + }else{ + if (chan){ + DEBUG_TEST("%s: Skipping Rx WTD Flags=%d\n", + chan->if_name,wan_test_bit(0,&chan->up)); + } + aft_reset_rx_watchdog(card); + aft_enable_rx_watchdog(card,AFT_MAX_WTD_TIMEOUT); + } + + DEBUG_TEST("%s: Rx WatchDog Expired %p!\n", + card->devname,chan); + } + + + /* -----------------2/6/2003 10:36AM----------------- + * Finish of the interupt handler + * --------------------------------------------------*/ +#if 0 +isr_end: +#endif + DEBUG_ISR("---- ISR end.-------------------\n"); + wan_clear_bit(0,&card->in_isr); + return; +} + + + +/**SECTION*********************************************************** + * + * WANPIPE Debugging Interfaces + * + ********************************************************************/ + + + +/*============================================================================= + * process_udp_mgmt_pkt + * + * Process all "wanpipemon" debugger commands. This function + * performs all debugging tasks: + * + * Line Tracing + * Line/Hardware Statistics + * Protocol Statistics + * + * "wanpipemon" utility is a user-space program that + * is used to debug the WANPIPE product. + * + */ +#if 1 +static int process_udp_mgmt_pkt(sdla_t* card, netdevice_t* dev, + private_area_t* chan, int local_dev ) +{ + unsigned short buffer_length; + wan_udp_pkt_t *wan_udp_pkt; + wan_trace_t *trace_info=NULL; + + wan_udp_pkt = (wan_udp_pkt_t *)chan->udp_pkt_data; + + if (wan_atomic_read(&chan->udp_pkt_len) == 0){ + return -ENODEV; + } + + trace_info=&chan->trace_info; + wan_udp_pkt = (wan_udp_pkt_t *)chan->udp_pkt_data; + + { + + netskb_t *skb; + + wan_udp_pkt->wan_udp_opp_flag = 0; + + switch(wan_udp_pkt->wan_udp_command) { + + case READ_CONFIGURATION: + case READ_CODE_VERSION: + wan_udp_pkt->wan_udp_return_code = 0; + wan_udp_pkt->wan_udp_data_len=0; + break; + + + case ENABLE_TRACING: + + wan_udp_pkt->wan_udp_return_code = WAN_CMD_OK; + wan_udp_pkt->wan_udp_data_len = 0; + + if (!wan_test_bit(0,&trace_info->tracing_enabled)){ + + trace_info->trace_timeout = SYSTEM_TICKS; + + wan_trace_purge(trace_info); + + if (wan_udp_pkt->wan_udp_data[0] == 0){ + wan_clear_bit(1,&trace_info->tracing_enabled); + DEBUG_UDP("%s: ADSL L3 trace enabled!\n", + card->devname); + }else if (wan_udp_pkt->wan_udp_data[0] == 1){ + wan_clear_bit(2,&trace_info->tracing_enabled); + wan_set_bit(1,&trace_info->tracing_enabled); + DEBUG_UDP("%s: ADSL L2 trace enabled!\n", + card->devname); + }else{ + wan_clear_bit(1,&trace_info->tracing_enabled); + wan_set_bit(2,&trace_info->tracing_enabled); + DEBUG_UDP("%s: ADSL L1 trace enabled!\n", + card->devname); + } + wan_set_bit (0,&trace_info->tracing_enabled); + + }else{ + DEBUG_EVENT("%s: Error: ATM trace running!\n", + card->devname); + wan_udp_pkt->wan_udp_return_code = 2; + } + + break; + + case DISABLE_TRACING: + + wan_udp_pkt->wan_udp_return_code = WAN_CMD_OK; + + if(wan_test_bit(0,&trace_info->tracing_enabled)) { + + wan_clear_bit(0,&trace_info->tracing_enabled); + wan_clear_bit(1,&trace_info->tracing_enabled); + wan_clear_bit(2,&trace_info->tracing_enabled); + + wan_trace_purge(trace_info); + + DEBUG_UDP("%s: Disabling ADSL trace\n", + card->devname); + + }else{ + /* set return code to line trace already + disabled */ + wan_udp_pkt->wan_udp_return_code = 1; + } + + break; + + case GET_TRACE_INFO: + + if(wan_test_bit(0,&trace_info->tracing_enabled)){ + trace_info->trace_timeout = SYSTEM_TICKS; + }else{ + DEBUG_EVENT("%s: Error ATM trace not enabled\n", + card->devname); + /* set return code */ + wan_udp_pkt->wan_udp_return_code = 1; + break; + } + + buffer_length = 0; + wan_udp_pkt->wan_udp_atm_num_frames = 0; + wan_udp_pkt->wan_udp_atm_ismoredata = 0; + +#if defined(__FreeBSD__) || defined(__OpenBSD__) + while (wan_skb_queue_len(&trace_info->trace_queue)){ + WAN_IFQ_POLL(&trace_info->trace_queue, skb); + if (skb == NULL){ + DEBUG_EVENT("%s: No more trace packets in trace queue!\n", + card->devname); + break; + } + if ((WAN_MAX_DATA_SIZE - buffer_length) < skb->m_pkthdr.len){ + /* indicate there are more frames on board & exit */ + wan_udp_pkt->wan_udp_atm_ismoredata = 0x01; + break; + } + + m_copydata(skb, + 0, + skb->m_pkthdr.len, + &wan_udp_pkt->wan_udp_data[buffer_length]); + buffer_length += skb->m_pkthdr.len; + WAN_IFQ_DEQUEUE(&trace_info->trace_queue, skb); + if (skb){ + wan_skb_free(skb); + } + wan_udp_pkt->wan_udp_atm_num_frames++; + } +#elif defined(__LINUX__) + while ((skb=skb_dequeue(&trace_info->trace_queue)) != NULL){ + + if((MAX_TRACE_BUFFER - buffer_length) < wan_skb_len(skb)){ + /* indicate there are more frames on board & exit */ + wan_udp_pkt->wan_udp_atm_ismoredata = 0x01; + if (buffer_length != 0){ + wan_skb_queue_head(&trace_info->trace_queue, skb); + }else{ + /* If rx buffer length is greater than the + * whole udp buffer copy only the trace + * header and drop the trace packet */ + + memcpy(&wan_udp_pkt->wan_udp_atm_data[buffer_length], + wan_skb_data(skb), + sizeof(wan_trace_pkt_t)); + + buffer_length = sizeof(wan_trace_pkt_t); + wan_udp_pkt->wan_udp_atm_num_frames++; + wan_skb_free(skb); + } + break; + } + + memcpy(&wan_udp_pkt->wan_udp_atm_data[buffer_length], + wan_skb_data(skb), + wan_skb_len(skb)); + + buffer_length += wan_skb_len(skb); + wan_skb_free(skb); + wan_udp_pkt->wan_udp_atm_num_frames++; + } +#endif + /* set the data length and return code */ + wan_udp_pkt->wan_udp_data_len = buffer_length; + wan_udp_pkt->wan_udp_return_code = WAN_CMD_OK; + break; + + case ROUTER_UP_TIME: + wan_getcurrenttime( &chan->router_up_time, NULL ); + chan->router_up_time -= chan->router_start_time; + *(unsigned long *)&wan_udp_pkt->wan_udp_data = + chan->router_up_time; + wan_udp_pkt->wan_udp_data_len = sizeof(unsigned long); + wan_udp_pkt->wan_udp_return_code = 0; + break; + + case WAN_GET_MEDIA_TYPE: + case WAN_FE_GET_STAT: + case WAN_FE_SET_LB_MODE: + case WAN_FE_FLUSH_PMON: + case WAN_FE_GET_CFG: + + if (IS_TE3(&card->fe.fe_cfg)){ + WAN_FECALL(&card->wandev, process_udp, + (&card->fe, + &wan_udp_pkt->wan_udp_cmd, + &wan_udp_pkt->wan_udp_data[0])); + }else{ + wan_udp_pkt->wan_udp_return_code = WAN_UDP_INVALID_CMD; + } + break; + + + + case WAN_GET_PROTOCOL: + wan_udp_pkt->wan_udp_aft_num_frames = card->wandev.config_id; + wan_udp_pkt->wan_udp_return_code = CMD_OK; + wan_udp_pkt->wan_udp_data_len = 1; + break; + + case WAN_GET_PLATFORM: + wan_udp_pkt->wan_udp_data[0] = WAN_PLATFORM_ID; + wan_udp_pkt->wan_udp_return_code = CMD_OK; + wan_udp_pkt->wan_udp_data_len = 1; + break; + + default: + wan_udp_pkt->wan_udp_data_len = 0; + wan_udp_pkt->wan_udp_return_code = 0xCD; + + if (WAN_NET_RATELIMIT()){ + DEBUG_EVENT( + "%s: Warning, Illegal UDP command attempted from network: %x\n", + card->devname,wan_udp_pkt->wan_udp_command); + } + break; + } /* end of switch */ + } /* end of else */ + + /* Fill UDP TTL */ + wan_udp_pkt->wan_ip_ttl= card->wandev.ttl; + + wan_udp_pkt->wan_udp_request_reply = UDPMGMT_REPLY; + return 1; + +} +#endif + + + +/**SECTION************************************************************* + * + * TASK Functions and Triggers + * + **********************************************************************/ + + +/*============================================================================ + * port_set_state + * + * Set PORT state. + * + */ +static void port_set_state (sdla_t *card, int state) +{ + struct wan_dev_le *devle; + netdevice_t *dev; + + if (card->wandev.state != state) + { +#if 0 + switch (state) + { + case WAN_CONNECTED: + DEBUG_EVENT( "%s: Link connected!\n", + card->devname); + break; + + case WAN_CONNECTING: + DEBUG_EVENT( "%s: Link connecting...\n", + card->devname); + break; + + case WAN_DISCONNECTED: + DEBUG_EVENT( "%s: Link disconnected!\n", + card->devname); + break; + } +#endif + card->wandev.state = state; + WAN_LIST_FOREACH(devle, &card->wandev.dev_head, dev_link){ + dev = WAN_DEVLE2DEV(devle); + if (!dev) continue; + set_chan_state(card, dev, state); + } + } +} + +/*============================================================ + * handle_front_end_state + * + * Front end state indicates the physical medium that + * the Z80 backend connects to. + * + * S514-1/2/3: V32/RS232/FT1 Front End + * Front end state is determined via + * Modem/Status. + * S514-4/5/7/8: 56K/T1/E1 Front End + * Front end state is determined via + * link status interrupt received + * from the front end hardware. + * + * If the front end state handler is enabed by the + * user. The interface state will follow the + * front end state. I.E. If the front end goes down + * the protocol and interface will be declared down. + * + * If the front end state is UP, then the interface + * and protocol will be up ONLY if the protocol is + * also UP. + * + * Therefore, we must have three state variables + * 1. Front End State (card->wandev.front_end_status) + * 2. Protocol State (card->wandev.state) + * 3. Interface State (dev->flags & IFF_UP) + * + */ + +static void handle_front_end_state(void *card_id) +{ + sdla_t *card = (sdla_t*)card_id; + unsigned char status; + + if (card->wandev.ignore_front_end_status == WANOPT_YES){ + return; + } + + WAN_FECALL(&card->wandev, get_fe_status, (&card->fe, &status)); + if (status == FE_CONNECTED){ + if (card->wandev.state != WAN_CONNECTED){ + port_set_state(card,WAN_CONNECTED); + enable_data_error_intr(card); + aft_te3_led_ctrl(card, WAN_AFT_RED, 0,WAN_AFT_OFF); + aft_te3_led_ctrl(card, WAN_AFT_GREEN, 0, WAN_AFT_ON); + card->u.xilinx.state_change_exit_isr=1; + }else{ + } + }else{ + if (card->wandev.state != WAN_DISCONNECTED){ + port_set_state(card,WAN_DISCONNECTED); + disable_data_error_intr(card,LINK_DOWN); + aft_te3_led_ctrl(card, WAN_AFT_RED, 0,WAN_AFT_ON); + aft_te3_led_ctrl(card, WAN_AFT_GREEN, 0, WAN_AFT_OFF); + card->u.xilinx.state_change_exit_isr=1; + } + } +} + +#if 0 +static unsigned char read_cpld(sdla_t *card, unsigned short cpld_off) +{ + + u16 org_off; + u8 tmp; + + cpld_off &= ~BIT_DEV_ADDR_CLEAR; + cpld_off |= BIT_DEV_ADDR_CPLD; + + /*ALEX: Save the current address. */ + card->hw_iface.bus_read_2(card->hw, + XILINX_MCPU_INTERFACE_ADDR, + &org_off); + card->hw_iface.bus_write_2(card->hw, + XILINX_MCPU_INTERFACE_ADDR, + cpld_off); + + card->hw_iface.bus_read_1(card->hw,XILINX_MCPU_INTERFACE, &tmp); + + /*ALEX: Restore original address */ + card->hw_iface.bus_write_2(card->hw, + XILINX_MCPU_INTERFACE_ADDR, + org_off); + return tmp; + + +} +#endif + +static int write_cpld(void *pcard, unsigned short off,unsigned char data) +{ + sdla_t *card = (sdla_t*)pcard; + u16 org_off; + + off &= ~BIT_DEV_ADDR_CLEAR; + off |= BIT_DEV_ADDR_CPLD; + + /*ALEX: Save the current original address */ + card->hw_iface.bus_read_2(card->hw, + XILINX_MCPU_INTERFACE_ADDR, + &org_off); + + /* This delay is required to avoid bridge optimization + * (combining two writes together)*/ + WP_DELAY(5); + + card->hw_iface.bus_write_2(card->hw, + XILINX_MCPU_INTERFACE_ADDR, + off); + + /* This delay is required to avoid bridge optimization + * (combining two writes together)*/ + WP_DELAY(5); + + card->hw_iface.bus_write_1(card->hw, + XILINX_MCPU_INTERFACE, + data); + /*ALEX: Restore the original address */ + card->hw_iface.bus_write_2(card->hw, + XILINX_MCPU_INTERFACE_ADDR, + org_off); + return 0; +} + +#if 0 +static unsigned char write_front_end_reg (void* card1, unsigned short off, unsigned char value) +{ + sdla_t* card = (sdla_t*)card1; + + off &= ~BIT_DEV_ADDR_CLEAR; + card->hw_iface.bus_write_2(card->hw,XILINX_MCPU_INTERFACE_ADDR, off); + /* NC: Mar 25 2004 + * This delays are required to avoid bridge optimization + * (combining two writes together) + */ + WP_DELAY(5); + card->hw_iface.bus_write_1(card->hw,XILINX_MCPU_INTERFACE, value); + WP_DELAY(5); + + return 0; +} + +/*============================================================================ + * Read TE1/56K Front end registers + */ +static unsigned char read_front_end_reg (void* card1, unsigned short off) +{ + sdla_t* card = (sdla_t*)card1; + u8 tmp; + + off &= ~BIT_DEV_ADDR_CLEAR; + card->hw_iface.bus_write_2(card->hw, XILINX_MCPU_INTERFACE_ADDR, off); + card->hw_iface.bus_read_1(card->hw,XILINX_MCPU_INTERFACE, &tmp); + WP_DELAY(5); + + return tmp; +} +#endif + +static int xilinx_read(sdla_t *card, wan_cmd_api_t *api_cmd) +{ + + if (api_cmd->offset <= 0x3C){ + card->hw_iface.pci_read_config_dword(card->hw, + api_cmd->offset, + (u32*)&api_cmd->data[0]); + api_cmd->len=4; + + }else{ + card->hw_iface.peek(card->hw, api_cmd->offset, &api_cmd->data[0], api_cmd->len); + } + +#ifdef DEB_XILINX + DEBUG_EVENT("%s: Reading Bar%i Offset=0x%X Len=%i\n", + card->devname,api_cmd->bar,api_cmd->offset,api_cmd->len); +#endif + + return 0; +} + +static int xilinx_write(sdla_t *card, wan_cmd_api_t *api_cmd) +{ + +#ifdef DEB_XILINX + DEBUG_EVENT("%s: Writting Bar%i Offset=0x%X Len=%i\n", + card->devname, + api_cmd->bar,api_cmd->offset,api_cmd->len); +#endif + +#if 0 + card->hw_iface.poke(card->hw, api_cmd->offset, &api_cmd->data[0], api_cmd->len); +#endif + if (api_cmd->len == 1){ + card->hw_iface.bus_write_1( + card->hw, + api_cmd->offset, + (u8)api_cmd->data[0]); + }else if (api_cmd->len == 2){ + card->hw_iface.bus_write_2( + card->hw, + api_cmd->offset, + *(u16*)&api_cmd->data[0]); + }else if (api_cmd->len == 4){ + card->hw_iface.bus_write_4( + card->hw, + api_cmd->offset, + *(u32*)&api_cmd->data[0]); + }else{ + card->hw_iface.poke( + card->hw, + api_cmd->offset, + &api_cmd->data[0], + api_cmd->len); + } + + return 0; +} + +static int xilinx_write_bios(sdla_t *card, wan_cmd_api_t *api_cmd) +{ +#ifdef DEB_XILINX + DEBUG_EVENT("Setting PCI 0x%X=0x%08lX 0x3C=0x%08X\n", + (card->wandev.S514_cpu_no[0] == SDLA_CPU_A) ? 0x10 : 0x14, + card->u.xilinx.bar,card->wandev.irq); +#endif + card->hw_iface.pci_write_config_dword(card->hw, + (card->wandev.S514_cpu_no[0] == SDLA_CPU_A) ? 0x10 : 0x14, + card->u.xilinx.bar); + card->hw_iface.pci_write_config_dword(card->hw, 0x3C, card->wandev.irq); + card->hw_iface.pci_write_config_dword(card->hw, 0x0C, 0x0000ff00); + + return 0; +} + +static int aft_devel_ioctl(sdla_t *card,struct ifreq *ifr) +{ + wan_cmd_api_t api_cmd; + int err; + + if (!ifr || !ifr->ifr_data){ + DEBUG_EVENT("%s: Error: No ifr or ifr_data\n",__FUNCTION__); + return -EINVAL; + } + + if (WAN_COPY_FROM_USER(&api_cmd,ifr->ifr_data,sizeof(wan_cmd_api_t))){ + return -EFAULT; + } + + switch(api_cmd.cmd){ +#if defined(__LINUX__) + case SDLA_HDLC_READ_REG: +#endif + case SIOC_WAN_READ_REG: + err=xilinx_read(card, &api_cmd); + break; + +#if defined(__LINUX__) + case SDLA_HDLC_WRITE_REG: +#endif + case SIOC_WAN_WRITE_REG: + err=xilinx_write(card, &api_cmd); + break; + +#if defined(__LINUX__) + case SDLA_HDLC_SET_PCI_BIOS: +#endif + case SIOC_WAN_SET_PCI_BIOS: + err=xilinx_write_bios(card, &api_cmd); + break; + } + + if (WAN_COPY_TO_USER(ifr->ifr_data,&api_cmd,sizeof(wan_cmd_api_t))){ + return -EFAULT; + } + return 0; +} + +/*========================================= + * enable_data_error_intr + * + * Description: + * + * Run only after the front end comes + * up from down state. + * + * Clean the DMA Tx/Rx pending interrupts. + * (Ignore since we will reconfigure + * all dma descriptors. DMA controler + * was already disabled on link down) + * + * For all channels clean Tx/Rx Fifo + * + * Enable DMA controler + * (This starts the fifo cleaning + * process) + * + * For all channels reprogram Tx/Rx DMA + * descriptors. + * + * Clean the Tx/Rx Error pending interrupts. + * (Since dma fifo's are now empty) + * + * Enable global DMA and Error interrutps. + * + */ + +static void enable_data_error_intr(sdla_t *card) +{ + struct wan_dev_le *devle; + u32 reg; + netdevice_t *dev; + + DEBUG_TEST("%s: %s() !!!\n", + card->devname,__FUNCTION__); + + + /* Clean Tx/Rx DMA interrupts */ + card->hw_iface.bus_read_4(card->hw, + XILINX_DMA_RX_INTR_PENDING_REG, ®); + card->hw_iface.bus_read_4(card->hw, + XILINX_DMA_TX_INTR_PENDING_REG, ®); + + + /* For all channels clean Tx/Rx fifos */ + WAN_LIST_FOREACH(devle, &card->wandev.dev_head, dev_link){ + private_area_t *chan; + + dev = WAN_DEVLE2DEV(devle); + if (!dev || !wan_netif_priv(dev)) + continue; + chan = wan_netif_priv(dev); + + if (!wan_test_bit(0,&chan->up)){ + continue; + } + + aft_list_descriptors(chan); + + DEBUG_TEST("%s: 1) Free Used DMA CHAINS %s\n", + card->devname,chan->if_name); + + aft_rx_dma_chain_handler(chan,0,1); + aft_free_rx_complete_list(chan); + + + aft_list_descriptors(chan); + + DEBUG_TEST("%s: 1) Free UNUSED DMA CHAINS %s\n", + card->devname,chan->if_name); + + aft_free_rx_descriptors(chan); + + aft_free_tx_descriptors(chan); + + + DEBUG_TEST("%s: 2) Init interface fifo no wait %s\n", + card->devname,chan->if_name); + + xilinx_init_rx_dev_fifo(card, chan, WP_NO_WAIT); + xilinx_init_tx_dev_fifo(card, chan, WP_NO_WAIT); + + aft_list_descriptors(chan); + } + + + + if (card->fe.fe_cfg.cfg.te3_cfg.fractional){ + card->hw_iface.bus_read_4(card->hw,TE3_FRACT_ENCAPSULATION_REG,®); + + DEBUG_EVENT("%s: Rx Fractional Frame Size = 0x%lX\n", + card->devname, + get_te3_rx_fract_frame_size(reg)); + + /* FIXME: Setup bitrate and tx frame size */ + } + + + /* Enable DMA controler, in order to start the + * fifo cleaning */ + reg=0; + reg|=(AFT_T3_DMA_FIFO_MARK << DMA_FIFO_T3_MARK_BIT_SHIFT); + reg|=(MAX_AFT_DMA_CHAINS-1)&DMA_CHAIN_TE3_MASK; + + wan_set_bit(DMA_RX_ENGINE_ENABLE_BIT,®); + wan_set_bit(DMA_TX_ENGINE_ENABLE_BIT,®); + card->hw_iface.bus_write_4(card->hw,XILINX_DMA_CONTROL_REG,reg); + + /* For all channels clean Tx/Rx fifos */ + WAN_LIST_FOREACH(devle, &card->wandev.dev_head, dev_link){ + private_area_t *chan; + + dev = WAN_DEVLE2DEV(devle); + if (!dev || !wan_netif_priv(dev)) + continue; + chan = wan_netif_priv(dev); + + if (!wan_test_bit(0,&chan->up)){ + continue; + } + + DEBUG_TEST("%s: 3) Init interface fifo %s\n", + card->devname,chan->if_name); + + xilinx_init_rx_dev_fifo(card, chan, WP_WAIT); + xilinx_init_tx_dev_fifo(card, chan, WP_WAIT); + + DEBUG_TEST("%s: Clearing Fifo and idle_flag %s\n", + card->devname,chan->if_name); + wan_clear_bit(0,&chan->idle_start); + } + + /* For all channels, reprogram Tx/Rx DMA descriptors. + * For Tx also make sure that the BUSY flag is clear + * and previoulsy Tx packet is deallocated */ + + WAN_LIST_FOREACH(devle, &card->wandev.dev_head, dev_link){ + private_area_t *chan; + + dev = WAN_DEVLE2DEV(devle); + if (!dev || !wan_netif_priv(dev)) + continue; + chan = wan_netif_priv(dev); + + if (!wan_test_bit(0,&chan->up)){ + continue; + } + + DEBUG_TEST("%s: 4) Init interface %s\n", + card->devname,chan->if_name); + + xilinx_dma_rx(card,chan,-1); + + aft_list_descriptors(chan); + + DEBUG_TEST("%s: Clearing Fifo and idle_flag %s\n", + card->devname,chan->if_name); + + } + + /* Clean Tx/Rx Error interrupts, since fifos are now + * empty, and Tx fifo may generate an underrun which + * we want to ignore :) */ + + card->hw_iface.bus_read_4(card->hw, + XILINX_HDLC_RX_INTR_PENDING_REG, ®); + card->hw_iface.bus_read_4(card->hw, + XILINX_HDLC_TX_INTR_PENDING_REG, ®); + + /* Enable Global DMA and Error Interrupts */ + reg=0; + card->hw_iface.bus_read_4(card->hw,XILINX_CHIP_CFG_REG,®); + wan_set_bit(GLOBAL_INTR_ENABLE_BIT,®); + wan_set_bit(ERROR_INTR_ENABLE_BIT,®); + card->hw_iface.bus_write_4(card->hw,XILINX_CHIP_CFG_REG,reg); + + + card->hw_iface.bus_read_4(card->hw,XILINX_DMA_CONTROL_REG,®); + + aft_enable_rx_watchdog(card,AFT_RX_TIMEOUT); + aft_enable_tx_watchdog(card,AFT_TX_TIMEOUT); + + DEBUG_TEST("%s: END !!! Dma=0x%08X\n", + __FUNCTION__,reg); + +} + +static void disable_data_error_intr(sdla_t *card, unsigned char event) +{ + u32 reg; +#if 0 + private_area_t *chan; + + card->hw_iface.bus_read_4(card->hw,XILINX_CHIP_CFG_REG,®); + wan_clear_bit(GLOBAL_INTR_ENABLE_BIT,®); + wan_clear_bit(ERROR_INTR_ENABLE_BIT,®); + wan_clear_bit(FRONT_END_INTR_ENABLE_BIT,®); + wan_clear_bit(ENABLE_TE3_FRACTIONAL,®); + card->hw_iface.bus_write_4(card->hw,XILINX_CHIP_CFG_REG,reg); + + aft_reset_rx_watchdog(card); + aft_reset_tx_watchdog(card); + + chan=(private_area_t*)card->u.xilinx.dev_to_ch_map[0]; + if (chan && wan_test_bit(0,&chan->up)){ + xilinx_dev_close(card,chan); + WAN_NETIF_STOP_QUEUE(chan->common.dev); + WAN_TASKLET_KILL(&chan->common.bh_task); + } + + xilinx_t3_exar_chip_unconfigure(card); + + WP_DELAY(10500); + + xilinx_t3_exar_chip_configure(card); + if (chan && wan_test_bit(0,&chan->up)){ + WP_DELAY(500); + xilinx_t3_exar_dev_configure(card,chan); + WP_DELAY(500); + xilinx_dev_enable(card, chan); + WAN_TASKLET_INIT((&chan->common.bh_task),0,wp_bh,(unsigned long)chan); + } +#endif + + + card->hw_iface.bus_read_4(card->hw,XILINX_CHIP_CFG_REG,®); + wan_clear_bit(GLOBAL_INTR_ENABLE_BIT,®); + wan_clear_bit(ERROR_INTR_ENABLE_BIT,®); + if (event==DEVICE_DOWN){ + wan_clear_bit(FRONT_END_INTR_ENABLE_BIT,®); + wan_clear_bit(ENABLE_TE3_FRACTIONAL,®); + } + card->hw_iface.bus_write_4(card->hw,XILINX_CHIP_CFG_REG,reg); + + card->hw_iface.bus_read_4(card->hw,XILINX_DMA_CONTROL_REG,®); + wan_clear_bit(DMA_RX_ENGINE_ENABLE_BIT,®); + wan_clear_bit(DMA_TX_ENGINE_ENABLE_BIT,®); + card->hw_iface.bus_write_4(card->hw,XILINX_DMA_CONTROL_REG,reg); + + aft_reset_rx_watchdog(card); + aft_reset_tx_watchdog(card); + + if (event==DEVICE_DOWN){ + wan_set_bit(CARD_DOWN,&card->wandev.critical); + } + + + DEBUG_TEST("%s: Event = %s\n",__FUNCTION__, + event==DEVICE_DOWN?"Device Down": "Link Down"); + +} + +static void xilinx_init_tx_dma_descr(sdla_t *card, private_area_t *chan) +{ + unsigned long dma_descr; + unsigned long reg=0; + + dma_descr=(chan->logic_ch_num<<4) + XILINX_TxDMA_DESCRIPTOR_HI; + card->hw_iface.bus_write_4(card->hw,dma_descr, reg); +} + + + +/*============================================================================ + * Update communications error and general packet statistics. + */ +static int update_comms_stats(sdla_t* card) +{ + /* 1. On the first timer interrupt, update T1/E1 alarms + * and PMON counters (only for T1/E1 card) (TE1) + */ + + /* TE1 Update T1/E1 alarms */ + if (IS_TE3(&card->fe.fe_cfg)) { + WAN_FECALL(&card->wandev, read_alarm, (&card->fe, 0)); + /* TE1 Update T1/E1 perfomance counters */ + WAN_FECALL(&card->wandev, read_pmon, (&card->fe, 0)); + } + + return 0; +} + +static void xilinx_tx_fifo_under_recover (sdla_t *card, private_area_t *chan) +{ + +#if 1 + u32 reg; + /* Enable DMA controler, in order to start the + * fifo cleaning */ + card->hw_iface.bus_read_4(card->hw,XILINX_DMA_CONTROL_REG,®); + wan_clear_bit(DMA_TX_ENGINE_ENABLE_BIT,®); + card->hw_iface.bus_write_4(card->hw,XILINX_DMA_CONTROL_REG,reg); +#endif + +#if 0 + aft_list_tx_descriptors(chan); +#endif + aft_free_tx_descriptors(chan); + +#if 1 + xilinx_init_tx_dev_fifo(card,chan,WP_NO_WAIT); + + card->hw_iface.bus_read_4(card->hw,XILINX_DMA_CONTROL_REG,®); + wan_set_bit(DMA_TX_ENGINE_ENABLE_BIT,®); + card->hw_iface.bus_write_4(card->hw,XILINX_DMA_CONTROL_REG,reg); + + xilinx_init_tx_dev_fifo(card,chan,WP_WAIT); +#endif + wan_clear_bit(0,&chan->idle_start); + + WAN_NETIF_WAKE_QUEUE(chan->common.dev); +#ifndef CONFIG_PRODUCT_WANPIPE_GENERIC + if (chan->common.usedby == API){ + wan_wakeup_api(chan); + }else if (chan->common.usedby == STACK){ + wanpipe_lip_kick(chan,0); + } +#endif + aft_enable_tx_watchdog(card,AFT_TX_TIMEOUT); +} + +static int xilinx_write_ctrl_hdlc(sdla_t *card, u32 timeslot, u8 reg_off, u32 data) +{ + /* M.F. for Exar T3 card direct access + * without analize current timeslot */ + + card->hw_iface.bus_write_4(card->hw,reg_off,data); + + return 0; +} + +static int set_chan_state(sdla_t* card, netdevice_t* dev, int state) +{ + private_area_t *chan = wan_netif_priv(dev); + + chan->common.state = state; + if (state == WAN_CONNECTED){ + wan_clear_bit(0,&chan->idle_start); + aft_te3_led_ctrl(card, WAN_AFT_RED, 1, WAN_AFT_OFF); + aft_te3_led_ctrl(card, WAN_AFT_GREEN, 1,WAN_AFT_ON); + WAN_NETIF_CARRIER_ON(dev); + WAN_NETIF_WAKE_QUEUE(dev); + }else{ + aft_te3_led_ctrl(card, WAN_AFT_RED, 1, WAN_AFT_ON); + aft_te3_led_ctrl(card, WAN_AFT_GREEN, 1,WAN_AFT_OFF); + WAN_NETIF_CARRIER_OFF(dev); + WAN_NETIF_STOP_QUEUE(dev); + } + +#if defined(__LINUX__) +# if !defined(CONFIG_PRODUCT_WANPIPE_GENERIC) + if (chan->common.usedby == API){ + wan_update_api_state(chan); + } +#endif +#endif + + if (chan->common.usedby == STACK){ + if (state == WAN_CONNECTED){ + wanpipe_lip_connect(chan,0); + }else{ + wanpipe_lip_disconnect(chan,0); + } + } + return 0; +} + + + +/**SECTION************************************************************* + * + * Protocol API Support Functions + * + **********************************************************************/ + + +static int protocol_init (sdla_t *card, netdevice_t *dev, + private_area_t *chan, + wanif_conf_t* conf) +{ + + chan->common.protocol = conf->protocol; + + DEBUG_TEST("%s: Protocol init 0x%X PPP=0x0%x FR=0x0%X\n", + wan_netif_name(dev), chan->common.protocol, + WANCONFIG_PPP, + WANCONFIG_FR); + +#ifndef CONFIG_PRODUCT_WANPIPE_GENERIC + + DEBUG_EVENT("%s: AFT Driver doesn't directly support any protocols!\n", + chan->if_name); + return -1; + +#else + if (chan->common.protocol == WANCONFIG_PPP || + chan->common.protocol == WANCONFIG_CHDLC){ + + struct ifreq ifr; + struct if_settings ifsettings; + + wanpipe_generic_register(card, dev, wan_netif_name(dev)); + chan->common.prot_ptr = dev; + + if (chan->common.protocol == WANCONFIG_CHDLC){ + DEBUG_EVENT("%s: Starting Kernel CISCO HDLC protocol\n", + chan->if_name); + ifsettings.type = IF_PROTO_CISCO; + }else{ + DEBUG_EVENT("%s: Starting Kernel Sync PPP protocol\n", + chan->if_name); + ifsettings.type = IF_PROTO_PPP; + + } + ifr.ifr_data = (caddr_t)&ifsettings; + if (wp_lite_set_proto(dev, &ifr)){ + wanpipe_generic_unregister(dev); + return -EINVAL; + } + + }else if (chan->common.protocol == WANCONFIG_GENERIC){ + chan->common.prot_ptr = dev; + + }else{ + DEBUG_EVENT("%s:%s: Unsupported protocol %d\n", + card->devname,chan->if_name,chan->common.protocol); + return -EPROTONOSUPPORT; + } +#endif + + return 0; +} + + +static int protocol_start (sdla_t *card, netdevice_t *dev) +{ + int err=0; + + private_area_t *chan=wan_netif_priv(dev); + + if (!chan) + return 0; + + return err; +} + +static int protocol_stop (sdla_t *card, netdevice_t *dev) +{ + private_area_t *chan=wan_netif_priv(dev); + int err = 0; + + if (!chan) + return 0; + + return err; +} + +static int protocol_shutdown (sdla_t *card, netdevice_t *dev) +{ + private_area_t *chan=wan_netif_priv(dev); + + if (!chan) + return 0; + +#ifndef CONFIG_PRODUCT_WANPIPE_GENERIC + + return 0; +#else + + if (chan->common.protocol == WANCONFIG_PPP || + chan->common.protocol == WANCONFIG_CHDLC){ + + chan->common.prot_ptr = NULL; + wanpipe_generic_unregister(dev); + + }else if (chan->common.protocol == WANCONFIG_GENERIC){ + DEBUG_EVENT("%s:%s Protocol shutdown... \n", + card->devname, chan->if_name); + } +#endif + return 0; +} + +void protocol_recv(sdla_t *card, private_area_t *chan, netskb_t *skb) +{ + +#ifdef CONFIG_PRODUCT_WANPIPE_GENERIC + if (chan->common.protocol == WANCONFIG_PPP || + chan->common.protocol == WANCONFIG_CHDLC){ + wanpipe_generic_input(chan->common.dev, skb); + return 0; + } +#endif + +#if defined(__LINUX__) && defined(CONFIG_PRODUCT_WANPIPE_GENERIC) + if (chan->common.protocol == WANCONFIG_GENERIC){ + skb->protocol = htons(ETH_P_HDLC); + skb->dev = chan->common.dev; + skb->mac.raw = wan_netif_data(skb); + netif_rx(skb); + return 0; + } +#endif + +#if defined(__LINUX__) + skb->protocol = htons(ETH_P_IP); + skb->dev = chan->common.dev; + skb->mac.raw = wan_skb_data(skb); + netif_rx(skb); +#else + DEBUG_EVENT("%s: Action not supported (IP)!\n", + card->devname); + wan_skb_free(skb); +#endif + + return; +} + + +/**SECTION************************************************************* + * + * T3 Exar Config Code + * + **********************************************************************/ + + +/*========================================================= + * xilinx_t3_exar_chip_configure + * + */ + +static int xilinx_t3_exar_chip_configure(sdla_t *card) +{ + u32 reg,tmp; + volatile unsigned char cnt=0; + int err=0; + + DEBUG_CFG("T3 Exar Chip Configuration. -- \n"); + + xilinx_delay(1); + + card->hw_iface.bus_read_4(card->hw,XILINX_CHIP_CFG_REG, ®); + + /* Enable the chip/hdlc reset condition */ + reg=0; + wan_set_bit(CHIP_RESET_BIT,®); + wan_set_bit(FRONT_END_RESET_BIT,®); + + /* Hardcode the AFT T3/E3 clock source + * to External/Normal */ + if (card->fe.fe_cfg.cfg.te3_cfg.clock == WAN_MASTER_CLK){ + wan_set_bit(AFT_T3_CLOCK_MODE,®); + }else{ + wan_clear_bit(AFT_T3_CLOCK_MODE,®); + } + + DEBUG_CFG("--- T3 Exar Chip Reset. -- \n"); + + card->hw_iface.bus_write_4(card->hw,XILINX_CHIP_CFG_REG,reg); + + WP_DELAY(10); + + /* Disable the chip/hdlc reset condition */ + wan_clear_bit(CHIP_RESET_BIT,®); + wan_clear_bit(FRONT_END_RESET_BIT,®); + + /* Disable ALL chip interrupts */ + wan_clear_bit(GLOBAL_INTR_ENABLE_BIT,®); + wan_clear_bit(ERROR_INTR_ENABLE_BIT,®); + wan_clear_bit(FRONT_END_INTR_ENABLE_BIT,®); + + /* Configure for T3 or E3 front end */ + + if (IS_DS3(&card->fe.fe_cfg)){ + card->u.xilinx.num_of_time_slots=NUM_OF_T1_CHANNELS; + wan_clear_bit(INTERFACE_TYPE_T3_E3_BIT,®); + if (card->fe.fe_cfg.frame == WAN_FR_DS3_Cbit){ + wan_set_bit(INTERFACE_MODE_DS3_C_BIT,®); + }else{ + wan_clear_bit(INTERFACE_MODE_DS3_C_BIT,®); + } + }else if (IS_E3(&card->fe.fe_cfg)){ + card->u.xilinx.num_of_time_slots=NUM_OF_E1_CHANNELS; + wan_set_bit(INTERFACE_TYPE_T3_E3_BIT,®); + if (card->fe.fe_cfg.frame == WAN_FR_E3_G832){ + wan_set_bit(INTERFACE_MODE_E3_G832,®); + }else{ + wan_clear_bit(INTERFACE_MODE_E3_G832,®); + } + }else{ + DEBUG_EVENT("%s: Error: T3 Exar doesn't support non T3/E3 interface!\n", + card->devname); + return -EINVAL; + } + + /* Hardcode the HDLC Conroller to + * HDLC mode. The transparent mode can be + * configured later in new_if() section + * + * HDLC =clear bit + * TRANSPARENT =set bit + * */ + wan_clear_bit(AFT_T3_HDLC_TRANS_MODE,®); + + + /* Enable/Disable TX and RX Fractional + * HDLC */ + + /* FIXME: HAVE A CONFIG OPTION HERE */ + + /* Enable Internal HDLC Encapsulation core */ + if (card->fe.fe_cfg.cfg.te3_cfg.fractional){ + DEBUG_EVENT("%s: BEFORE TE3 FRACT = 0x%X\n", + card->devname, reg); + + wan_set_bit(ENABLE_TE3_FRACTIONAL,®); + + //te3_enable_fractional(®, TE3_FRACT_VENDOR_KENTROX); + DEBUG_EVENT("%s: AFTER TE3 FRACT = 0x%X\n", + card->devname, reg); + }else{ + wan_clear_bit(ENABLE_TE3_FRACTIONAL,®); + } + + DEBUG_CFG("--- T3 Exar Chip enable/config. -- \n"); + + card->hw_iface.bus_write_4(card->hw,XILINX_CHIP_CFG_REG,reg); + + xilinx_delay(1); +#if 0 + framer_reset(card); /* was for A105 proto */ +#endif /* M.F. remove for A300 */ + +#if 0 + write_cpld(card,0x00, 0x00); /* M.F. was 0x01 for A105 proto */ + /* M.F. 0x00 for A300 */ + /* set DS3 interface mode */ + write_cpld(card,0x01, 0x00); /* clear TxAIS bit */ + + // 3. Setup Framer + write_framer(card,0x00, 0x6F); /* DS3 - mode (bit 6)*/ + /* Internal LOS enable (bit 5)*/ + /* Interrupt enabl.reset(bit 3)*/ + /* Frame format M13 (bit 2)*/ + /* TimRef - Mode 3 (code '1X')*/ + write_framer(card,0x01, 0xA2); /* */ +#else + +//FIXME: Alex to put in Exar T3/E3 Configuration + DEBUG_EVENT("%s: Config %s Front End: Clock=%s\n", + card->devname, + FE_MEDIA_DECODE(&card->fe), + (card->fe.fe_cfg.cfg.te3_cfg.clock == WAN_MASTER_CLK)? + "Master":"Normal"); + + if (card->wandev.fe_iface.config){ + err = card->wandev.fe_iface.config(&card->fe); + if (err){ + DEBUG_EVENT("%s: Failed %s configuratoin!\n", + card->devname, + FE_MEDIA_DECODE(&card->fe)); + return -EINVAL; + } + }else{ + DEBUG_EVENT("%s: Internal Error (%s:%d)\n", + card->devname, + __FUNCTION__,__LINE__); + return -EINVAL; + } +#endif + for (;;){ + card->hw_iface.bus_read_4(card->hw,XILINX_CHIP_CFG_REG, ®); + + if (!wan_test_bit(HDLC_CORE_READY_FLAG_BIT,®)){ + /* The HDLC Core is not ready! we have + * an error. */ + if (++cnt > 5){ + err = -EINVAL; + break; + }else{ + WP_DELAY(500); + /* FIXME: we cannot do this while in + * critical area */ + } + }else{ + err=0; + break; + } + } + + xilinx_delay(1); + + if (err != 0){ + DEBUG_EVENT("%s: Error: HDLC Core Not Ready!\n", + card->devname); + + card->hw_iface.bus_read_4(card->hw,XILINX_CHIP_CFG_REG, ®); + + /* Disable the chip/hdlc reset condition */ + wan_set_bit(CHIP_RESET_BIT,®); + + card->hw_iface.bus_write_4(card->hw,XILINX_CHIP_CFG_REG,reg); + return err; + } else{ + DEBUG_CFG("%s: HDLC Core Ready 0x%08X\n", + card->devname,reg); + } + + xilinx_delay(1); + + /* Setup global DMA parameters */ + reg=0; + reg|=(AFT_T3_DMA_FIFO_MARK << DMA_FIFO_T3_MARK_BIT_SHIFT); + reg|=(MAX_AFT_DMA_CHAINS-1)&DMA_CHAIN_TE3_MASK; + + /* Enable global DMA engine and set to default + * number of active channels. Note: this value will + * change in dev configuration */ + wan_set_bit(DMA_RX_ENGINE_ENABLE_BIT,®); + wan_set_bit(DMA_TX_ENGINE_ENABLE_BIT,®); + + DEBUG_CFG("--- Setup DMA control Reg. -- \n"); + + card->hw_iface.bus_write_4(card->hw,XILINX_DMA_CONTROL_REG,reg); + DEBUG_CFG("--- Tx/Rx global enable. -- \n"); + + xilinx_delay(1); + + reg=0; + card->hw_iface.bus_write_4(card->hw,XILINX_TIMESLOT_HDLC_CHAN_REG,reg); + + /* Clear interrupt pending registers befor first interrupt enable */ + card->hw_iface.bus_read_4(card->hw, XILINX_DMA_RX_INTR_PENDING_REG, &tmp); + card->hw_iface.bus_read_4(card->hw, XILINX_DMA_TX_INTR_PENDING_REG, &tmp); + card->hw_iface.bus_read_4(card->hw, XILINX_HDLC_RX_INTR_PENDING_REG, &tmp); + card->hw_iface.bus_read_4(card->hw, XILINX_HDLC_TX_INTR_PENDING_REG, &tmp); + + card->hw_iface.bus_read_4(card->hw, XILINX_CHIP_CFG_REG, (u32*)®); + + if (wan_test_bit(DMA_INTR_FLAG,®)){ + DEBUG_EVENT("%s: Error: Active DMA Interrupt Pending. !\n", + card->devname); + + reg = 0; + /* Disable the chip/hdlc reset condition */ + wan_set_bit(CHIP_RESET_BIT,®); + card->hw_iface.bus_write_4(card->hw,XILINX_CHIP_CFG_REG,reg); + return err; + } + if (wan_test_bit(ERROR_INTR_FLAG,®)){ + DEBUG_EVENT("%s: Error: Active Error Interrupt Pending. !\n", + card->devname); + + reg = 0; + /* Disable the chip/hdlc reset condition */ + wan_set_bit(CHIP_RESET_BIT,®); + card->hw_iface.bus_write_4(card->hw,XILINX_CHIP_CFG_REG,reg); + return err; + } + + + /* Alawys disable global data and error + * interrupts */ + wan_clear_bit(GLOBAL_INTR_ENABLE_BIT,®); + wan_clear_bit(ERROR_INTR_ENABLE_BIT,®); + +#ifndef AFT_XTEST_DEBUG + /* Always enable the front end interrupt */ + wan_set_bit(FRONT_END_INTR_ENABLE_BIT,®); +#endif + DEBUG_CFG("--- Set Global Interrupts (0x%X)-- \n",reg); + + xilinx_delay(1); + + card->hw_iface.bus_write_4(card->hw,XILINX_CHIP_CFG_REG,reg); + + DEBUG_CFG("--- Set Global Interrupt enabled. -- \n"); + + return err; +} + +static int xilinx_t3_exar_dev_configure(sdla_t *card, private_area_t *chan) +{ + + u32 reg,reg1; + + DEBUG_TEST("-- T3 Exar Dev Configure Xilinx. --\n"); + + + chan->logic_ch_num=0; + chan->first_time_slot=0; + card->u.xilinx.logic_ch_map=0x01; + + if (!card->u.xilinx.dev_to_ch_map[0]){ + card->u.xilinx.dev_to_ch_map[0]=(void*)chan; + } + + reg=0; + + if (chan->hdlc_eng){ + /* HDLC engine is enabled on the above logical channels */ + wan_clear_bit(HDLC_RX_PROT_DISABLE_BIT,®); + wan_clear_bit(HDLC_TX_PROT_DISABLE_BIT,®); + + wan_set_bit(HDLC_TX_CHAN_ENABLE_BIT,®); + + if (card->fe.fe_cfg.cfg.te3_cfg.fractional){ + DEBUG_EVENT("%s: Configuring for Fractional\n",card->devname); + wan_set_bit(HDLC_RX_ADDR_FIELD_DISC_BIT,®); + wan_set_bit(HDLC_TX_ADDR_INSERTION_BIT,®); + }else{ + wan_set_bit(HDLC_RX_ADDR_RECOGN_DIS_BIT,®); + } + + if (card->fe.fe_cfg.cfg.te3_cfg.fcs == 32){ + wan_set_bit(HDLC_TX_FCS_SIZE_BIT,®); + wan_set_bit(HDLC_RX_FCS_SIZE_BIT,®); + } + + DEBUG_EVENT("%s:%s: Config for HDLC mode: FCS=%d\n", + card->devname,chan->if_name, + card->fe.fe_cfg.cfg.te3_cfg.fcs); + }else{ + + /* Transprent Mode */ + + /* Do not start HDLC Core here, because + * we have to setup Tx/Rx DMA buffers first + * The transparent mode, will start + * comms as soon as the HDLC is enabled */ + + } + + /* Select an HDLC Tx channel for configuration */ + reg1=0; + card->hw_iface.bus_write_4(card->hw, AFT_T3_RXTX_ADDR_SELECT_REG, reg1); + + if (card->fe.fe_cfg.cfg.te3_cfg.fractional){ + xilinx_write_ctrl_hdlc(card, + chan->first_time_slot, + XILINX_HDLC_ADDR_REG, + 0xA5A5A5A5); + } + + xilinx_write_ctrl_hdlc(card, + chan->first_time_slot, + XILINX_HDLC_CONTROL_REG, + reg); + + + /* Select an HDLC Rx channel for configuration */ + reg1=1; + card->hw_iface.bus_write_4(card->hw, AFT_T3_RXTX_ADDR_SELECT_REG, reg1); + + if (card->fe.fe_cfg.cfg.te3_cfg.fractional){ + + xilinx_write_ctrl_hdlc(card, + chan->first_time_slot, + XILINX_HDLC_ADDR_REG, + 0xA5A5A5A5); + } + + xilinx_write_ctrl_hdlc(card, + chan->first_time_slot, + XILINX_HDLC_CONTROL_REG, + reg); + + return 0; + +} + +static void xilinx_t3_exar_dev_unconfigure(sdla_t *card, private_area_t *chan) +{ + /* Nothing to do for T3 Exar */ + wan_smp_flag_t flags; + + wan_spin_lock_irq(&card->wandev.lock,&flags); + card->u.xilinx.dev_to_ch_map[0]=NULL; + aft_reset_rx_watchdog(card); + aft_reset_tx_watchdog(card); + wan_spin_unlock_irq(&card->wandev.lock,&flags); + +} + +static void xilinx_t3_exar_chip_unconfigure(sdla_t *card) +{ + + u32 reg=0; + + card->hw_iface.bus_read_4(card->hw,XILINX_CHIP_CFG_REG, ®); + + /* Enable the chip/hdlc reset condition */ + wan_set_bit(CHIP_RESET_BIT,®); + wan_set_bit(FRONT_END_RESET_BIT,®); + + card->hw_iface.bus_write_4(card->hw,XILINX_CHIP_CFG_REG,reg); + +} + + +static void xilinx_t3_exar_transparent_config(sdla_t *card,private_area_t *chan) +{ + u32 reg; + + DEBUG_EVENT("%s: Configuring for Transparent mode!\n", + card->devname); + + /* T3/E3 Exar Card */ + card->hw_iface.bus_read_4(card->hw,XILINX_CHIP_CFG_REG, ®); + /* Enable hdlc transparent mode */ + wan_set_bit(AFT_T3_HDLC_TRANS_MODE,®); + card->hw_iface.bus_write_4(card->hw,XILINX_CHIP_CFG_REG,reg); +} + + +#define BIT_DEV_ADDR_CLEAR 0x600 + +static int write_framer(void *pcard, unsigned short framer_off,unsigned short framer_data) +{ + sdla_t *card = (sdla_t*)pcard; + + framer_off &= ~BIT_DEV_ADDR_CLEAR; + + card->hw_iface.bus_write_2(card->hw, + 0x46, + framer_off); + + card->hw_iface.bus_write_2(card->hw, + 0x44, + framer_data); + return 0; +} + +static unsigned int read_framer(void *pcard,unsigned short framer_off) +{ + sdla_t *card = (sdla_t*)pcard; + unsigned int framer_data; + + framer_off &= ~BIT_DEV_ADDR_CLEAR; + + card->hw_iface.bus_write_2(card->hw, + 0x46, + framer_off); + + card->hw_iface.bus_read_4(card->hw, + 0x44, + &framer_data); + return framer_data; +} + +#if 0 +static void framer_reset(sdla_t *card) +{ + int i = 0; + unsigned short j = 0; + + j = (unsigned short)read_cpld(card,0x00); + j = j & 0x00FE; + write_cpld(card,0x00, j); + // delay + for(i=0;i<10;i++); + j = j | 0x0001; + write_cpld(card,0x00, j); +} +#endif + +/**SECTION************************************************************* + * + * TE3 Exar Tx Functions + * DMA Chains + * + **********************************************************************/ + + +/*=============================================== + * aft_tx_dma_chain_handler + * + */ +static void aft_tx_dma_chain_handler(unsigned long data) +{ + private_area_t *chan = (private_area_t *)data; + sdla_t *card = chan->card; + int dma_free=0; + u32 reg,dma_descr; + aft_dma_chain_t *dma_chain; + + if (wan_test_and_set_bit(TX_HANDLER_BUSY,&chan->dma_status)){ + DEBUG_EVENT("%s: SMP Critical in %s\n", + chan->if_name,__FUNCTION__); + return; + } + + dma_chain = &chan->tx_dma_chain_table[chan->tx_pending_chain_indx]; + + for (;;){ + + /* If the current DMA chain is in use,then + * all chains are busy */ + if (!wan_test_bit(0,&dma_chain->init)){ + break; + } + + dma_descr=(chan->tx_pending_chain_indx<<4) + XILINX_TxDMA_DESCRIPTOR_HI; + card->hw_iface.bus_read_4(card->hw,dma_descr,®); + + /* If GO bit is set, then the current DMA chain + * is in process of being transmitted, thus + * all are busy */ + if (wan_test_bit(TxDMA_HI_DMA_GO_READY_BIT,®)){ + break; + } + + DEBUG_TEST("%s: TX DMA Handler Chain %i\n",chan->if_name,dma_chain->index); + + if (dma_chain->skb){ +//NENAD +#if 1 + wan_skb_set_csum(dma_chain->skb, reg); + wan_skb_queue_tail(&chan->wp_tx_complete_list,dma_chain->skb); + dma_chain->skb=NULL; +#else + chan->if_stats.tx_packets++; + chan->if_stats.tx_bytes+=wan_skb_len(dma_chain->skb); +#endif + } + + aft_tx_dma_chain_init(chan,dma_chain); + + if (chan->single_dma_chain){ + break; + } + + if (++chan->tx_pending_chain_indx >= MAX_AFT_DMA_CHAINS){ + chan->tx_pending_chain_indx=0; + } + + dma_chain = &chan->tx_dma_chain_table[chan->tx_pending_chain_indx]; + dma_free=1; + } + + wan_clear_bit(TX_HANDLER_BUSY,&chan->dma_status); + + if (wan_skb_queue_len(&chan->wp_tx_complete_list)){ + WAN_TASKLET_SCHEDULE((&chan->common.bh_task)); + } + + return; +} + +/*=============================================== + * aft_dma_chain_tx + * + */ +static int aft_dma_chain_tx(aft_dma_chain_t *dma_chain,private_area_t *chan, int intr) +{ + +#define dma_descr dma_chain->dma_descr +#define reg dma_chain->reg +#define len dma_chain->dma_len +#define dma_ch_indx dma_chain->index +#define len_align dma_chain->len_align +#define card chan->card + + dma_descr=(dma_ch_indx<<4) + XILINX_TxDMA_DESCRIPTOR_HI; + + DEBUG_TX("%s:%d: chan logic ch=%i chain=%li dma_descr=0x%x set!\n", + __FUNCTION__,__LINE__,chan->logic_ch_num,dma_ch_indx,dma_descr); + + card->hw_iface.bus_read_4(card->hw,dma_descr,®); + + if (wan_test_bit(TxDMA_HI_DMA_GO_READY_BIT,®)){ + DEBUG_EVENT("%s: Error: TxDMA GO Ready bit set on dma (chain=%i) Tx 0x%X\n", + card->devname,dma_ch_indx,reg); + return -EBUSY; + } + + dma_descr=(dma_ch_indx<<4) + XILINX_TxDMA_DESCRIPTOR_LO; + + /* Write the pointer of the data packet to the + * DMA address register */ + reg=dma_chain->dma_addr; + + /* Set the 32bit alignment of the data length. + * Used to pad the tx packet to the 32 bit + * boundary */ + reg&=~(TxDMA_LO_ALIGNMENT_BIT_MASK); + reg|=(len&0x03); + + len_align=0; + if (len&0x03){ + len_align=1; + } + + DEBUG_TX("%s: TXDMA_LO=0x%X PhyAddr=0x%X DmaDescr=0x%X\n", + __FUNCTION__,reg,dma_chain->dma_addr,dma_descr); + + card->hw_iface.bus_write_4(card->hw,dma_descr,reg); + + dma_descr=(dma_ch_indx<<4) + XILINX_TxDMA_DESCRIPTOR_HI; + + reg=0; + + reg|=(((len>>2)+len_align)&TxDMA_HI_DMA_DATA_LENGTH_MASK); + + reg|=(chan->fifo_size_code&DMA_FIFO_SIZE_MASK)<fifo_base_addr&DMA_FIFO_BASE_ADDR_MASK)<< + DMA_FIFO_BASE_ADDR_SHIFT; + + + if (chan->single_dma_chain){ + wan_clear_bit(DMA_HI_TE3_NOT_LAST_FRAME_BIT,®); + wan_clear_bit(DMA_HI_TE3_INTR_DISABLE_BIT,®); + }else{ + + wan_set_bit(DMA_HI_TE3_NOT_LAST_FRAME_BIT,®); + + if (intr){ + DEBUG_TEST("%s: Setting Interrupt on index=%i\n", + chan->if_name,dma_ch_indx); + wan_clear_bit(DMA_HI_TE3_INTR_DISABLE_BIT,®); + }else{ + wan_set_bit(DMA_HI_TE3_INTR_DISABLE_BIT,®); + } + } + + if (chan->hdlc_eng){ + /* Only enable the Frame Start/Stop on + * non-transparent hdlc configuration */ + + wan_set_bit(TxDMA_HI_DMA_FRAME_START_BIT,®); + wan_set_bit(TxDMA_HI_DMA_FRAME_END_BIT,®); + } + + wan_set_bit(TxDMA_HI_DMA_GO_READY_BIT,®); + + DEBUG_TX("%s: TXDMA_HI=0x%X DmaDescr=0x%lX len=%i\n", + __FUNCTION__,reg,dma_chain->dma_addr,len); + + card->hw_iface.bus_write_4(card->hw,dma_descr,reg); + +#if 0 + ++chan->if_stats.tx_fifo_errors; +#endif + + return 0; + +#undef dma_descr +#undef reg +#undef len +#undef dma_ch_indx +#undef len_align +#undef card +} + +/*=============================================== + * aft_dma_chain_init + * + */ +static void aft_tx_dma_chain_init(private_area_t *chan, aft_dma_chain_t *dma_chain) +{ + + if (dma_chain->dma_addr){ + chan->card->hw_iface.pci_unmap_dma(chan->card->hw, + dma_chain->dma_addr, + dma_chain->dma_len, + PCI_DMA_TODEVICE); + } + + + if (dma_chain->skb){ + wan_skb_free(dma_chain->skb); + dma_chain->skb=NULL; + } + + dma_chain->dma_addr=0; + dma_chain->dma_len=0; + + wan_clear_bit(0,&dma_chain->init); +} + +static void aft_rx_dma_chain_init(private_area_t *chan, aft_dma_chain_t *dma_chain) +{ + + if (dma_chain->dma_addr){ + chan->card->hw_iface.pci_unmap_dma(chan->card->hw, + dma_chain->dma_addr, + dma_chain->dma_len, + PCI_DMA_FROMDEVICE); + } + + + if (dma_chain->skb){ + aft_init_requeue_free_skb(chan,dma_chain->skb); + dma_chain->skb=NULL; + } + + dma_chain->dma_addr=0; + dma_chain->dma_len=0; + + wan_clear_bit(0,&dma_chain->init); +} + +static int aft_realign_skb_pkt(private_area_t *chan, netskb_t *skb) +{ + unsigned char *data=wan_skb_data(skb); + int len = wan_skb_len(skb); + + if (len > chan->dma_mtu){ + DEBUG_EVENT("%s: Critical error: Tx unalign pkt(%d) > MTU buf(%d)!\n", + chan->if_name,len,chan->dma_mtu); + return -ENOMEM; + } + + if (!chan->tx_realign_buf){ + chan->tx_realign_buf=wan_malloc(chan->dma_mtu); + if (!chan->tx_realign_buf){ + DEBUG_EVENT("%s: Error: Failed to allocate tx memory buf\n", + chan->if_name); + return -ENOMEM; + }else{ + DEBUG_EVENT("%s: AFT Realign buffer allocated Len=%d\n", + chan->if_name,chan->dma_mtu); + + } + } + + memcpy(chan->tx_realign_buf,data,len); + + wan_skb_init(skb,0); + wan_skb_trim(skb,0); + + if (wan_skb_tailroom(skb) < len){ + DEBUG_EVENT("%s: Critical error: Tx unalign pkt tail room(%i) < unalign len(%i)!\n", + chan->if_name,wan_skb_tailroom(skb),len); + + return -ENOMEM; + } + + data=wan_skb_put(skb,len); + + if ((unsigned long)data & 0x03){ + /* At this point pkt should be realigned. If not + * there is something really wrong! */ + return -EINVAL; + } + + memcpy(data,chan->tx_realign_buf,len); + + return 0; +} + + + +/*=============================================== + * xilinx_dma_te3_tx + * + */ +static int xilinx_dma_te3_tx (sdla_t *card,private_area_t *chan, netskb_t *skb) +{ + int err=0, intr=0; + aft_dma_chain_t *dma_chain; + + if (wan_test_and_set_bit(TX_DMA_BUSY,&chan->dma_status)){ + DEBUG_EVENT("%s: SMP Critical in %s\n", + chan->if_name,__FUNCTION__); + + return -EBUSY; + } + + if (chan->tx_chain_indx >= MAX_AFT_DMA_CHAINS){ + DEBUG_EVENT("%s: MAJOR ERROR: TE3 Tx: Dma tx chain = %i\n", + chan->if_name,chan->tx_chain_indx); + if (!chan->single_dma_chain){ + aft_enable_tx_watchdog(card,AFT_TX_TIMEOUT); + } + return -EBUSY; + } + + dma_chain = &chan->tx_dma_chain_table[chan->tx_chain_indx]; + + aft_reset_tx_watchdog(card); + + /* If the current DMA chain is in use,then + * all chains are busy */ + if (wan_test_and_set_bit(0,&dma_chain->init)){ + wan_clear_bit(TX_DMA_BUSY,&chan->dma_status); + return -EBUSY; + } + + if ((unsigned long)wan_skb_data(skb) & 0x03){ + err=aft_realign_skb_pkt(chan,skb); + if (err){ + if (WAN_NET_RATELIMIT()){ + DEBUG_EVENT("%s: Tx Error: Non Aligned packet %p: dropping...\n", + chan->if_name,wan_skb_data(skb)); + } + wan_skb_free(skb); + wan_clear_bit(0,&dma_chain->init); + chan->if_stats.tx_errors++; + return -EINVAL; + } + } + + dma_chain->skb=skb; + + dma_chain->dma_addr = + card->hw_iface.pci_map_dma(card->hw, + wan_skb_data(dma_chain->skb), + wan_skb_len(dma_chain->skb), + PCI_DMA_TODEVICE); + + dma_chain->dma_len = wan_skb_len(dma_chain->skb); + + + DEBUG_TX("%s: DMA Chain %i: Cur=%i Pend=%i Len=%i\n", + chan->if_name,dma_chain->index, + chan->tx_chain_indx,chan->tx_pending_chain_indx, + wan_skb_len(dma_chain->skb)); + + intr=0; + if (!chan->single_dma_chain && + !wan_test_bit(TX_INTR_PENDING,&chan->dma_chain_status)){ + int pending_indx=chan->tx_pending_chain_indx; + if (chan->tx_chain_indx >= pending_indx){ + intr = ((MAX_AFT_DMA_CHAINS-(chan->tx_chain_indx - + pending_indx))<=2); + }else{ + intr = ((pending_indx - chan->tx_chain_indx)<=2); + } + + if (intr){ + DEBUG_TEST("%s: Setting tx interrupt on chain=%i\n", + chan->if_name,dma_chain->index); + wan_set_bit(TX_INTR_PENDING,&chan->dma_chain_status); + } + } + + err=aft_dma_chain_tx(dma_chain,chan,intr); + if (err){ + DEBUG_EVENT("%s: Tx dma chain %i overrun error: should never happen!\n", + chan->if_name,dma_chain->index); + aft_tx_dma_chain_init(chan,dma_chain); + chan->if_stats.tx_errors++; + + wan_clear_bit(TX_DMA_BUSY,&chan->dma_status); + return -EINVAL; + } + + + /* We are sure that the packet will + * be bound and transmitted, thus unhook + * it from the protocol stack */ + wan_skb_unlink(skb); + + if (!chan->single_dma_chain){ + if (++chan->tx_chain_indx >= MAX_AFT_DMA_CHAINS){ + chan->tx_chain_indx=0; + } + + if (!wan_test_bit(TX_INTR_PENDING,&chan->dma_chain_status)){ + aft_enable_tx_watchdog(card,AFT_TX_TIMEOUT); + } + } + + wan_clear_bit(TX_DMA_BUSY,&chan->dma_status); + + return 0; +} + + + +static void aft_pending_tx(sdla_t *card, private_area_t *chan) +{ + netskb_t *skb; + int err; + + while ((skb=wan_skb_dequeue(&chan->wp_tx_pending_list))!=NULL){ + err=xilinx_dma_te3_tx(card,chan,skb); + if (err==-EBUSY){ + wan_skb_queue_head(&chan->wp_tx_pending_list,skb); + break; + } + } +} + + +/**SECTION************************************************************* + * + * TE3 Exar Rx Functions + * DMA Chains + * + **********************************************************************/ + +static int aft_dma_chain_rx(aft_dma_chain_t *dma_chain, private_area_t *chan, int intr) +{ +#define dma_descr dma_chain->dma_descr +#define reg dma_chain->reg +#define len dma_chain->dma_len +#define dma_ch_indx dma_chain->index +#define len_align dma_chain->len_align +#define card chan->card + + /* Write the pointer of the data packet to the + * DMA address register */ + reg=dma_chain->dma_addr; + + /* Set the 32bit alignment of the data length. + * Since we are setting up for rx, set this value + * to Zero */ + reg&=~(RxDMA_LO_ALIGNMENT_BIT_MASK); + + dma_descr=(dma_ch_indx<<4) + XILINX_RxDMA_DESCRIPTOR_LO; + +// DEBUG_RX("%s: RxDMA_LO = 0x%X, BusAddr=0x%X DmaDescr=0x%X\n", +// __FUNCTION__,reg,bus_addr,dma_descr); + + card->hw_iface.bus_write_4(card->hw,dma_descr,reg); + + dma_descr=(unsigned long)(dma_ch_indx<<4) + XILINX_RxDMA_DESCRIPTOR_HI; + + reg =0; + + if (chan->single_dma_chain){ + wan_clear_bit(DMA_HI_TE3_NOT_LAST_FRAME_BIT,®); + wan_clear_bit(DMA_HI_TE3_INTR_DISABLE_BIT,®); + }else{ + + wan_set_bit(DMA_HI_TE3_NOT_LAST_FRAME_BIT,®); + + if (intr){ + DEBUG_TEST("%s: Setting Rx Interrupt on index=%i\n", + chan->if_name,dma_ch_indx); + wan_clear_bit(DMA_HI_TE3_INTR_DISABLE_BIT,®); + }else{ + wan_set_bit(DMA_HI_TE3_INTR_DISABLE_BIT,®); + } + + } + + if (chan->hdlc_eng){ + reg|=((chan->dma_mtu>>2)-1)&RxDMA_HI_DMA_DATA_LENGTH_MASK; + }else{ + reg|=(card->wandev.mtu>>2)&RxDMA_HI_DMA_DATA_LENGTH_MASK; + } + + reg|=(chan->fifo_size_code&DMA_FIFO_SIZE_MASK)<fifo_base_addr&DMA_FIFO_BASE_ADDR_MASK)<< + DMA_FIFO_BASE_ADDR_SHIFT; + + wan_set_bit(RxDMA_HI_DMA_GO_READY_BIT,®); + + DEBUG_RX("%s: RXDMA_HI = 0x%X, BusAddr=0x%X DmaDescr=0x%X\n", + __FUNCTION__,reg,dma_chain->dma_addr,dma_descr); + + card->hw_iface.bus_write_4(card->hw,dma_descr,reg); + + return 0; + +#undef dma_descr +#undef reg +#undef len +#undef dma_ch_indx +#undef len_align +#undef card +} + +static int xilinx_dma_rx(sdla_t *card, private_area_t *chan, int gcur_ptr) +{ + int err=0, intr=0; + aft_dma_chain_t *dma_chain; + int cur_dma_ptr, i,max_dma_cnt,free_queue_len; + u32 reg; + + if (wan_test_and_set_bit(RX_DMA_BUSY,&chan->dma_status)){ + DEBUG_EVENT("%s: SMP Critical in %s\n", + chan->if_name,__FUNCTION__); + return -EBUSY; + } + + aft_reset_rx_watchdog(card); + + if (chan->single_dma_chain) { + max_dma_cnt=MAX_AFT_DMA_CHAINS; + cur_dma_ptr=0; + free_queue_len=MAX_AFT_DMA_CHAINS; + }else{ + + free_queue_len=wan_skb_queue_len(&chan->wp_rx_free_list); + if (free_queue_len == 0){ + aft_free_rx_complete_list(chan); + free_queue_len=wan_skb_queue_len(&chan->wp_rx_free_list); + if (free_queue_len == 0){ + DEBUG_EVENT("%s: %s() CRITICAL ERROR: No free rx buffers\n", + card->devname,__FUNCTION__); + goto te3_rx_skip; + } + } + + if (gcur_ptr >= 0){ + cur_dma_ptr=gcur_ptr; + }else{ + card->hw_iface.bus_read_4(card->hw,AFT_TE3_CRNT_DMA_DESC_ADDR_REG,®); + cur_dma_ptr=get_current_rx_dma_ptr(reg); + } + + if (chan->rx_chain_indx >= cur_dma_ptr){ + max_dma_cnt = MAX_AFT_DMA_CHAINS - (chan->rx_chain_indx-cur_dma_ptr); + }else{ + max_dma_cnt = cur_dma_ptr - chan->rx_chain_indx; + } + + if (free_queue_len < max_dma_cnt){ + #if 0 + if (WAN_NET_RATELIMIT()){ + DEBUG_EVENT("%s: Free List(%d) lower than max dma %d\n", + card->devname, + free_queue_len, + max_dma_cnt); + } + #endif + max_dma_cnt = free_queue_len; + } + + } + + DEBUG_TEST("%s: DMA RX: CBoardPtr=%i Driver=%i MaxDMA=%i\n", + card->devname,cur_dma_ptr,chan->rx_chain_indx,max_dma_cnt); + + for (i=0;irx_dma_chain_table[chan->rx_chain_indx]; + + /* If the current DMA chain is in use,then + * all chains are busy */ + if (wan_test_and_set_bit(0,&dma_chain->init)){ + DEBUG_TEST("%s: Warning: %s():%d dma chain busy %i!\n", + card->devname, __FUNCTION__, __LINE__, + dma_chain->index); + + err=-EBUSY; + break; + } + + dma_chain->skb=wan_skb_dequeue(&chan->wp_rx_free_list); + if (!dma_chain->skb){ + DEBUG_TEST("%s: Warning Rx chain = %i: no free rx bufs (RxComp=%i RxFree=%i)\n", + chan->if_name,dma_chain->index, + wan_skb_queue_len(&chan->wp_rx_complete_list), + wan_skb_queue_len(&chan->wp_rx_free_list)); + wan_clear_bit(0,&dma_chain->init); + err=-EINVAL; + break; + } + + dma_chain->dma_addr = + card->hw_iface.pci_map_dma(card->hw, + wan_skb_tail(dma_chain->skb), + chan->dma_mtu, + PCI_DMA_FROMDEVICE); + + dma_chain->dma_len = chan->dma_mtu; + + intr=0; + if (!wan_test_bit(RX_INTR_PENDING,&chan->dma_chain_status)){ + + free_queue_len--; + + if (free_queue_len <= 2){ + DEBUG_TEST("%s: DBG: Setting intr queue size low\n", + card->devname); + intr=1; + }else{ + if (chan->rx_chain_indx >= cur_dma_ptr){ + intr = ((MAX_AFT_DMA_CHAINS - + (chan->rx_chain_indx-cur_dma_ptr)) <=4); + }else{ + intr = ((cur_dma_ptr - chan->rx_chain_indx)<=4); + } + } + + if (intr){ + DEBUG_TEST("%s: Setting Rx interrupt on chain=%i\n", + chan->if_name,dma_chain->index); + wan_set_bit(RX_INTR_PENDING,&chan->dma_chain_status); + } + } + + DEBUG_TEST("%s: Setting Buffer on Rx Chain = %i Intr=%i\n", + chan->if_name,dma_chain->index, intr); + + err=aft_dma_chain_rx(dma_chain,chan,intr); + if (err){ + DEBUG_EVENT("%s: Rx dma chain %i overrun error: should never happen!\n", + chan->if_name,dma_chain->index); + aft_rx_dma_chain_init(chan,dma_chain); + chan->if_stats.rx_dropped++; + break; + } + + if (chan->single_dma_chain){ + break; + } + + if (++chan->rx_chain_indx >= MAX_AFT_DMA_CHAINS){ + chan->rx_chain_indx=0; + } + } + +te3_rx_skip: + + if (!chan->single_dma_chain){ + aft_enable_rx_watchdog(card,AFT_RX_TIMEOUT); + } + + wan_clear_bit(RX_DMA_BUSY,&chan->dma_status); + + return err; +} + +/*=============================================== + * aft_rx_dma_chain_handler + * + */ +//N1 +static void aft_rx_dma_chain_handler(private_area_t *chan, int wtd, int reset) +{ + sdla_t *card = chan->card; + u32 reg,dma_descr; + wp_rx_element_t *rx_el; + aft_dma_chain_t *dma_chain; + int i,max_dma_cnt, cur_dma_ptr; + + if (wan_test_and_set_bit(RX_HANDLER_BUSY,&chan->dma_status)){ + DEBUG_EVENT("%s: SMP Critical in %s\n", + chan->if_name,__FUNCTION__); + return; + } + + if (!wtd){ + /* Not watchdog, thus called from an interrupt. + * Clear the RX INTR Pending flag */ + wan_clear_bit(RX_INTR_PENDING,&chan->dma_chain_status); + } + + card->hw_iface.bus_read_4(card->hw,AFT_TE3_CRNT_DMA_DESC_ADDR_REG,®); + cur_dma_ptr=get_current_rx_dma_ptr(reg); + + if (cur_dma_ptr == chan->rx_pending_chain_indx){ + max_dma_cnt = MAX_AFT_DMA_CHAINS; + }else if (cur_dma_ptr > chan->rx_pending_chain_indx){ + max_dma_cnt = cur_dma_ptr-chan->rx_pending_chain_indx; + }else{ + max_dma_cnt = MAX_AFT_DMA_CHAINS - (chan->rx_pending_chain_indx-cur_dma_ptr); + } + + DEBUG_TEST("%s: DMA RX %s: CBoardPtr=%i Driver=%i MaxDMA=%i\n", + card->devname, + wtd?"WTD":"Intr", + cur_dma_ptr, + chan->rx_chain_indx,max_dma_cnt); + + for (i=0;irx_dma_chain_table[chan->rx_pending_chain_indx]; + if (!dma_chain){ + DEBUG_EVENT("%s:%d Assertion Error !!!!\n", + __FUNCTION__,__LINE__); + break; + } + + /* If the current DMA chain is in use,then + * all chains are busy */ + if (!wan_test_bit(0,&dma_chain->init)){ + DEBUG_TEST("%s: Warning (%s) Pending chain %i empty!\n", + chan->if_name,__FUNCTION__,dma_chain->index); + + break; + } + + dma_descr=(dma_chain->index<<4) + XILINX_RxDMA_DESCRIPTOR_HI; + card->hw_iface.bus_read_4(card->hw,dma_descr,®); + + /* If GO bit is set, then the current DMA chain + * is in process of being transmitted, thus + * all are busy */ + if (wan_test_bit(RxDMA_HI_DMA_GO_READY_BIT,®)){ + DEBUG_TEST("%s: Warning (%s) Pending chain %i Go bit still set!\n", + chan->if_name,__FUNCTION__,dma_chain->index); + break; + } + + card->hw_iface.pci_unmap_dma(card->hw, + dma_chain->dma_addr, + chan->dma_mtu, + PCI_DMA_FROMDEVICE); + + rx_el=(wp_rx_element_t *)wan_skb_push(dma_chain->skb, sizeof(wp_rx_element_t)); + memset(rx_el,0,sizeof(wp_rx_element_t)); + +#if 0 + chan->if_stats.rx_frame_errors++; +#endif + + /* Reading Rx DMA descriptor information */ + dma_descr=(dma_chain->index<<4) + XILINX_RxDMA_DESCRIPTOR_LO; + card->hw_iface.bus_read_4(card->hw,dma_descr, &rx_el->align); + rx_el->align&=RxDMA_LO_ALIGNMENT_BIT_MASK; + + dma_descr=(dma_chain->index<<4) + XILINX_RxDMA_DESCRIPTOR_HI; + card->hw_iface.bus_read_4(card->hw,dma_descr, &rx_el->reg); + + rx_el->pkt_error= dma_chain->pkt_error; + rx_el->dma_addr = dma_chain->dma_addr; + + wan_skb_queue_tail(&chan->wp_rx_complete_list,dma_chain->skb); + + DEBUG_RX("%s: RxInr Pending chain %i Rxlist=%i LO:0x%X HI:0x%X Data=0x%X Len=%i!\n", + chan->if_name,dma_chain->index, + wan_skb_queue_len(&chan->wp_rx_complete_list), + rx_el->align,rx_el->reg, + (*(unsigned char*)wan_skb_data(dma_chain->skb)), + wan_skb_len(dma_chain->skb)); + + dma_chain->skb=NULL; + dma_chain->dma_addr=0; + dma_chain->dma_len=0; + dma_chain->pkt_error=0; + wan_clear_bit(0,&dma_chain->init); + + + if (chan->single_dma_chain){ + break; + } + + if (++chan->rx_pending_chain_indx >= MAX_AFT_DMA_CHAINS){ + chan->rx_pending_chain_indx=0; + } + + } + + if (reset){ + goto reset_skip_rx_setup; + } + + xilinx_dma_rx(card,chan,cur_dma_ptr); + + if (wan_skb_queue_len(&chan->wp_rx_complete_list)){ + DEBUG_TEST("%s: Rx Queued list triggering\n",chan->if_name); + WAN_TASKLET_SCHEDULE((&chan->common.bh_task)); + chan->rx_no_data_cnt=0; + }else{ + if (!chan->single_dma_chain){ + if ((chan->rx_no_data_cnt >= 0) && (++chan->rx_no_data_cnt < 3)){ + aft_enable_rx_watchdog(card,AFT_RX_TIMEOUT); + }else{ + /* Enable Rx Interrupt on pending rx descriptor */ + DEBUG_TEST("%s: Setting Max Rx Watchdog Timeout\n", + chan->if_name); + aft_enable_rx_watchdog(card,AFT_MAX_WTD_TIMEOUT); + chan->rx_no_data_cnt=-1; + } + } + } + +reset_skip_rx_setup: + + wan_clear_bit(RX_HANDLER_BUSY,&chan->dma_status); + + + return; +} + +static void aft_index_tx_rx_dma_chains(private_area_t *chan) +{ + int i; + + for (i=0;itx_dma_chain_table[i].index=i; + chan->rx_dma_chain_table[i].index=i; + } +} + + +static void aft_init_tx_rx_dma_descr(private_area_t *chan) +{ + int i; + u32 reg=0; + sdla_t *card=chan->card; + unsigned int tx_dma_descr,rx_dma_descr; + unsigned int dma_cnt=MAX_AFT_DMA_CHAINS; + + if (chan->single_dma_chain){ + dma_cnt=1; + } + + + for (i=0;ihw_iface.bus_write_4(card->hw,tx_dma_descr,reg); + card->hw_iface.bus_write_4(card->hw,rx_dma_descr,reg); + + aft_tx_dma_chain_init(chan,&chan->tx_dma_chain_table[i]); + aft_tx_dma_chain_init(chan,&chan->rx_dma_chain_table[i]); + } +} + +#if 0 +static void aft_dma_te3_set_intr(aft_dma_chain_t *dma_chain, private_area_t *chan) +{ +#define dma_ch_indx dma_chain->index +#define card chan->card + + u32 reg=0; + u32 len; + u32 dma_descr; + + /* If the current DMA chain is in use,then + * all chains are busy */ + if (!wan_test_bit(0,&dma_chain->init)){ + DEBUG_EVENT("%s: (%s) Error: Pending chain %i empty!\n", + chan->if_name,__FUNCTION__,dma_chain->index); + return; + } + + dma_descr=(unsigned long)(dma_ch_indx<<4) + XILINX_RxDMA_DESCRIPTOR_HI; + + card->hw_iface.bus_read_4(card->hw,dma_descr,®); + + /* If GO bit is set, then the current DMA chain + * is in process of being Received, thus + * all are busy */ + if (!wan_test_bit(RxDMA_HI_DMA_GO_READY_BIT,®)){ + DEBUG_EVENT("%s: (%s) Error: Pending chain %i Go bit is not set!\n", + chan->if_name,__FUNCTION__,dma_chain->index); + return; + } + + len=reg&RxDMA_HI_DMA_DATA_LENGTH_MASK; + + DEBUG_TEST("%s: Set Rx Intr on 1st Pending Chain: index=%i Len=%i (dmalen=%i)\n", + chan->if_name,dma_ch_indx,len,dma_chain->dma_len); + + wan_clear_bit(DMA_HI_TE3_INTR_DISABLE_BIT,®); + + card->hw_iface.bus_write_4(card->hw,dma_descr,reg); + +#undef dma_ch_indx +#undef card +} +#endif + +/* + * ****************************************************************** + * Proc FS function + */ +static int wan_aft3_get_info(void* pcard, struct seq_file *m, int *stop_cnt) +{ + sdla_t *card = (sdla_t*)pcard; + + m->count = + WAN_FECALL(&card->wandev, update_alarm_info, (&card->fe, m, stop_cnt)); + m->count = + WAN_FECALL(&card->wandev, update_pmon_info, (&card->fe, m, stop_cnt)); + + return m->count; +} + + +static void aft_free_rx_complete_list(private_area_t *chan) +{ + void *skb; + while((skb=wan_skb_dequeue(&chan->wp_rx_complete_list)) != NULL){ + + chan->if_stats.rx_dropped++; + aft_init_requeue_free_skb(chan, skb); + } +} + +static void aft_list_descriptors(private_area_t *chan) +{ +#if 0 + u32 reg,cur_dma_ptr; + sdla_t *card=chan->card; + aft_dma_chain_t *dma_chain; + u32 dma_descr; + int i; + + card->hw_iface.bus_read_4(card->hw,AFT_TE3_CRNT_DMA_DESC_ADDR_REG,®); + cur_dma_ptr=get_current_rx_dma_ptr(reg); + + DEBUG_EVENT("%s: List Descritpors:\n",chan->if_name); + + DEBUG_EVENT("%s: Chain DMA Status=0x%lX, TxCur=%i, TxPend=%i RxCur=%i RxPend=%i HwCur=%i RC=%i RFree=%i\n", + chan->if_name, + chan->dma_chain_status, + chan->tx_chain_indx, + chan->tx_pending_chain_indx, + chan->rx_chain_indx, + chan->rx_pending_chain_indx, + cur_dma_ptr, + wan_skb_queue_len(&chan->wp_rx_complete_list), + wan_skb_queue_len(&chan->wp_rx_free_list)); + + + for (i=0;irx_dma_chain_table[i]; + if (!dma_chain){ + DEBUG_EVENT("%s:%d Assertion Error !!!!\n", + __FUNCTION__,__LINE__); + break; + } + + dma_descr=(dma_chain->index<<4) + XILINX_RxDMA_DESCRIPTOR_HI; + card->hw_iface.bus_read_4(card->hw,dma_descr,®); + + DEBUG_EVENT("%s: DMA=%i : Init=%li Go=%u Intr=%u Addr=%s Skb=%s\n", + chan->if_name, + dma_chain->index, + dma_chain->init, + wan_test_bit(RxDMA_HI_DMA_GO_READY_BIT,®), + wan_test_bit(DMA_HI_TE3_INTR_DISABLE_BIT,®), + dma_chain->dma_addr?"Yes":"No", + dma_chain->skb?"Yes":"No"); + } +#endif +} + +static void aft_list_tx_descriptors(private_area_t *chan) +{ +#if 1 + u32 reg,cur_dma_ptr,low,dma_ctrl; + sdla_t *card=chan->card; + aft_dma_chain_t *dma_chain; + u32 dma_descr; + int i; + + card->hw_iface.bus_read_4(card->hw,AFT_TE3_CRNT_DMA_DESC_ADDR_REG,®); + cur_dma_ptr=get_current_tx_dma_ptr(reg); + + card->hw_iface.bus_read_4(card->hw,XILINX_DMA_CONTROL_REG,&dma_ctrl); + + DEBUG_EVENT("%s: List TX Descritpors:\n",chan->if_name); + + DEBUG_EVENT("%s: Chain DMA Status=0x%lX, TxCur=%i, TxPend=%i HwCur=%i RP=%i RC=%i RFree=%i Ctrl=0x%X\n", + chan->if_name, + chan->dma_chain_status, + chan->tx_chain_indx, + chan->tx_pending_chain_indx, + cur_dma_ptr, + wan_skb_queue_len(&chan->wp_tx_pending_list), + wan_skb_queue_len(&chan->wp_tx_complete_list), + wan_skb_queue_len(&chan->wp_tx_free_list), + dma_ctrl); + + + for (i=0;itx_dma_chain_table[i]; + if (!dma_chain){ + DEBUG_EVENT("%s:%d Assertion Error !!!!\n", + __FUNCTION__,__LINE__); + break; + } + + dma_descr=(dma_chain->index<<4) + XILINX_TxDMA_DESCRIPTOR_HI; + card->hw_iface.bus_read_4(card->hw,dma_descr,®); + + dma_descr=(dma_chain->index<<4) + XILINX_TxDMA_DESCRIPTOR_LO; + card->hw_iface.bus_read_4(card->hw,dma_descr,&low); + + DEBUG_EVENT("%s: DMA=%i : Init=%lu Go=%u Intr=%u Addr=%s Skb=%s HI=0x%X LO=0x%X\n", + chan->if_name, + dma_chain->index, + dma_chain->init, + wan_test_bit(TxDMA_HI_DMA_GO_READY_BIT,®), + wan_test_bit(DMA_HI_TE3_INTR_DISABLE_BIT,®), + dma_chain->dma_addr?"Yes":"No", + dma_chain->skb?"Yes":"No", + reg,low); + } +#endif +} + + +static void aft_free_rx_descriptors(private_area_t *chan) +{ + u32 reg; + sdla_t *card=chan->card; + aft_dma_chain_t *dma_chain; + u32 dma_descr; + int i; + + for (i=0;irx_dma_chain_table[i]; + if (!dma_chain){ + DEBUG_EVENT("%s:%d Assertion Error !!!!\n", + __FUNCTION__,__LINE__); + break; + } + + /* If the current DMA chain is in use,then + * all chains are busy */ + if (!wan_test_bit(0,&dma_chain->init)){ + continue; + } + + dma_descr=(dma_chain->index<<4) + XILINX_RxDMA_DESCRIPTOR_HI; + card->hw_iface.bus_read_4(card->hw,dma_descr,®); + + /* If GO bit is set, then the current DMA chain + * is in process of being transmitted, thus + * all are busy */ + reg=0; + card->hw_iface.bus_write_4(card->hw,dma_descr,reg); + + card->hw_iface.pci_unmap_dma(card->hw, + dma_chain->dma_addr, + chan->dma_mtu, + PCI_DMA_FROMDEVICE); + + aft_init_requeue_free_skb(chan, dma_chain->skb); + + dma_chain->skb=NULL; + dma_chain->dma_addr=0; + dma_chain->dma_len=0; + dma_chain->pkt_error=0; + wan_clear_bit(0,&dma_chain->init); + } + + chan->rx_pending_chain_indx = chan->rx_chain_indx; + +} + +static void aft_reset_tx_chain_cnt(private_area_t *chan) +{ + u32 reg,cur_dma_ptr; + sdla_t *card=chan->card; + card->hw_iface.bus_read_4(card->hw,AFT_TE3_CRNT_DMA_DESC_ADDR_REG,®); + + if (chan->single_dma_chain){ + set_current_tx_dma_ptr(®,0); + cur_dma_ptr=0; + }else{ + cur_dma_ptr=get_current_tx_dma_ptr(reg); + } + + chan->tx_pending_chain_indx = chan->tx_chain_indx = cur_dma_ptr; + return; +} + +static void aft_free_tx_descriptors(private_area_t *chan) +{ + u32 reg; + sdla_t *card=chan->card; + aft_dma_chain_t *dma_chain; + u32 dma_descr; + int i; + void *skb; + unsigned int dma_cnt=MAX_AFT_DMA_CHAINS; + + DEBUG_TEST("%s:%s: Tx: Freeing Descripors\n",card->devname,chan->if_name); + + wan_clear_bit(TX_INTR_PENDING,&chan->dma_chain_status); + wan_clear_bit(TX_DMA_BUSY,&chan->dma_status); + + for (i=0;itx_dma_chain_table[i]; + if (!dma_chain){ + DEBUG_EVENT("%s:%d Assertion Error !!!!\n", + __FUNCTION__,__LINE__); + break; + } + + dma_descr=(dma_chain->index<<4) + XILINX_TxDMA_DESCRIPTOR_HI; + reg=0; + card->hw_iface.bus_write_4(card->hw,dma_descr,reg); + + aft_tx_dma_chain_init(chan, dma_chain); + } + + chan->tx_chain_indx = chan->tx_pending_chain_indx; + + aft_reset_tx_chain_cnt(chan); + + while((skb=wan_skb_dequeue(&chan->wp_tx_complete_list)) != NULL){ + wan_skb_free(skb); + } +} + + + +static void aft_te3_led_ctrl(sdla_t *card, int color, int led_pos, int on) +{ + u32 reg; + card->hw_iface.bus_read_4(card->hw,TE3_LOCAL_CONTROL_STATUS_REG,®); + aft_te3_set_led(color, led_pos, on, ®); + card->hw_iface.bus_write_4(card->hw,TE3_LOCAL_CONTROL_STATUS_REG,reg); +} + + +static void __aft_fe_intr_ctrl(sdla_t *card, int status) +{ + u32 reg; + + card->hw_iface.bus_read_4(card->hw,XILINX_CHIP_CFG_REG,®); + if (status){ + wan_set_bit(FRONT_END_INTR_ENABLE_BIT,®); + }else{ + wan_clear_bit(FRONT_END_INTR_ENABLE_BIT,®); + } + card->hw_iface.bus_write_4(card->hw,XILINX_CHIP_CFG_REG,reg); +} + +static void aft_fe_intr_ctrl(sdla_t *card, int status) +{ + wan_smp_flag_t smp_flags; + + wan_spin_lock_irq(&card->wandev.lock,&smp_flags); + __aft_fe_intr_ctrl(card, status); + wan_spin_unlock_irq(&card->wandev.lock,&smp_flags); +} + + +#if defined(__LINUX__) +static void aft_port_task (void * card_ptr) +#else +static void aft_port_task (void * card_ptr, int arg) +#endif +{ + sdla_t *card = (sdla_t *)card_ptr; + wan_smp_flag_t smp_flags,isr_flags; + + if (wan_test_bit(CARD_DOWN,&card->wandev.critical)){ + return; + } + + DEBUG_TEST("%s: AFT PORT TASK CMD=0x%X!\n", + card->devname,card->u.aft.port_task_cmd); + + if (wan_test_bit(AFT_FE_INTR,&card->u.aft.port_task_cmd)){ + card->hw_iface.hw_lock(card->hw,&smp_flags); + + aft_fe_intr_ctrl(card, 0); + wan_spin_lock_irq(&card->wandev.lock,&isr_flags); + front_end_interrupt(card,0); + wan_spin_unlock_irq(&card->wandev.lock,&isr_flags); + aft_fe_intr_ctrl(card, 1); + + wan_clear_bit(AFT_FE_INTR,&card->u.aft.port_task_cmd); + card->hw_iface.hw_unlock(card->hw,&smp_flags); + } + + if (wan_test_bit(AFT_FE_POLL,&card->u.aft.port_task_cmd)){ + card->hw_iface.hw_lock(card->hw,&smp_flags); + + aft_fe_intr_ctrl(card, 0); + wan_spin_lock_irq(&card->wandev.lock,&isr_flags); + WAN_FECALL(&card->wandev, polling, (&card->fe)); + wan_spin_unlock_irq(&card->wandev.lock,&isr_flags); + aft_fe_intr_ctrl(card, 1); + + wan_clear_bit(AFT_FE_POLL,&card->u.aft.port_task_cmd); + card->hw_iface.hw_unlock(card->hw,&smp_flags); + } +} + +#if 0 +static int aft_hdlc_core_ready(sdla_t *card) +{ + u32 reg; + int i,err=1; + + for (i=0;i<5;i++){ + card->hw_iface.bus_read_4(card->hw,XILINX_CHIP_CFG_REG, ®); + + if (!wan_test_bit(HDLC_CORE_READY_FLAG_BIT,®)){ + WP_DELAY(500); + }else{ + err=0; + break; + } + } + + if (err){ + DEBUG_EVENT("%s: Critical Error: HDLC Core not ready!\n", + card->devname); + } + return err; +} +#endif +/****** End ****************************************************************/ diff -Nur linux.org/drivers/net/wan/sdla_aft_te3.orig.c linux-2.6.17/drivers/net/wan/sdla_aft_te3.orig.c --- linux.org/drivers/net/wan/sdla_aft_te3.orig.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/drivers/net/wan/sdla_aft_te3.orig.c 2006-08-30 10:07:16.000000000 +0000 @@ -0,0 +1,5645 @@ +/***************************************************************************** +* sdla_aft_te3.c WANPIPE(tm) AFT Xilinx Hardware Support +* +* Authors: Nenad Corbic +* +* Copyright: (c) 2003 Sangoma Technologies Inc. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version +* 2 of the License, or (at your option) any later version. +* ============================================================================ +* Jan 07, 2003 Nenad Corbic Initial version. +*****************************************************************************/ + +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) +# include +# include +# include +# include /* Socket Driver common area */ +# include +# include +# include +#else +# include +# include +# include +# include +# include +# include /* Socket Driver common area */ +# include +# include +# include +# if defined(CONFIG_PRODUCT_WANPIPE_GENERIC) +# include +# endif +#endif + +//#define XILINX_A010 1 + +/****** Defines & Macros ****************************************************/ + +/* Private critical flags */ +enum { + POLL_CRIT = PRIV_CRIT, + CARD_DOWN +}; + +enum { + LINK_DOWN, + DEVICE_DOWN +}; + +enum { + TX_DMA_BUSY, + TX_HANDLER_BUSY, + TX_INTR_PENDING, + TX_DATA_READY, + + RX_HANDLER_BUSY, + RX_DMA_BUSY, + RX_INTR_PENDING, + RX_DATA_READY, + + RX_WTD_SKIP, +}; + +enum { + AFT_FE_CFG_ERR, + AFT_FE_CFG, + AFT_FE_INTR, + AFT_FE_POLL + +}; + +#define MAX_IP_ERRORS 10 + +#define PORT(x) (x == 0 ? "PRIMARY" : "SECONDARY" ) + +#undef DEB_XILINX + +#if 0 +# define AFT_XTEST_DEBUG 1 +#else +# undef AFT_XTEST_DEBUG +#endif + +#if 1 +# define TRUE_FIFO_SIZE 1 +#else +# undef TRUE_FIFO_SIZE +# define HARD_FIFO_CODE 0x01 +#endif + +#define MAX_AFT_DMA_CHAINS 16 +#define MAX_TX_BUF MAX_AFT_DMA_CHAINS+1 +#define MAX_RX_BUF MAX_AFT_DMA_CHAINS*4+1 + +#define AFT_MAX_CHIP_SECURITY_CNT 100 +/* Remove HDLC Address + * 1=Remove Enabled + * 0=Remove Disabled + */ + +static int aft_rx_copyback=500; + +/******Data Structures*****************************************************/ + +/* This structure is placed in the private data area of the device structure. + * The card structure used to occupy the private area but now the following + * structure will incorporate the card structure along with Protocol specific data + */ + +typedef struct aft_dma_chain +{ + unsigned long init; + u32 dma_addr; + u32 dma_len; + struct sk_buff *skb; + u32 index; + + u32 dma_descr; + u32 len_align; + u32 reg; + + u8 pkt_error; +}aft_dma_chain_t; + +typedef struct private_area +{ + wanpipe_common_t common; + sdla_t *card; + struct net_device *dev; + + struct sk_buff_head wp_tx_free_list; + struct sk_buff_head wp_tx_pending_list; + struct sk_buff_head wp_tx_complete_list; + struct sk_buff *tx_dma_skb; + u8 tx_dma_cnt; + + struct sk_buff_head wp_rx_free_list; + struct sk_buff_head wp_rx_complete_list; + + unsigned long time_slot_map; + unsigned char num_of_time_slots; + long logic_ch_num; + + unsigned char hdlc_eng; + unsigned long dma_status; + unsigned char protocol; + unsigned char ignore_modem; + + struct net_device_stats if_stats; + +#if 1 + int tracing_enabled; /* For enabling Tracing */ + unsigned long router_start_time; + unsigned long trace_timeout; + + unsigned char route_status; + unsigned char route_removed; + unsigned long tick_counter; /* For 5s timeout counter */ + unsigned long router_up_time; + + unsigned char mc; /* Mulitcast support on/off */ + unsigned char udp_pkt_src; /* udp packet processing */ + unsigned short timer_int_enabled; + + unsigned char interface_down; + + /* Polling task queue. Each interface + * has its own task queue, which is used + * to defer events from the interrupt */ + struct tq_struct poll_task; + struct timer_list poll_delay_timer; + + u8 gateway; + u8 true_if_encoding; + + //FIXME: add driver stats as per frame relay! +#endif + + /* Entry in proc fs per each interface */ + struct proc_dir_entry *dent; + + unsigned char udp_pkt_data[sizeof(wan_udp_pkt_t)+10]; + atomic_t udp_pkt_len; + + char if_name[WAN_IFNAME_SZ+1]; + + u8 idle_flag; + u16 max_idle_size; + u8 idle_start; + + u8 pkt_error; + u8 rx_fifo_err_cnt; + + int first_time_slot; + + struct sk_buff *tx_idle_skb; + unsigned char rx_dma; + unsigned char pci_retry; + + unsigned char fifo_size_code; + unsigned char fifo_base_addr; + unsigned char fifo_size; + + int dma_mtu; + + void * prot_ch; + int prot_state; + + wan_trace_t trace_info; + + /* TE3 Specific Dma Chains */ + unsigned char tx_chain_indx,tx_pending_chain_indx; + aft_dma_chain_t tx_dma_chain_table[MAX_AFT_DMA_CHAINS]; + + unsigned char rx_chain_indx, rx_pending_chain_indx; + aft_dma_chain_t rx_dma_chain_table[MAX_AFT_DMA_CHAINS]; + int rx_no_data_cnt; + + unsigned long dma_chain_status; + unsigned long up; + + unsigned char *tx_realign_buf; + +}private_area_t; + +/* Route Status options */ +#define NO_ROUTE 0x00 +#define ADD_ROUTE 0x01 +#define ROUTE_ADDED 0x02 +#define REMOVE_ROUTE 0x03 + +#define WP_WAIT 0 +#define WP_NO_WAIT 1 + +/* variable for keeping track of enabling/disabling FT1 monitor status */ +//static int rCount; + +extern void disable_irq(unsigned int); +extern void enable_irq(unsigned int); + +/**SECTOIN************************************************** + * + * Function Prototypes + * + ***********************************************************/ + +/* WAN link driver entry points. These are called by the WAN router module. */ +static int update (wan_device_t* wandev); +static int new_if (wan_device_t* wandev, struct net_device* dev, wanif_conf_t* conf); +static int del_if(wan_device_t *wandev, struct net_device *dev); + +/* Network device interface */ +static int if_init (struct net_device* dev); +static int if_open (struct net_device* dev); +static int if_close (struct net_device* dev); +static int if_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); + +static struct net_device_stats* if_stats (struct net_device* dev); + +static int if_send (struct sk_buff* skb, struct net_device* dev); + +static void handle_front_end_state(void* card_id); +static void enable_timer(void* card_id); +static void if_tx_timeout (struct net_device *dev); + +/* Miscellaneous Functions */ +static void port_set_state (sdla_t *card, int); + +static void disable_comm (sdla_t *card); + +/* Interrupt handlers */ +static void wp_aft_te3_isr (sdla_t* card); + +/* Bottom half handlers */ +static void wp_bh (unsigned long); + +/* Miscellaneous functions */ +static int process_udp_mgmt_pkt(sdla_t* card, struct net_device* dev, + private_area_t*, + int local_dev); + +static int xilinx_t3_exar_chip_configure(sdla_t *card); +static int xilinx_t3_exar_dev_configure(sdla_t *card, private_area_t *chan); +static void xilinx_t3_exar_dev_unconfigure(sdla_t *card, private_area_t *chan); +static void xilinx_t3_exar_chip_unconfigure(sdla_t *card); +static void xilinx_t3_exar_transparent_config(sdla_t *card,private_area_t *chan); + +static int xilinx_dma_rx(sdla_t *card, private_area_t *chan, int gcur_ptr); +static void xilinx_dev_enable(sdla_t *card, private_area_t *chan); +static void xilinx_dev_close(sdla_t *card, private_area_t *chan); +static void xilinx_dma_tx_complete (sdla_t *card, private_area_t *chan,int wtd); +static void xilinx_dma_rx_complete (sdla_t *card, private_area_t *chan, int wtd); +static int xilinx_init_rx_dev_fifo(sdla_t *card, private_area_t *chan, unsigned char); +static void xilinx_init_tx_dma_descr(sdla_t *card, private_area_t *chan); +static int xilinx_init_tx_dev_fifo(sdla_t *card, private_area_t *chan, unsigned char); +static void xilinx_tx_post_complete (sdla_t *card, private_area_t *chan, struct sk_buff *skb); +static void xilinx_rx_post_complete (sdla_t *card, private_area_t *chan, + struct sk_buff *skb, + struct sk_buff **new_skb, + unsigned char *pkt_error); + + + + +#if 0 +//FIXME: Not used check with M.F. if still needed +static unsigned char read_cpld(sdla_t *card, unsigned short cpld_off); +#endif +static int write_cpld(void *pcard, unsigned short cpld_off,unsigned char cpld_data); + +static int aft_devel_ioctl(sdla_t *card,struct ifreq *ifr); +static int xilinx_write_bios(sdla_t *card, wan_cmd_api_t *api_cmd); +static int xilinx_write(sdla_t *card, wan_cmd_api_t *api_cmd); +static int xilinx_read(sdla_t *card, wan_cmd_api_t *api_cmd); + +static void front_end_interrupt(sdla_t *card, unsigned long reg); +static void enable_data_error_intr(sdla_t *card); +static void disable_data_error_intr(sdla_t *card, unsigned char); + +static void xilinx_tx_fifo_under_recover (sdla_t *card, private_area_t *chan); + +static int xilinx_write_ctrl_hdlc(sdla_t *card, u32 timeslot, u8 reg_off, u32 data); + +static int set_chan_state(sdla_t* card, netdevice_t* dev, int state); + +static int update_comms_stats(sdla_t* card); + +static int protocol_init (sdla_t*card,netdevice_t *dev, + private_area_t *chan, wanif_conf_t* conf); +static int protocol_stop (sdla_t *card, netdevice_t *dev); +static int protocol_start (sdla_t *card, netdevice_t *dev); +static int protocol_shutdown (sdla_t *card, netdevice_t *dev); +static void protocol_recv(sdla_t *card, private_area_t *chan, struct sk_buff *skb); + +static int aft_alloc_rx_dma_buff(sdla_t *card, private_area_t *chan, int num); +static int aft_init_requeue_free_skb(private_area_t *chan, struct sk_buff *skb); + +static int write_framer(void *pcard,unsigned short framer_off,unsigned short framer_data); +static unsigned int read_framer(void *pcard,unsigned short framer_off); +#if 0 +//FIXME to be taken out check with M.F. +static void framer_reset(sdla_t *card); +#endif + +static int xilinx_dma_te3_tx (sdla_t *card,private_area_t *chan,struct sk_buff *skb); +static void aft_tx_dma_chain_handler(unsigned long data); +static void aft_tx_dma_chain_init(private_area_t *chan, aft_dma_chain_t *); +static void aft_rx_dma_chain_init(private_area_t *chan, aft_dma_chain_t *); +static void aft_index_tx_rx_dma_chains(private_area_t *chan); +static void aft_rx_dma_chain_handler(private_area_t *chan, int wtd, int reset); +#if 0 +//FIXME: Currently not used... +static void aft_dma_te3_set_intr(aft_dma_chain_t *dma_chain, private_area_t *chan); +#endif +static void aft_init_tx_rx_dma_descr(private_area_t *chan); +static void aft_pending_tx(sdla_t *card, private_area_t *chan); +static void aft_free_rx_complete_list(private_area_t *chan); +static void aft_list_descriptors(private_area_t *chan); +static void aft_free_rx_descriptors(private_area_t *chan); +static void aft_te3_led_ctrl(sdla_t *card, int color, int led_pos, int on); +static void aft_list_tx_descriptors(private_area_t *chan); +static void aft_free_tx_descriptors(private_area_t *chan); + +#if defined(__LINUX__) +static void aft_port_task (void * card_ptr); +#else +static void aft_port_task (void * card_ptr, int arg); +#endif +static void aft_fe_intr_ctrl(sdla_t *card, int status); +static void __aft_fe_intr_ctrl(sdla_t *card, int status); + + +/* TE1 Control registers */ +//static WRITE_FRONT_END_REG_T write_front_end_reg; +//static READ_FRONT_END_REG_T read_front_end_reg; + +/* Procfs functions */ +static int wan_aft3_get_info(void* pcard, struct seq_file* m, int* stop_cnt); + +static void xilinx_delay(int sec) +{ +#if 0 + unsigned long timeout=jiffies; + while ((jiffies-timeout)<(sec*HZ)){ + schedule(); + } +#endif +} + +/**SECTION********************************************************* + * + * Public Functions + * + ******************************************************************/ + +int wp_aft_te3_default_devcfg(sdla_t* card, wandev_conf_t* conf) +{ + conf->config_id = WANCONFIG_AFT_TE3; + conf->u.xilinx.dma_per_ch = MAX_RX_BUF; + conf->u.xilinx.mru = 1500; + return 0; +} + +int wp_aft_te3_default_ifcfg(sdla_t* card, wanif_conf_t* conf) +{ + conf->protocol = WANCONFIG_HDLC; + memcpy(conf->usedby, "WANPIPE", 7); + conf->if_down = 0; + conf->ignore_dcd = WANOPT_NO; + conf->ignore_cts = WANOPT_NO; + conf->hdlc_streaming = WANOPT_NO; + conf->mc = 0; + conf->gateway = 0; + conf->active_ch = ENABLE_ALL_CHANNELS; + + return 0; +} + +/*============================================================================ + * wp_xilinx_init - Cisco HDLC protocol initialization routine. + * + * @card: Wanpipe card pointer + * @conf: User hardware/firmware/general protocol configuration + * pointer. + * + * This routine is called by the main WANPIPE module + * during setup: ROUTER_SETUP ioctl(). + * + * At this point adapter is completely initialized + * and firmware is running. + * o read firmware version (to make sure it's alive) + * o configure adapter + * o initialize protocol-specific fields of the adapter data space. + * + * Return: 0 o.k. + * < 0 failure. + */ + +int wp_aft_te3_init (sdla_t* card, wandev_conf_t* conf) +{ + int err; + + /* Verify configuration ID */ + wan_clear_bit(CARD_DOWN,&card->wandev.critical); + if (card->wandev.config_id != WANCONFIG_AFT_TE3) { + DEBUG_EVENT( "%s: invalid configuration ID %u!\n", + card->devname, card->wandev.config_id); + return -EINVAL; + } + + if (conf == NULL){ + DEBUG_EVENT("%s: Bad configuration structre!\n", + card->devname); + return -EINVAL; + } + +#if defined(WAN_DEBUG_MEM) + DEBUG_EVENT("%s: Total Mem %d\n",__FUNCTION__,wan_atomic_read(&wan_debug_mem)); +#endif + + + /* Obtain hardware configuration parameters */ + card->wandev.clocking = conf->clocking; + card->wandev.ignore_front_end_status = conf->ignore_front_end_status; + card->wandev.ttl = conf->ttl; + card->wandev.interface = conf->interface; + card->wandev.comm_port = conf->comm_port; + card->wandev.udp_port = conf->udp_port; + card->wandev.new_if_cnt = 0; + wan_atomic_set(&card->wandev.if_cnt,0); + card->u.aft.chip_security_cnt=0; + + memcpy(&card->u.xilinx.cfg,&conf->u.xilinx,sizeof(wan_xilinx_conf_t)); + + card->u.xilinx.cfg.dma_per_ch = MAX_RX_BUF; + + /* TE1 Make special hardware initialization for T1/E1 board */ + if (IS_TE3(&conf->fe_cfg)){ + + memcpy(&card->fe.fe_cfg, &conf->fe_cfg, sizeof(sdla_fe_cfg_t)); + card->fe.name = card->devname; + card->fe.card = card; + card->fe.write_cpld = write_cpld; +// card->fe.read_cpld = read_cpld; + card->fe.write_framer = write_framer; + card->fe.read_framer = read_framer; + +// card->wandev.write_front_end_reg = write_front_end_reg; +// card->wandev.read_front_end_reg = read_front_end_reg; + card->wandev.te_enable_timer = enable_timer; + card->wandev.te_link_state = handle_front_end_state; +//ALEX conf->interface = +// IS_T1_CARD(card) ? WANOPT_V35 : WANOPT_RS232; + + if (card->wandev.comm_port == WANOPT_PRI){ + conf->clocking = WANOPT_EXTERNAL; + } + + }else{ + DEBUG_EVENT("%s: Invalid Front-End media type!!\n", + card->devname); + return -EINVAL; + } + + if (card->wandev.ignore_front_end_status == WANOPT_NO){ + DEBUG_EVENT( + "%s: Enabling front end link monitor\n", + card->devname); + }else{ + DEBUG_EVENT( + "%s: Disabling front end link monitor\n", + card->devname); + } + + /* WARNING: After this point the init function + * must return with 0. The following bind + * functions will cause problems if structures + * below are not initialized */ + + card->wandev.update = &update; + card->wandev.new_if = &new_if; + card->wandev.del_if = &del_if; + card->disable_comm = &disable_comm; + +#ifdef WANPIPE_ENABLE_PROC_FILE_HOOKS + /* Proc fs functions hooks */ + card->wandev.get_config_info = &get_config_info; + card->wandev.get_status_info = &get_status_info; + card->wandev.get_dev_config_info= &get_dev_config_info; + card->wandev.get_if_info = &get_if_info; + card->wandev.set_dev_config = &set_dev_config; + card->wandev.set_if_info = &set_if_info; +#endif + card->wandev.get_info = &wan_aft3_get_info; + + /* Setup Port Bps */ + if(card->wandev.clocking) { + card->wandev.bps = conf->bps; + }else{ + card->wandev.bps = 0; + } + + /* For Primary Port 0 */ +#ifdef CONFIG_PRODUCT_WANPIPE_TDM_VOICE + card->wandev.mtu = conf->mtu; +#else + card->wandev.mtu = + (conf->mtu >= MIN_WP_PRI_MTU) ? + wp_min(conf->mtu, MAX_WP_PRI_MTU) : DEFAULT_WP_PRI_MTU; +#endif + + + if (!card->u.xilinx.cfg.mru){ + card->u.xilinx.cfg.mru = card->wandev.mtu; + } + + + DEBUG_TEST("%s: Set MTU size to %d!\n", + card->devname, card->wandev.mtu); + + card->hw_iface.getcfg(card->hw, SDLA_BASEADDR, &card->u.xilinx.bar); + + xilinx_delay(1); + port_set_state(card,WAN_DISCONNECTED); + aft_te3_led_ctrl(card, WAN_AFT_RED, 0,WAN_AFT_ON); + aft_te3_led_ctrl(card, WAN_AFT_GREEN, 0, WAN_AFT_OFF); + + WAN_TASKQ_INIT((&card->u.aft.port_task),0,aft_port_task,card); + + + err=xilinx_t3_exar_chip_configure(card); + if (err){ + return err; + } + card->isr = &wp_aft_te3_isr; + + xilinx_delay(1); + + /* Set protocol link state to disconnected, + * After seting the state to DISCONNECTED this + * function must return 0 i.e. success */ + + DEBUG_EVENT( "%s: Init Done.\n",card->devname); + return 0; +} + + + + +/**SECTION************************************************************** + * + * WANPIPE Device Driver Entry Points + * + * *********************************************************************/ + + + +/*============================================================================ + * update - Update wanpipe device status & statistics + * + * @wandev: Wanpipe device pointer + * + * This procedure is called when updating the PROC file system. + * It returns various communications statistics. + * + * cat /proc/net/wanrouter/wanpipe# (where #=1,2,3...) + * + * These statistics are accumulated from 3 + * different locations: + * 1) The 'if_stats' recorded for the device. + * 2) Communication error statistics on the adapter. + * 3) Operational statistics on the adapter. + * + * The board level statistics are read during a timer interrupt. + * Note that we read the error and operational statistics + * during consecitive timer ticks so as to minimize the time + * that we are inside the interrupt handler. + * + */ +static int update (wan_device_t* wandev) +{ + sdla_t* card = wandev->private; + struct net_device* dev; + volatile private_area_t* chan; + + /* sanity checks */ + if((wandev == NULL) || (wandev->private == NULL)) + return -EFAULT; + + if(wandev->state == WAN_UNCONFIGURED) + return -ENODEV; + + if(wan_test_bit(PERI_CRIT, (void*)&card->wandev.critical)) + return -EAGAIN; + + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + if(dev == NULL) + return -ENODEV; + + if((chan=dev->priv) == NULL) + return -ENODEV; + + if(card->update_comms_stats){ + return -EAGAIN; + } + + DEBUG_TEST("%s: Chain Dma Status=0x%lX, TxCur=%i, TxPend=%i RxCur=%i RxPend=%i\n", + chan->if_name, + chan->dma_chain_status, + chan->tx_chain_indx, + chan->tx_pending_chain_indx, + chan->rx_chain_indx, + chan->rx_pending_chain_indx); + + + update_comms_stats(card); + + return 0; +} + + + +/*============================================================================ + * new_if - Create new logical channel. + * + * &wandev: Wanpipe device pointer + * &dev: Network device pointer + * &conf: User configuration options pointer + * + * This routine is called by the ROUTER_IFNEW ioctl, + * in wanmain.c. The ioctl passes us the user configuration + * options which we use to configure the driver and + * firmware. + * + * This functions main purpose is to allocate the + * private structure for protocol and bind it + * to dev->priv pointer. + * + * Also the dev->init pointer should also be initialized + * to the if_init() function. + * + * Any allocation necessary for the private strucutre + * should be done here, as well as proc/ file initializetion + * for the network interface. + * + * o parse media- and hardware-specific configuration + * o make sure that a new channel can be created + * o allocate resources, if necessary + * o prepare network device structure for registaration. + * o add network interface to the /proc/net/wanrouter + * + * The opposite of this function is del_if() + * + * Return: 0 o.k. + * < 0 failure (channel will not be created) + */ +static int new_if (wan_device_t* wandev, struct net_device* dev, wanif_conf_t* conf) +{ + sdla_t* card = wandev->private; + private_area_t* chan; + int err = 0; + struct sk_buff *skb; + + DEBUG_EVENT( "%s: Configuring Interface: %s\n", + card->devname, dev->name); + + if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)){ + DEBUG_EVENT( "%s: Invalid interface name!\n", + card->devname); + return -EINVAL; + } + + /* allocate and initialize private data */ + chan = wan_malloc(sizeof(private_area_t)); + if(chan == NULL){ + WAN_MEM_ASSERT(card->devname); + return -ENOMEM; + } + memset(chan, 0, sizeof(private_area_t)); + + chan->first_time_slot=-1; + + strncpy(chan->if_name, dev->name, WAN_IFNAME_SZ); + + chan->card = card; + + skb_queue_head_init(&chan->wp_tx_free_list); + skb_queue_head_init(&chan->wp_tx_pending_list); + skb_queue_head_init(&chan->wp_tx_complete_list); + + skb_queue_head_init(&chan->wp_rx_free_list); + skb_queue_head_init(&chan->wp_rx_complete_list); + + wan_trace_info_init(&chan->trace_info,MAX_TRACE_QUEUE); + + /* Initiaize Tx/Rx DMA Chains */ + aft_index_tx_rx_dma_chains(chan); + + /* Initialize the socket binding information + * These hooks are used by the API sockets to + * bind into the network interface */ + + WAN_TASKLET_INIT((&chan->common.bh_task),0,wp_bh,(unsigned long)chan); + chan->common.dev = dev; + chan->tracing_enabled = 0; + chan->route_status = NO_ROUTE; + chan->route_removed = 0; + + /* Setup interface as: + * WANPIPE = IP over Protocol (Firmware) + * API = Raw Socket access to Protocol (Firmware) + * BRIDGE = Ethernet over Protocol, no ip info + * BRIDGE_NODE = Ethernet over Protocol, with ip info + */ + if(strcmp(conf->usedby, "WANPIPE") == 0) { + + DEBUG_EVENT( "%s: Running in WANPIPE mode\n", + wandev->name); + chan->common.usedby = WANPIPE; + + /* Option to bring down the interface when + * the link goes down */ + if (conf->if_down){ + wan_set_bit(DYN_OPT_ON,&chan->interface_down); + DEBUG_EVENT( + "%s:%s: Dynamic interface configuration enabled\n", + card->devname,chan->if_name); + } + + if (conf->protocol != WANOPT_NO){ + dev->priv=chan; + if ((err=protocol_init(card,dev,chan,conf)) != 0){ + dev->priv=NULL; + goto new_if_error; + } + + if (conf->ignore_dcd == WANOPT_YES || conf->ignore_cts == WANOPT_YES){ + DEBUG_EVENT( "%s: Ignore modem changes DCD/CTS\n",card->devname); + chan->ignore_modem=1; + }else{ + DEBUG_EVENT( "%s: Restart protocol on modem changes DCD/CTS\n", + card->devname); + } + } + + } else if( strcmp(conf->usedby, "API") == 0) { + chan->common.usedby = API; + DEBUG_EVENT( "%s:%s: Running in API mode\n", + wandev->name,chan->if_name); + wan_reg_api(chan, dev, card->devname); + + }else if (strcmp(conf->usedby, "BRIDGE") == 0) { + chan->common.usedby = BRIDGE; + DEBUG_EVENT( "%s:%s: Running in WANPIPE (BRIDGE) mode.\n", + card->devname,chan->if_name); + + }else if (strcmp(conf->usedby, "BRIDGE_N") == 0) { + chan->common.usedby = BRIDGE_NODE; + DEBUG_EVENT( "%s:%s: Running in WANPIPE (BRIDGE_NODE) mode.\n", + card->devname,chan->if_name); + + }else if (strcmp(conf->usedby, "TDM_VOICE") == 0) { + chan->common.usedby = TDM_VOICE; + DEBUG_EVENT( "%s:%s: Running in TDM Voice mode.\n", + card->devname,chan->if_name); + + }else if (strcmp(conf->usedby, "STACK") == 0) { + chan->common.usedby = STACK; + if (chan->hdlc_eng){ + card->wandev.mtu+=32; + } + DEBUG_EVENT( "%s:%s: Running in Stack mode.\n", + card->devname,chan->if_name); + + + }else{ + DEBUG_EVENT( "%s:%s: Error: Invalid operation mode [WANPIPE|API|BRIDGE|BRIDGE_NODE]\n", + card->devname,chan->if_name); + err=-EINVAL; + goto new_if_error; + } + +#ifdef CONFIG_PRODUCT_WANPIPE_TDM_VOICE + if (chan->common.usedby == TDM_VOICE){ + //card->wandev.mtu = wp_tdmv_check_mtu(card, conf->active_ch); + WAN_TDMV_CALL(check_mtu,(card, conf->active_ch, &card->wandev.mtu),err); + if (err){ + err = -EINVAL; + goto new_if_error; + } + //if (wp_tdmv_init(card, conf)){ + WAN_TDMV_CALL(init, (card, conf), err); + if (err){ + err = -EINVAL; + goto new_if_error; + } + } +#endif + + xilinx_delay(1); + + chan->hdlc_eng = conf->hdlc_streaming; + + if (!chan->hdlc_eng){ + if (card->wandev.mtu&0x03){ + DEBUG_EVENT("%s:%s: Error, Transparent MTU must be word aligned!\n", + card->devname,chan->if_name); + err = -EINVAL; + goto new_if_error; + } + } + chan->time_slot_map=conf->active_ch; + + err=xilinx_t3_exar_dev_configure(card,chan); + if (err){ + goto new_if_error; + } + + xilinx_delay(1); + + + if (!chan->hdlc_eng){ + unsigned char *buf; + + if (!chan->max_idle_size){ + chan->max_idle_size=card->wandev.mtu; + } + + DEBUG_EVENT("%s:%s: Config for Transparent mode: Idle=%X Len=%u\n", + card->devname,chan->if_name, + chan->idle_flag,chan->max_idle_size); + + chan->idle_flag=0x7E; + +#ifdef CONFIG_PRODUCT_WANPIPE_TDM_VOICE + if (chan->common.usedby == TDM_VOICE){ + chan->idle_flag = WAN_TDMV_IDLE_FLAG; + } +#endif + + chan->tx_idle_skb = wan_skb_alloc(chan->max_idle_size); + if (!chan->tx_idle_skb){ + err=-ENOMEM; + goto new_if_error; + } + buf=skb_put(chan->tx_idle_skb,chan->max_idle_size); + memset(buf,chan->idle_flag,chan->max_idle_size); + } + + chan->dma_mtu = card->wandev.mtu >= card->u.xilinx.cfg.mru? + card->wandev.mtu:card->u.xilinx.cfg.mru; + + chan->dma_mtu = xilinx_valid_mtu(chan->dma_mtu); + if (!chan->dma_mtu){ + DEBUG_EVENT("%s:%s: Error invalid MTU %i mru %i\n", + card->devname, + chan->if_name, + card->wandev.mtu,card->u.xilinx.cfg.mru); + err= -EINVAL; + goto new_if_error; + } + + DEBUG_EVENT("%s:%s: Allocating %i dma skb len=%i\n", + card->devname,chan->if_name, + card->u.xilinx.cfg.dma_per_ch, + chan->dma_mtu); + + + err=aft_alloc_rx_dma_buff(card, chan, card->u.xilinx.cfg.dma_per_ch); + if (err){ + goto new_if_error; + } + + /* If gateway option is set, then this interface is the + * default gateway on this system. We must know that information + * in case DYNAMIC interface configuration is enabled. + * + * I.E. If the interface is brought down by the driver, the + * default route will also be removed. Once the interface + * is brought back up, we must know to re-astablish the + * default route. + */ + if ((chan->gateway = conf->gateway) == WANOPT_YES){ + DEBUG_EVENT( "%s: Interface %s is set as a gateway.\n", + card->devname,chan->if_name); + } + + /* Get Multicast Information from the user + * FIXME: This option is not clearly defined + */ + chan->mc = conf->mc; + + + /* The network interface "dev" has been passed as + * an argument from the above layer. We must initialize + * it so it can be registered into the kernel. + * + * The "dev" structure is the link between the kernel + * stack and the wanpipe driver. It contains all + * access hooks that kernel uses to communicate to + * the our driver. + * + * For now, just set the "dev" name to the user + * defined name and initialize: + * dev->if_init : function that will be called + * to further initialize + * dev structure on "ifconfig up" + * + * dev->priv : private structure allocated above + * + */ + +#if 0 + /* Create interface file in proc fs. + * Once the proc file system is created, the new_if() function + * should exit successfuly. + * + * DO NOT place code under this function that can return + * anything else but 0. + */ + err = wanrouter_proc_add_interface(wandev, + &chan->dent, + chan->if_name, + dev); + if (err){ + DEBUG_EVENT( + "%s: can't create /proc/net/router/frmw/%s entry!\n", + card->devname, chan->if_name); + goto new_if_error; + } +#endif + /* Only setup the dev pointer once the new_if function has + * finished successfully. DO NOT place any code below that + * can return an error */ + dev->init = &if_init; + dev->priv = chan; +#ifdef WANPIPE_GENERIC + if_init(dev); +#endif + + + /* Increment the number of network interfaces + * configured on this card. + */ + wan_atomic_inc(&card->wandev.if_cnt); + + chan->common.state = WAN_CONNECTING; + + DEBUG_EVENT( "\n"); + + return 0; + +new_if_error: + + while ((skb=wan_skb_dequeue(&chan->wp_tx_free_list)) != NULL){ + wan_skb_free(skb); + } + + while ((skb=wan_skb_dequeue(&chan->wp_rx_free_list)) != NULL){ + wan_skb_free(skb); + } + + WAN_TASKLET_KILL(&chan->common.bh_task); + + if (chan->common.usedby == API){ + wan_unreg_api(chan, card->devname); + } + + if (chan->tx_idle_skb){ + wan_skb_free(chan->tx_idle_skb); + chan->tx_idle_skb=NULL; + } + + wan_free(chan); + + dev->priv=NULL; + + return err; +} + +/*============================================================================ + * del_if - Delete logical channel. + * + * @wandev: Wanpipe private device pointer + * @dev: Netowrk interface pointer + * + * This function is called by ROUTER_DELIF ioctl call + * to deallocate the network interface. + * + * The network interface and the private structure are + * about to be deallocated by the upper layer. + * We have to clean and deallocate any allocated memory. + * + * NOTE: DO NOT deallocate dev->priv here! It will be + * done by the upper layer. + * + */ +static int del_if (wan_device_t* wandev, struct net_device* dev) +{ + private_area_t* chan = dev->priv; + sdla_t* card = chan->card; + struct sk_buff *skb; + wan_smp_flag_t flags; + +#ifdef CONFIG_PRODUCT_WANPIPE_TDM_VOICE + if (chan->common.usedby == TDM_VOICE){ + int err; + //if ((err = wp_tdmv_remove(card)) != 0){ + WAN_TDMV_CALL(remove, (card), err); + if (err){ + return err; + } + } +#endif + xilinx_t3_exar_dev_unconfigure(card,chan); + + WAN_TASKLET_KILL(&chan->common.bh_task); + + if (chan->common.usedby == API){ + wan_unreg_api(chan, card->devname); + } + + protocol_shutdown(card,dev); + + + wan_spin_lock_irq(&card->wandev.lock,&flags); + + while ((skb=wan_skb_dequeue(&chan->wp_rx_free_list)) != NULL){ + wan_skb_free(skb); + } + + while ((skb=wan_skb_dequeue(&chan->wp_rx_complete_list)) != NULL){ + wan_skb_free(skb); + } + + while ((skb=wan_skb_dequeue(&chan->wp_tx_free_list)) != NULL){ + wan_skb_free(skb); + } + while ((skb=wan_skb_dequeue(&chan->wp_tx_pending_list)) != NULL){ + wan_skb_free(skb); + } + + + if (chan->tx_realign_buf){ + wan_free(chan->tx_realign_buf); + chan->tx_realign_buf=NULL; + } + + wan_spin_unlock_irq(&card->wandev.lock,&flags); + + /* Delete interface name from proc fs. */ +#if 0 + wanrouter_proc_delete_interface(wandev, chan->if_name); +#endif + + /* Decrement the number of network interfaces + * configured on this card. + */ + wan_atomic_dec(&card->wandev.if_cnt); + + DEBUG_SUB_MEM(sizeof(private_area_t)); + return 0; +} + + +/**SECTION*********************************************************** + * + * KERNEL Device Entry Interfaces + * + ********************************************************************/ + + + +/*============================================================================ + * if_init - Initialize Linux network interface. + * + * @dev: Network interface pointer + * + * During "ifconfig up" the upper layer calls this function + * to initialize dev access pointers. Such as transmit, + * stats and header. + * + * It is called only once for each interface, + * during Linux network interface registration. + * + * Returning anything but zero will fail interface + * registration. + */ +static int if_init (struct net_device* dev) +{ + private_area_t* chan = dev->priv; + sdla_t* card = chan->card; + wan_device_t* wandev = &card->wandev; +#ifdef WANPIPE_GENERIC + hdlc_device* hdlc; +#endif + + /* Initialize device driver entry points */ + dev->open = &if_open; + dev->stop = &if_close; +#ifdef WANPIPE_GENERIC + hdlc = dev_to_hdlc(dev); + hdlc->xmit = if_send; +#else + dev->hard_start_xmit = &if_send; +#endif + dev->get_stats = &if_stats; +#if defined(LINUX_2_4)||defined(LINUX_2_6) + dev->tx_timeout = &if_tx_timeout; + dev->watchdog_timeo = 2*HZ; +#endif + dev->do_ioctl = if_do_ioctl; + + if (chan->common.usedby == BRIDGE || + chan->common.usedby == BRIDGE_NODE){ + + /* Setup the interface for Bridging */ + int hw_addr=0; + ether_setup(dev); + + /* Use a random number to generate the MAC address */ + memcpy(dev->dev_addr, "\xFE\xFC\x00\x00\x00\x00", 6); + get_random_bytes(&hw_addr, sizeof(hw_addr)); + *(int *)(dev->dev_addr + 2) += hw_addr; + + }else{ + + if (chan->protocol != WANCONFIG_PPP && + chan->protocol != WANCONFIG_CHDLC){ + dev->flags |= IFF_POINTOPOINT; + dev->flags |= IFF_NOARP; + dev->type = ARPHRD_PPP; + dev->mtu = card->wandev.mtu; + dev->hard_header_len = 0; + dev->hard_header = NULL; + dev->rebuild_header = NULL; + } + + if (chan->common.usedby == API){ + dev->mtu = card->wandev.mtu+sizeof(api_tx_hdr_t); + } + + /* Enable Mulitcasting if user selected */ + if (chan->mc == WANOPT_YES){ + dev->flags |= IFF_MULTICAST; + } + + if (chan->true_if_encoding){ + dev->type = ARPHRD_HDLC; /* This breaks the tcpdump */ + }else{ + dev->type = ARPHRD_PPP; + } + } + + /* Initialize hardware parameters */ + dev->irq = wandev->irq; + dev->dma = wandev->dma; + dev->base_addr = wandev->ioport; + card->hw_iface.getcfg(card->hw, SDLA_MEMBASE, &dev->mem_start); + card->hw_iface.getcfg(card->hw, SDLA_MEMEND, &dev->mem_end); + + /* Set transmit buffer queue length + * If too low packets will not be retransmitted + * by stack. + */ + dev->tx_queue_len = 100; + + return 0; +} + +/*============================================================================ + * if_open - Open network interface. + * + * @dev: Network device pointer + * + * On ifconfig up, this function gets called in order + * to initialize and configure the private area. + * Driver should be configured to send and receive data. + * + * This functions starts a timer that will call + * frmw_config() function. This function must be called + * because the IP addresses could have been changed + * for this interface. + * + * Return 0 if O.k. or errno. + */ +static int if_open (struct net_device* dev) +{ + private_area_t* chan = dev->priv; + sdla_t* card = chan->card; + struct timeval tv; + unsigned long flags; + + /* Only one open per interface is allowed */ + if (open_dev_check(dev)){ + DEBUG_EVENT("%s: Open dev check failed!\n", + dev->name); + return -EBUSY; + } + + /* Initialize the router start time. + * Used by wanpipemon debugger to indicate + * how long has the interface been up */ + do_gettimeofday(&tv); + chan->router_start_time = tv.tv_sec; + + WAN_NETIF_START_QUEUE(dev); + + /* If FRONT End is down, it means that the DMA + * is disabled. In this case don't try to + * reset fifo. Let the enable_data_error_intr() + * function do this, after front end has come up */ + + wan_spin_lock_irq(&card->wandev.lock,&flags); + if (card->wandev.state == WAN_CONNECTED){ + DEBUG_TEST("%s: OPEN reseting fifo\n", + dev->name); + xilinx_init_rx_dev_fifo(card,chan,WP_WAIT); + xilinx_init_tx_dev_fifo(card,chan,WP_WAIT); + xilinx_init_tx_dma_descr(card,chan); + + xilinx_dma_rx(card,chan,-1); + } + + /* Check for transparent HDLC mode */ + if (!chan->hdlc_eng){ + /* The Transparent HDLC engine is + * enabled. The Rx dma has already + * been setup above. Now setup + * TX DMA and enable the HDLC engine */ + + DEBUG_CFG("%s: Transparent Tx Enabled!\n", + dev->name); + + xilinx_t3_exar_transparent_config(card,chan); + } + + xilinx_dev_enable(card,chan); + + wan_set_bit(0,&chan->up); + wan_spin_unlock_irq(&card->wandev.lock,&flags); + + chan->ignore_modem=0x0F; + + /* Increment the module usage count */ + wanpipe_open(card); + + if (card->wandev.state == WAN_CONNECTED){ + /* If Front End is connected already set interface + * state to Connected too */ + set_chan_state(card, dev, WAN_CONNECTED); + } + + protocol_start(card,dev); + + /* Wait for the front end interrupt + * before enabling the card */ + return 0; +} + +/*============================================================================ + * if_close - Close network interface. + * + * @dev: Network device pointer + * + * On ifconfig down, this function gets called in order + * to cleanup interace private area. + * + * IMPORTANT: + * + * No deallocation or unconfiguration should ever occur in this + * function, because the interface can come back up + * (via ifconfig up). + * + * Furthermore, in dynamic interfacace configuration mode, the + * interface will come up and down to reflect the protocol state. + * + * Any deallocation and cleanup can occur in del_if() + * function. That function is called before the dev interface + * itself is deallocated. + * + * Thus, we should only stop the net queue and decrement + * the wanpipe usage counter via wanpipe_close() function. + */ + +static int if_close (struct net_device* dev) +{ + private_area_t* chan = dev->priv; + sdla_t* card = chan->card; + wan_smp_flag_t smp_flags; + + wan_clear_bit(0,&chan->up); + + WAN_NETIF_STOP_QUEUE(dev); + +#if defined(LINUX_2_1) + dev->start=0; +#endif + protocol_stop(card,dev); + + chan->common.state = WAN_DISCONNECTED; + + wan_spin_lock_irq(&card->wandev.lock,&smp_flags); + xilinx_dev_close(card,chan); + wan_spin_unlock_irq(&card->wandev.lock,&smp_flags); + + chan->ignore_modem=0x00; + + wanpipe_close(card); + return 0; +} + + +/*============================================================= + * disable_comm - Main shutdown function + * + * @card: Wanpipe device pointer + * + * The command 'wanrouter stop' has been called + * and the whole wanpipe device is going down. + * This is the last function called to disable + * all comunications and deallocate any memory + * that is still allocated. + * + * o Disable communications, turn off interrupts + * o Deallocate memory used, if any + * o Unconfigure TE1 card + */ + +static void disable_comm (sdla_t *card) +{ + unsigned long flags; + + /* Unconfiging, only on shutdown */ + if (IS_TE3(&card->fe.fe_cfg)) { + sdla_te3_unconfig(&card->fe); + } + + wan_spin_lock_irq(&card->wandev.lock,&flags); + + card->isr=NULL; + + /* Disable DMA ENGINE before we perform + * core reset. Otherwise, we will receive + * rx fifo errors on subsequent resetart. */ + disable_data_error_intr(card,DEVICE_DOWN); + + wan_set_bit(CARD_DOWN,&card->wandev.critical); + + wan_spin_unlock_irq(&card->wandev.lock,&flags); + + udelay(10); + + xilinx_t3_exar_chip_unconfigure(card); + + return; +} + + + +/*============================================================================ + * if_tx_timeout + * + * Kernel networking stack calls this function in case + * the interface has been stopped for TX_TIMEOUT seconds. + * + * This would occur if we lost TX interrupts or the + * card has stopped working for some reason. + * + * Handle transmit timeout event from netif watchdog + */ +static void if_tx_timeout (struct net_device *dev) +{ + private_area_t* chan = dev->priv; + sdla_t *card = chan->card; + unsigned int cur_dma_ptr; + u32 reg; + unsigned long smp_flags; + + /* If our device stays busy for at least 5 seconds then we will + * kick start the device by making dev->tbusy = 0. We expect + * that our device never stays busy more than 5 seconds. So this + * is only used as a last resort. + */ + + ++chan->if_stats.collisions; + + DEBUG_EVENT( "%s: Transmit timed out on %s\n", card->devname,dev->name); + +// DEBUG_EVENT("%s: TxStatus=0x%X DMAADDR=0x%lX DMALEN=%i \n", +// chan->if_name, +// chan->dma_status, +// chan->tx_dma_addr, +// chan->tx_dma_len); + + card->hw_iface.bus_read_4(card->hw,AFT_TE3_CRNT_DMA_DESC_ADDR_REG,®); + cur_dma_ptr=get_current_tx_dma_ptr(reg); + + DEBUG_EVENT("%s: Chain TxIntrPend=%i, TxBusy=%i TxCur=%i, TxPend=%i HwCur=%i TxErr=%li\n", + chan->if_name, + wan_test_bit(TX_INTR_PENDING,&chan->dma_chain_status), + wan_test_bit(TX_DMA_BUSY,&chan->dma_status), + chan->tx_chain_indx, + chan->tx_pending_chain_indx, + cur_dma_ptr, + chan->if_stats.tx_fifo_errors); + + /* The Interrupt didn't trigger. + * Clear the interrupt pending flag and + * let watch dog, clean up the tx chain */ + + wan_spin_lock_irq(&card->wandev.lock, &smp_flags); + aft_list_tx_descriptors(chan); + xilinx_tx_fifo_under_recover(card,chan); + wan_spin_unlock_irq(&card->wandev.lock, &smp_flags); + + aft_enable_tx_watchdog(card,AFT_TX_TIMEOUT); +} + + +/*============================================================================ + * if_send - Send a packet on a network interface. + * + * @dev: Network interface pointer + * @skb: Packet obtained from the stack or API + * that should be sent out the port. + * + * o Mark interface as stopped + * (marks start of the transmission) to indicate + * to the stack that the interface is busy. + * + * o Check link state. + * If link is not up, then drop the packet. + * + * o Copy the tx packet into the protocol tx buffers on + * the adapter. + * + * o If tx successful: + * Free the skb buffer and mark interface as running + * and return 0. + * + * o If tx failed, busy: + * Keep interface marked as busy + * Do not free skb buffer + * Enable Tx interrupt (which will tell the stack + * that interace is not busy) + * Return a non-zero value to tell the stack + * that the tx should be retried. + * + * Return: 0 complete (socket buffer must be freed) + * non-0 packet may be re-transmitted + * + */ +static int if_send (struct sk_buff* skb, struct net_device* dev) +{ + + private_area_t *chan = dev->priv; + sdla_t *card = chan->card; + wan_smp_flag_t smp_flags; + + /* Mark interface as busy. The kernel will not + * attempt to send any more packets until we clear + * this condition */ + + if (skb == NULL){ + /* This should never happen. Just a sanity check. + */ + DEBUG_EVENT( "%s: interface %s got kicked!\n", + card->devname, dev->name); + + WAN_NETIF_WAKE_QUEUE(dev); + return 0; + } + + /* Non 2.4 kernels used to call if_send() + * after TX_TIMEOUT seconds have passed of interface + * being busy. Same as if_tx_timeout() in 2.4 kernels */ +#if defined(LINUX_2_1) + if (dev->tbusy){ + + /* If our device stays busy for at least 5 seconds then we will + * kick start the device by making dev->tbusy = 0. We expect + * that our device never stays busy more than 5 seconds. So this + * is only used as a last resort. + */ + ++chan->if_stats.collisions; + if((jiffies - chan->tick_counter) < (5 * HZ)) { + return 1; + } + + if_tx_timeout(dev); + } +#endif + + if (chan->common.state != WAN_CONNECTED){ + WAN_NETIF_STOP_QUEUE(dev); + if (WAN_NETIF_CARRIER_OK(dev)){ + DEBUG_EVENT("%s: Critical Error: Carrier on on tx dev down\n", + chan->if_name); + } + wan_netif_set_ticks(dev, SYSTEM_TICKS); + ++chan->if_stats.tx_carrier_errors; + return 1; + + }else if (wan_skb_queue_len(&chan->wp_tx_pending_list)){ + DEBUG_EVENT("%s: Critical Error: Tx Pending List Full\n", + chan->if_name); + WAN_NETIF_STOP_QUEUE(dev); + return 1; + + }else { + int err=0; + + if (chan->common.usedby == API){ + if (sizeof(api_tx_hdr_t) >= wan_skb_len(skb)){ + wan_skb_free(skb); + ++chan->if_stats.tx_errors; + WAN_NETIF_START_QUEUE(dev); + goto if_send_exit_crit; + } + wan_skb_pull(skb,sizeof(api_tx_hdr_t)); + } + + wan_spin_lock_irq(&card->wandev.lock, &smp_flags); + + err=xilinx_dma_te3_tx(card,chan,skb); + + switch (err){ + + case 0: + WAN_NETIF_START_QUEUE(dev); + wan_netif_set_ticks(dev, SYSTEM_TICKS); + err=0; + break; + + case -EBUSY: + WAN_NETIF_STOP_QUEUE(dev); + err=1; + break; + + default: + + /* The packet was dropped + * by the tx chain handler. + * The tx_dropped stat was updated, + * thus all is left for us is + * to start the interface again. + * This SHOULD NEVER happen */ + if (WAN_NET_RATELIMIT()){ + DEBUG_EVENT("%s: TE3 Failed to send: Should never happend!\n", + chan->if_name); + } + WAN_NETIF_START_QUEUE(dev); + wan_netif_set_ticks(dev, SYSTEM_TICKS); + err=0; + } + wan_spin_unlock_irq(&card->wandev.lock, &smp_flags); + + return err; + } + +if_send_exit_crit: + + return 0; +} + + +/*============================================================================ + * if_stats + * + * Used by /proc/net/dev and ifconfig to obtain interface + * statistics. + * + * Return a pointer to struct net_device_stats. + */ +static struct net_device_stats* if_stats (struct net_device* dev) +{ + private_area_t* chan; + + if ((chan=dev->priv) == NULL) + return NULL; + +#if 0 +{ + sdla_t *card; + card=chan->card; + + + u8 *base_addr=card->u.xilinx.rx_dma_ptr; + u8 *base_addr_tx=card->u.xilinx.tx_dma_ptr; + u8 *addr=(u8*)wan_dma_get_vaddr(card,base_addr); + u8 *addrtx=(u8*)wan_dma_get_vaddr(card,base_addr_tx); + u8 *addr1, *addr0; + + addr+=chan->logic_ch_num*card->u.xilinx.dma_mtu_off; + + addr0=addr+0*card->u.xilinx.dma_mtu; + addr1=addr+1*card->u.xilinx.dma_mtu; + + DEBUG_EVENT("%s: Buf 0: 0x%02X 1: 0x%02X Txbuf: 0x%02X RxCompList=%i RxFreeList=%i TxList=%i\n", + dev->name,addr0[0],addr1[0],addrtx[0], + wan_skb_queue_len(&chan->wp_rx_complete_list), + wan_skb_queue_len(&chan->wp_rx_free_list), + wan_skb_queue_len(&chan->wp_tx_pending_list)); +} +#endif + + +#if 0 + DEBUG_EVENT("%s: RxCompList=%i RxFreeList=%i TxList=%i\n", + dev->name, + wan_skb_queue_len(&chan->wp_rx_complete_list), + wan_skb_queue_len(&chan->wp_rx_free_list), + wan_skb_queue_len(&chan->wp_tx_pending_list)); +#endif + + + return &chan->if_stats; +} + + + + +/*======================================================================== + * + * if_do_ioctl - Ioctl handler for fr + * + * @dev: Device subject to ioctl + * @ifr: Interface request block from the user + * @cmd: Command that is being issued + * + * This function handles the ioctls that may be issued by the user + * to control or debug the protocol or hardware . + * + * It does both busy and security checks. + * This function is intended to be wrapped by callers who wish to + * add additional ioctl calls of their own. + * + * Used by: SNMP Mibs + * wanpipemon debugger + * + */ +static int if_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + private_area_t* chan= (private_area_t*)dev->priv; + sdla_t *card; + unsigned long smp_flags; + wan_udp_pkt_t *wan_udp_pkt; + int err=0; + + if (!chan){ + return -ENODEV; + } + card=chan->card; + + NET_ADMIN_CHECK(); + + switch(cmd) + { + + case SIOC_WANPIPE_BIND_SK: + if (!ifr){ + err= -EINVAL; + break; + } + + wan_spin_lock_irq(&card->wandev.lock, &smp_flags); + err=wan_bind_api_to_svc(chan,ifr->ifr_data); + chan->if_stats.rx_dropped=0; + wan_spin_unlock_irq(&card->wandev.lock, &smp_flags); + break; + + case SIOC_WANPIPE_UNBIND_SK: + if (!ifr){ + err= -EINVAL; + break; + } + + wan_spin_lock_irq(&card->wandev.lock, &smp_flags); + err=wan_unbind_api_from_svc(chan,ifr->ifr_data); + wan_spin_unlock_irq(&card->wandev.lock, &smp_flags); + + break; + + case SIOC_WANPIPE_CHECK_TX: + case SIOC_ANNEXG_CHECK_TX: + err=0; + break; + + case SIOC_WANPIPE_DEV_STATE: + err = chan->common.state; + break; + + case SIOC_ANNEXG_KICK: + err=0; + break; + + case SIOC_WAN_DEVEL_IOCTL: + err = aft_devel_ioctl(card, ifr); + break; + + case SIOC_AFT_CUSTOMER_ID: + err=0; + break; + + case SIOC_WANPIPE_PIPEMON: + + if (wan_atomic_read(&chan->udp_pkt_len) != 0){ + return -EBUSY; + } + + wan_atomic_set(&chan->udp_pkt_len,MAX_LGTH_UDP_MGNT_PKT); + + /* For performance reasons test the critical + * here before spin lock */ + if (wan_test_bit(0,&card->in_isr)){ + wan_atomic_set(&chan->udp_pkt_len,0); + return -EBUSY; + } + + + wan_udp_pkt=(wan_udp_pkt_t*)chan->udp_pkt_data; + if (copy_from_user(&wan_udp_pkt->wan_udp_hdr,ifr->ifr_data,sizeof(wan_udp_hdr_t))){ + wan_atomic_set(&chan->udp_pkt_len,0); + return -EFAULT; + } + + /* We have to check here again because we don't know + * what happened during spin_lock */ + if (wan_test_bit(0,&card->in_isr)) { + DEBUG_EVENT( "%s:%s Pipemon command failed, Driver busy: try again.\n", + card->devname,dev->name); + wan_atomic_set(&chan->udp_pkt_len,0); + return -EBUSY; + } + + process_udp_mgmt_pkt(card,dev,chan,1); + + /* This area will still be critical to other + * PIPEMON commands due to udp_pkt_len + * thus we can release the irq */ + + if (wan_atomic_read(&chan->udp_pkt_len) > sizeof(wan_udp_pkt_t)){ + DEBUG_EVENT( "%s: Error: Pipemon buf too bit on the way up! %i\n", + card->devname,wan_atomic_read(&chan->udp_pkt_len)); + wan_atomic_set(&chan->udp_pkt_len,0); + return -EINVAL; + } + + if (copy_to_user(ifr->ifr_data,&wan_udp_pkt->wan_udp_hdr,sizeof(wan_udp_hdr_t))){ + wan_atomic_set(&chan->udp_pkt_len,0); + return -EFAULT; + } + + wan_atomic_set(&chan->udp_pkt_len,0); + return 0; + + default: +#ifndef WANPIPE_GENERIC + DEBUG_EVENT("%s: Command %x not supported!\n", + card->devname,cmd); + return -EOPNOTSUPP; +#else + if (card->wandev.ioctl){ + err = card->wandev.hdlc_ioctl(card, dev, ifr, cmd); + } +#endif + } + + return err; +} + + +/**SECTION********************************************************** + * + * FIRMWARE Specific Interface Functions + * + *******************************************************************/ + + +#define FIFO_RESET_TIMEOUT_CNT 1000 +#define FIFO_RESET_TIMEOUT_US 10 +static int xilinx_init_rx_dev_fifo(sdla_t *card, private_area_t *chan, unsigned char wait) +{ + + u32 reg; + u32 dma_descr; + u8 timeout=1; + u16 i; + unsigned int cur_dma_ptr; + + /* Clean RX DMA fifo */ + + card->hw_iface.bus_read_4(card->hw,AFT_TE3_CRNT_DMA_DESC_ADDR_REG,®); + cur_dma_ptr=get_current_rx_dma_ptr(reg); + + dma_descr=(unsigned long)(cur_dma_ptr<<4) + XILINX_RxDMA_DESCRIPTOR_HI; + reg=0; + wan_set_bit(INIT_DMA_FIFO_CMD_BIT,®); + + DEBUG_TEST("%s: Clearing RX Fifo %s DmaDescr=(0x%X) Reg=(0x%X)\n", + __FUNCTION__,chan->if_name, + dma_descr,reg); + + card->hw_iface.bus_write_4(card->hw,dma_descr,reg); + + if (wait == WP_WAIT){ + for(i=0;ihw_iface.bus_read_4(card->hw,dma_descr,®); + if (wan_test_bit(INIT_DMA_FIFO_CMD_BIT,®)){ + udelay(FIFO_RESET_TIMEOUT_US); + continue; + } + timeout=0; + break; + } + + if (timeout){ + DEBUG_EVENT("%s:%s: Error: Rx fifo reset timedout %u us\n", + card->devname,chan->if_name,i*FIFO_RESET_TIMEOUT_US); + }else{ + DEBUG_TEST("%s:%s: Rx Fifo Reset Successful\n", + card->devname,chan->if_name); + } + }else{ + timeout=0; + } + + return timeout; +} + +static int xilinx_init_tx_dev_fifo(sdla_t *card, private_area_t *chan, unsigned char wait) +{ + u32 reg; + u32 dma_descr; + u8 timeout=1; + u16 i; + unsigned int cur_dma_ptr; + + card->hw_iface.bus_read_4(card->hw,AFT_TE3_CRNT_DMA_DESC_ADDR_REG,®); + cur_dma_ptr=get_current_tx_dma_ptr(reg); + + /* Clean TX DMA fifo */ + dma_descr=(unsigned long)(cur_dma_ptr<<4) + XILINX_TxDMA_DESCRIPTOR_HI; + reg=0; + wan_set_bit(INIT_DMA_FIFO_CMD_BIT,®); + + DEBUG_TEST("%s: Clearing TX Fifo %s DmaDescr=(0x%X) Reg=(0x%X)\n", + __FUNCTION__,chan->if_name, + dma_descr,reg); + + card->hw_iface.bus_write_4(card->hw,dma_descr,reg); + + if (wait == WP_WAIT){ + for(i=0;ihw_iface.bus_read_4(card->hw,dma_descr,®); + if (wan_test_bit(INIT_DMA_FIFO_CMD_BIT,®)){ + udelay(FIFO_RESET_TIMEOUT_US); + continue; + } + timeout=0; + break; + } + + if (timeout){ + DEBUG_EVENT("%s:%s: Error: Tx fifo reset timedout %u us\n", + card->devname,chan->if_name,i*FIFO_RESET_TIMEOUT_US); + }else{ + DEBUG_TEST("%s:%s: Tx Fifo Reset Successful\n", + card->devname,chan->if_name); + } + }else{ + timeout=0; + } + + return timeout; +} + + +static void xilinx_dev_enable(sdla_t *card, private_area_t *chan) +{ + u32 reg; + + DEBUG_TEST("%s: Enabling Global Inter Mask !\n",chan->if_name); + + /* Enable Logic Channel Interrupts for DMA and fifo */ + card->hw_iface.bus_read_4(card->hw, + XILINX_GLOBAL_INTER_MASK, ®); + wan_set_bit(chan->logic_ch_num,®); + + card->hw_iface.bus_write_4(card->hw, + XILINX_GLOBAL_INTER_MASK, reg); + + wan_set_bit(chan->logic_ch_num,&card->u.xilinx.active_ch_map); +} + + + +static void xilinx_dev_close(sdla_t *card, private_area_t *chan) +{ + u32 reg; + + DEBUG_CFG("-- Close Xilinx device. --\n"); + + /* Disable Logic Channel Interrupts for DMA and fifo */ + card->hw_iface.bus_read_4(card->hw, + XILINX_GLOBAL_INTER_MASK, ®); + + wan_clear_bit(chan->logic_ch_num,®); + wan_clear_bit(chan->logic_ch_num,&card->u.xilinx.active_ch_map); + + /* We are masking the chan interrupt. + * Lock to make sure that the interrupt is + * not running */ + card->hw_iface.bus_write_4(card->hw, + XILINX_GLOBAL_INTER_MASK, reg); + + + aft_reset_rx_watchdog(card); + aft_reset_tx_watchdog(card); + + reg=0; + + /* Select an HDLC logic channel for configuration */ + card->hw_iface.bus_read_4(card->hw, XILINX_TIMESLOT_HDLC_CHAN_REG, ®); + + reg&=~HDLC_LOGIC_CH_BIT_MASK; + reg&= HDLC_LCH_TIMESLOT_MASK; /* mask not valid bits */ + + card->hw_iface.bus_write_4(card->hw, + XILINX_TIMESLOT_HDLC_CHAN_REG, + (reg|(chan->logic_ch_num&HDLC_LOGIC_CH_BIT_MASK))); + + + reg=0; + xilinx_write_ctrl_hdlc(card, + chan->first_time_slot, + XILINX_HDLC_CONTROL_REG, + reg); + + /* Initialize DMA descriptors and DMA Chains */ + aft_init_tx_rx_dma_descr(chan); + +} + +/**SECTION************************************************************* + * + * TX Handlers + * + **********************************************************************/ + + +/*=============================================== + * xilinx_dma_tx_complete + * + */ +static void xilinx_dma_tx_complete (sdla_t *card, private_area_t *chan, int wtd) +{ + DEBUG_TEST("%s: Tx interrupt wtd=%d\n",chan->if_name,wtd); + + aft_reset_tx_watchdog(card); + + if (!wtd){ + wan_clear_bit(TX_INTR_PENDING,&chan->dma_chain_status); + } + + aft_tx_dma_chain_handler((unsigned long)chan); + + + if (wan_skb_queue_len(&chan->wp_tx_pending_list)){ + aft_pending_tx(card,chan); + } + + +#if defined(__LINUX__) + if (WAN_NETIF_QUEUE_STOPPED(chan->common.dev)){ + WAN_NETIF_WAKE_QUEUE(chan->common.dev); +#ifndef CONFIG_PRODUCT_WANPIPE_GENERIC + if (chan->common.usedby == API){ + wan_wakeup_api(chan); + }else if (chan->common.usedby == STACK){ + wanpipe_lip_kick(chan,0); + } +#endif + } +#endif + + aft_enable_tx_watchdog(card,AFT_TX_TIMEOUT); + + return; +} + +/*=============================================== + * xilinx_tx_post_complete + * + */ +static void xilinx_tx_post_complete (sdla_t *card, private_area_t *chan, struct sk_buff *skb) +{ + unsigned long reg = wan_skb_csum(skb); + + if ((wan_test_bit(TxDMA_HI_DMA_GO_READY_BIT,®)) || + (reg & TxDMA_HI_DMA_DATA_LENGTH_MASK) || + (reg&TxDMA_HI_DMA_PCI_ERROR_MASK)){ + + DEBUG_EVENT("%s:%s: Tx DMA Descriptor=0x%lX\n", + card->devname,chan->if_name,reg); + + /* Checking Tx DMA Go bit. Has to be '0' */ + if (wan_test_bit(TxDMA_HI_DMA_GO_READY_BIT,®)){ + DEBUG_TEST("%s:%s: Error: TxDMA Intr: GO bit set on Tx intr\n", + card->devname,chan->if_name); + } + + if (reg & TxDMA_HI_DMA_DATA_LENGTH_MASK){ + DEBUG_TEST("%s:%s: Error: TxDMA Length not equal 0 \n", + card->devname,chan->if_name); + } + + /* Checking Tx DMA PCI error status. Has to be '0's */ + if (reg&TxDMA_HI_DMA_PCI_ERROR_MASK){ + + if (reg & TxDMA_HI_DMA_PCI_ERROR_M_ABRT){ + DEBUG_EVENT("%s:%s: Tx Error: Abort from Master: pci fatal error!\n", + card->devname,chan->if_name); + } + if (reg & TxDMA_HI_DMA_PCI_ERROR_T_ABRT){ + DEBUG_EVENT("%s:%s: Tx Error: Abort from Target: pci fatal error!\n", + card->devname,chan->if_name); + } + if (reg & TxDMA_HI_DMA_PCI_ERROR_DS_TOUT){ + DEBUG_EVENT("%s:%s: Tx Warning: PCI Latency Timeout!\n", + card->devname,chan->if_name); + goto tx_post_ok; + } + if (reg & TxDMA_HI_DMA_PCI_ERROR_RETRY_TOUT){ + DEBUG_EVENT("%s:%s: Tx Error: 'Retry' exceeds maximum (64k): pci fatal error!\n", + card->devname,chan->if_name); + } + } + chan->if_stats.tx_errors++; + goto tx_post_exit; + } + +tx_post_ok: + + chan->if_stats.tx_packets++; + chan->if_stats.tx_bytes+=wan_skb_len(skb); + + /* Indicate that the first tx frame went + * out on the transparent link */ + wan_set_bit(0,&chan->idle_start); + + wan_capture_trace_packet(card, &chan->trace_info, skb, TRC_OUTGOING_FRM); + +tx_post_exit: + + return; +} + + + +/**SECTION************************************************************* + * + * RX Handlers + * + **********************************************************************/ + +/*=============================================== + * xilinx_dma_rx_complete + * + */ +static void xilinx_dma_rx_complete (sdla_t *card, private_area_t *chan, int wtd) +{ + aft_reset_rx_watchdog(card); + aft_rx_dma_chain_handler(chan,wtd,0); +} + +/*=============================================== + * xilinx_rx_post_complete + * + */ +static void xilinx_rx_post_complete (sdla_t *card, private_area_t *chan, + struct sk_buff *skb, + struct sk_buff **new_skb, + unsigned char *pkt_error) +{ + + unsigned int len,data_error = 0; + unsigned char *buf; + +#if 0 + wp_rx_element_t *rx_el=(wp_rx_element_t *)&skb->cb[0]; +#else + wp_rx_element_t *rx_el; + rx_el=(wp_rx_element_t *)wan_skb_data(skb); +#endif + DEBUG_RX("%s:%s: RX HI=0x%X LO=0x%X\n DMA=0x%lX", + __FUNCTION__,chan->if_name,rx_el->reg,rx_el->align,rx_el->dma_addr); + +#if 0 + chan->if_stats.rx_errors++; +#endif + + rx_el->align&=RxDMA_LO_ALIGNMENT_BIT_MASK; + *pkt_error=0; + *new_skb=NULL; + + + /* Checking Rx DMA Go bit. Has to be '0' */ + if (wan_test_bit(RxDMA_HI_DMA_GO_READY_BIT,&rx_el->reg)){ + DEBUG_TEST("%s:%s: Error: RxDMA Intr: GO bit set on Rx intr\n", + card->devname,chan->if_name); + chan->if_stats.rx_errors++; + goto rx_comp_error; + } + + /* Checking Rx DMA PCI error status. Has to be '0's */ + if (rx_el->reg&RxDMA_HI_DMA_PCI_ERROR_MASK){ + + if (rx_el->reg & RxDMA_HI_DMA_PCI_ERROR_M_ABRT){ + DEBUG_EVENT("%s:%s: Rx Error: Abort from Master: pci fatal error!\n", + card->devname,chan->if_name); + } + if (rx_el->reg & RxDMA_HI_DMA_PCI_ERROR_T_ABRT){ + DEBUG_EVENT("%s:%s: Rx Error: Abort from Target: pci fatal error!\n", + card->devname,chan->if_name); + } + if (rx_el->reg & RxDMA_HI_DMA_PCI_ERROR_DS_TOUT){ + DEBUG_EVENT("%s:%s: Rx Error: No 'DeviceSelect' from target: pci fatal error!\n", + card->devname,chan->if_name); + } + if (rx_el->reg & RxDMA_HI_DMA_PCI_ERROR_RETRY_TOUT){ + DEBUG_EVENT("%s:%s: Rx Error: 'Retry' exceeds maximum (64k): pci fatal error!\n", + card->devname,chan->if_name); + } + + DEBUG_EVENT("%s: RXDMA PCI ERROR = 0x%x\n",chan->if_name,rx_el->reg); + chan->if_stats.rx_errors++; + goto rx_comp_error; + } + + if (chan->hdlc_eng){ + + /* Checking Rx DMA Frame start bit. (information for api) */ + if (!wan_test_bit(RxDMA_HI_DMA_FRAME_START_BIT,&rx_el->reg)){ + DEBUG_TEST("%s:%s RxDMA Intr: Start flag missing: MTU Mismatch! Reg=0x%X\n", + card->devname,chan->if_name,rx_el->reg); + chan->if_stats.rx_frame_errors++; + goto rx_comp_error; + } + + /* Checking Rx DMA Frame end bit. (information for api) */ + if (!wan_test_bit(RxDMA_HI_DMA_FRAME_END_BIT,&rx_el->reg)){ + DEBUG_TEST("%s:%s: RxDMA Intr: End flag missing: MTU Mismatch! Reg=0x%X\n", + card->devname,chan->if_name,rx_el->reg); + chan->if_stats.rx_frame_errors++; + goto rx_comp_error; + + } else { /* Check CRC error flag only if this is the end of Frame */ + + if (wan_test_bit(RxDMA_HI_DMA_CRC_ERROR_BIT,&rx_el->reg)){ + DEBUG_TEST("%s:%s: RxDMA Intr: CRC Error! Reg=0x%X Len=%i\n", + card->devname,chan->if_name,rx_el->reg, + (rx_el->reg&RxDMA_HI_DMA_DATA_LENGTH_MASK)>>2); + chan->if_stats.rx_frame_errors++; + wan_set_bit(WP_CRC_ERROR_BIT,&rx_el->pkt_error); + data_error = 1; + } + + /* Check if this frame is an abort, if it is + * drop it and continue receiving */ + if (wan_test_bit(RxDMA_HI_DMA_FRAME_ABORT_BIT,&rx_el->reg)){ + DEBUG_TEST("%s:%s: RxDMA Intr: Abort! Reg=0x%X\n", + card->devname,chan->if_name,rx_el->reg); + chan->if_stats.rx_frame_errors++; + wan_set_bit(WP_ABORT_ERROR_BIT,&rx_el->pkt_error); + data_error = 1; + } + + if (chan->common.usedby != API && data_error){ + goto rx_comp_error; + } + } + } + + len=rx_el->reg&RxDMA_HI_DMA_DATA_LENGTH_MASK; + + if (chan->hdlc_eng){ + /* In HDLC mode, calculate rx length based + * on alignment value, received from DMA */ + len=((((chan->dma_mtu>>2)-1)-len)<<2) - (~(rx_el->align)&RxDMA_LO_ALIGNMENT_BIT_MASK); + }else{ + /* In Transparent mode, our RX buffer will always be + * aligned to the 32bit (word) boundary, because + * the RX buffers are all of equal length */ + len=(((card->wandev.mtu>>2)-len)<<2) - (~(0x03)&RxDMA_LO_ALIGNMENT_BIT_MASK); + } + + *pkt_error=rx_el->pkt_error; + + /* After a RX FIFO overflow, we must mark max 7 + * subsequent frames since firmware, cannot + * guarantee the contents of the fifo */ + + if (wan_test_bit(WP_FIFO_ERROR_BIT,&rx_el->pkt_error)){ + if (++chan->rx_fifo_err_cnt >= WP_MAX_FIFO_FRAMES){ + chan->rx_fifo_err_cnt=0; + } + wan_set_bit(WP_FIFO_ERROR_BIT,pkt_error); + }else{ + if (chan->rx_fifo_err_cnt){ + if (++chan->rx_fifo_err_cnt >= WP_MAX_FIFO_FRAMES){ + chan->rx_fifo_err_cnt=0; + } + wan_set_bit(WP_FIFO_ERROR_BIT,pkt_error); + } + } + + wan_skb_pull(skb, sizeof(wp_rx_element_t)); + + + if (len > aft_rx_copyback){ + /* The rx size is big enough, thus + * send this buffer up the stack + * and allocate another one */ +#if 0 + memset(&skb->cb[0],0,sizeof(wp_rx_element_t)); +#endif + + wan_skb_put(skb,len); + *new_skb=skb; + + aft_alloc_rx_dma_buff(card,chan,1); + }else{ + + /* The rx packet is very + * small thus, allocate a new + * buffer and pass it up */ + *new_skb=wan_skb_alloc(len + 20); + if (!*new_skb){ + DEBUG_EVENT("%s:%s: Failed to allocate rx skb pkt (len=%i)!\n", + card->devname,chan->if_name,(len+20)); + chan->if_stats.rx_dropped++; + goto rx_comp_error; + } + + buf=wan_skb_put((*new_skb),len); + memcpy(buf,wan_skb_tail(skb),len); + + aft_init_requeue_free_skb(chan, skb); + } + + return; + +rx_comp_error: + + aft_init_requeue_free_skb(chan, skb); + return; +} + + + +/**SECTION************************************************** + * + * Logic Channel Registration Support and + * Utility funcitons + * + **********************************************************/ + +static int aft_init_requeue_free_skb(private_area_t *chan, struct sk_buff *skb) +{ + wan_skb_init(skb,16); + wan_skb_trim(skb,0); +#if 0 + memset(&skb->cb[0],0,sizeof(wp_rx_element_t)); +#endif + wan_skb_queue_tail(&chan->wp_rx_free_list,skb); + + return 0; +} + +static int aft_alloc_rx_dma_buff(sdla_t *card, private_area_t *chan, int num) +{ + int i; + struct sk_buff *skb; + + for (i=0;idma_mtu); + if (!skb){ + DEBUG_EVENT("%s: %s no memory\n", + chan->if_name,__FUNCTION__); + return -ENOMEM; + } + wan_skb_queue_tail(&chan->wp_rx_free_list,skb); + } + + return 0; +} + + +/*============================================================================ + * Enable timer interrupt + */ +static void enable_timer (void* card_id) +{ + sdla_t* card = (sdla_t*)card_id; + + DEBUG_TEST("%s: %s Sdla Polling!\n",__FUNCTION__,card->devname); + +#if defined(__LINUX__) + wan_set_bit(AFT_FE_POLL,&card->u.aft.port_task_cmd); + WAN_TASKQ_SCHEDULE((&card->u.aft.port_task)); +#else + { + unsigned long smp_flags; + wan_spin_lock_irq(&card->wandev.lock, &smp_flags); + card->hw_iface.hw_lock(card->hw,&smp_flags1); + WAN_FECALL(&card->wandev, polling, (&card->fe)); + card->hw_iface.hw_unlock(card->hw,&smp_flags1); + wan_spin_unlock_irq(&card->wandev.lock, &smp_flags); + } +#endif + return; +} + +/**SECTION************************************************** + * + * API Bottom Half Handlers + * + **********************************************************/ + +static void wp_bh (unsigned long data) +{ + private_area_t* chan = (private_area_t *)data; + struct sk_buff *new_skb,*skb; + unsigned char pkt_error; + unsigned long timeout=jiffies; + + DEBUG_TEST("%s: ------------ BEGIN --------------: %lu\n", + __FUNCTION__,SYSTEM_TICKS); + + if (!wan_test_bit(0,&chan->up)){ + DEBUG_EVENT("%s: wp_bh() chan not up!\n", + chan->if_name); + WAN_TASKLET_END((&chan->common.bh_task)); + return; + } + + + while((skb=wan_skb_dequeue(&chan->wp_rx_complete_list)) != NULL){ + +#if 0 + chan->if_stats.rx_errors++; +#endif + + if (jiffies-timeout > 1){ + if (WAN_NET_RATELIMIT()){ + DEBUG_EVENT("%s: BH Squeeze!\n",chan->if_name); + } + wan_skb_queue_head(&chan->wp_rx_complete_list,skb); + break; + } + + if (chan->common.usedby == API && chan->common.sk == NULL){ + DEBUG_TEST("%s: No sock bound to channel rx dropping!\n", + chan->if_name); + chan->if_stats.rx_dropped++; + aft_init_requeue_free_skb(chan, skb); + + continue; + } + + new_skb=NULL; + pkt_error=0; + + /* The post function will take care + * of the skb and new_skb buffer. + * If new_skb buffer exists, driver + * must pass it up the stack, or free it */ + xilinx_rx_post_complete (chan->card, chan, + skb, + &new_skb, + &pkt_error); + if (new_skb){ + + int len=wan_skb_len(new_skb); + + wan_capture_trace_packet(chan->card, &chan->trace_info, + new_skb,TRC_INCOMING_FRM); + + if (chan->common.usedby == API){ +#if defined(__LINUX__) +# ifndef CONFIG_PRODUCT_WANPIPE_GENERIC + + /* Only for API, we insert packet status + * byte to indicate a packet error. Take + * this byte and put it in the api header */ + + if (wan_skb_headroom(new_skb) >= sizeof(api_rx_hdr_t)){ + api_rx_hdr_t *rx_hdr= + (api_rx_hdr_t*)skb_push(new_skb,sizeof(api_rx_hdr_t)); + memset(rx_hdr,0,sizeof(api_rx_hdr_t)); + rx_hdr->error_flag=pkt_error; + }else{ + DEBUG_EVENT("%s: Error Rx pkt headroom %i < %i\n", + chan->if_name, + wan_skb_headroom(new_skb), + sizeof(api_rx_hdr_t)); + ++chan->if_stats.rx_dropped; + wan_skb_free(new_skb); + continue; + } + + new_skb->protocol = htons(PVC_PROT); + new_skb->mac.raw = new_skb->data; + new_skb->dev = chan->common.dev; + new_skb->pkt_type = WAN_PACKET_DATA; +#if 0 + chan->if_stats.rx_frame_errors++; +#endif + if (wan_api_rx(chan,new_skb) != 0){ + DEBUG_TEST("%s: Error: Rx Socket busy!\n", + chan->if_name); + ++chan->if_stats.rx_dropped; + wan_skb_free(new_skb); + continue; + } +# endif +#endif + }else if (chan->common.usedby == TDM_VOICE){ + + ++chan->if_stats.rx_dropped; + wan_skb_free(new_skb); + continue; + + }else if (chan->common.usedby == STACK){ + + if (wanpipe_lip_rx(chan,new_skb) != 0){ + ++chan->if_stats.rx_dropped; + wan_skb_free(new_skb); + continue; + } + + }else{ + protocol_recv(chan->card,chan,new_skb); + } + + chan->if_stats.rx_packets++; + chan->if_stats.rx_bytes+=len; + } + + } + + while((skb=wan_skb_dequeue(&chan->wp_tx_complete_list)) != NULL){ + xilinx_tx_post_complete (chan->card,chan,skb); + wan_skb_free(skb); + } + + + WAN_TASKLET_END((&chan->common.bh_task)); +#if 1 + { + int len; + if ((len=wan_skb_queue_len(&chan->wp_rx_complete_list))){ + DEBUG_TEST("%s: Triggering from bh rx=%i\n",chan->if_name,len); + WAN_TASKLET_SCHEDULE((&chan->common.bh_task)); + }else if ((len=wan_skb_queue_len(&chan->wp_tx_complete_list))){ + DEBUG_TEST("%s: Triggering from bh tx=%i\n",chan->if_name,len); + WAN_TASKLET_SCHEDULE((&chan->common.bh_task)); + } + } +#endif + + DEBUG_TEST("%s: ------------ END -----------------: %lu\n", + __FUNCTION__,SYSTEM_TICKS); + + return; +} + +/**SECTION************************************************** + * + * Interrupt Support Functions + * + **********************************************************/ + +static int fifo_error_interrupt(sdla_t *card, u32 reg, u32 tx_status, u32 rx_status) +{ + u32 err=0; + u32 i; + private_area_t *chan; + int num_of_logic_ch; + + + if (card->wandev.state != WAN_CONNECTED){ + DEBUG_EVENT("%s: Warning: Ignoring Error Intr: link disc!\n", + card->devname); + return 0; + } + + if (IS_TE3(&card->fe.fe_cfg)){ + num_of_logic_ch=1; + }else{ + num_of_logic_ch=card->u.xilinx.num_of_time_slots; + } + + if (tx_status != 0){ + for (i=0;iu.xilinx.logic_ch_map)){ + + chan=(private_area_t*)card->u.xilinx.dev_to_ch_map[i]; + if (!chan){ + DEBUG_EVENT("Warning: ignoring tx error intr: no dev!\n"); + continue; + } + + if (!wan_test_bit(0,&chan->up)){ + DEBUG_EVENT("%s: Warning: ignoring tx error intr: dev down 0x%X UP=0x%X!\n", + chan->common.dev->name,chan->common.state,chan->ignore_modem); + continue; + } + + if (chan->common.state != WAN_CONNECTED){ + DEBUG_EVENT("%s: Warning: ignoring tx error intr: dev disc!\n", + chan->common.dev->name); + continue; + } + + if (!chan->hdlc_eng && !wan_test_bit(0,&chan->idle_start)){ + DEBUG_EVENT("%s: Warning: ignoring tx error intr: dev init error!\n", + chan->common.dev->name); + if (chan->hdlc_eng){ + xilinx_tx_fifo_under_recover(card,chan); + } + continue; + } + + DEBUG_TEST("%s:%s: Warning TX Fifo Error on LogicCh=%li Slot=%i!\n", + card->devname,chan->if_name,chan->logic_ch_num,i); + + xilinx_tx_fifo_under_recover(card,chan); + ++chan->if_stats.tx_fifo_errors; + err=-EINVAL; + } + } + } + + + if (rx_status != 0){ + for (i=0;iu.xilinx.logic_ch_map)){ + chan=(private_area_t*)card->u.xilinx.dev_to_ch_map[i]; + if (!chan){ + continue; + } + + if (!wan_test_bit(0,&chan->up)){ + DEBUG_EVENT("%s: Warning: ignoring rx error intr: dev down 0x%X UP=0x%X!\n", + chan->common.dev->name,chan->common.state,chan->ignore_modem); + continue; + } + + if (chan->common.state != WAN_CONNECTED){ + DEBUG_EVENT("%s: Warning: ignoring rx error intr: dev disc!\n", + chan->common.dev->name); + continue; + } + + DEBUG_TEST("%s:%s: Warning RX Fifo Error on LCh=%li Slot=%i RxCL=%i RxFL=%i RxDMA=%i\n", + card->devname,chan->if_name,chan->logic_ch_num,i, + wan_skb_queue_len(&chan->wp_rx_complete_list), + wan_skb_queue_len(&chan->wp_rx_free_list), + chan->rx_dma); + + ++chan->if_stats.rx_fifo_errors; +#if 0 +{ + unsigned long dma_descr; + unsigned int reg; + dma_descr=(chan->logic_ch_num<<4) + XILINX_RxDMA_DESCRIPTOR_HI; + card->hw_iface.bus_read_4(card->hw, dma_descr, ®); + DEBUG_EVENT("%s: Hi Descriptor 0x%X\n",chan->if_name,reg); +} +#endif + + wan_set_bit(WP_FIFO_ERROR_BIT, &chan->pkt_error); + + err=-EINVAL; + } + } + } + + return err; +} + + +static void front_end_interrupt(sdla_t *card, unsigned long reg) +{ + /* FIXME: To be filled by ALEX :) */ + DEBUG_TE3("%s: front_end_interrupt!\n",card->devname); + +// wp_debug_func_add(__FUNCTION__); + + if (IS_TE3(&card->fe.fe_cfg)){ + /* FIXME HANDLE T3 Interrupt */ + WAN_FECALL(&card->wandev, isr, (&card->fe)); + }else{ + DEBUG_EVENT("%s: Internal Error (Never should happened)!\n", + card->devname); + } + + handle_front_end_state(card); + return; +} + +/**SECTION*************************************************************** + * + * HARDWARE Interrupt Handlers + * + ***********************************************************************/ + + +/*============================================================================ + * wpfw_isr + * + * Main interrupt service routine. + * Determin the interrupt received and handle it. + * + */ +static void wp_aft_te3_isr (sdla_t* card) +{ + int i; + u32 reg; + u32 dma_tx_reg,dma_rx_reg,rx_fifo_status=0,tx_fifo_status=0; + private_area_t *chan; + int skip_rx_wtd=0; + + if (wan_test_bit(CARD_DOWN,&card->wandev.critical)){ + return; + } + + wan_set_bit(0,&card->in_isr); + + /* -----------------2/6/2003 9:02AM------------------ + * Disable all chip Interrupts (offset 0x040) + * -- "Transmit/Receive DMA Engine" interrupt disable + * -- "FiFo/Line Abort Error" interrupt disable + * --------------------------------------------------*/ + card->hw_iface.bus_read_4(card->hw,XILINX_CHIP_CFG_REG, ®); + + DEBUG_TEST("\n"); + DEBUG_TEST("%s: ISR (0x%X) = 0x%08X \n", + card->devname,XILINX_CHIP_CFG_REG,reg); + + if (wan_test_bit(ENABLE_TE3_FRACTIONAL,®)){ + unsigned int frc_crc; + u32 freg; + + card->hw_iface.bus_read_4(card->hw,TE3_FRACT_ENCAPSULATION_REG, &freg); + frc_crc=get_te3_rx_fract_crc_cnt(freg); + if (frc_crc){ + if (net_ratelimit()){ + DEBUG_EVENT("%s: TE3 Frac CRC Cnt = %i 0x%08X\n", + card->devname, frc_crc,reg); + } + } + } + + if (wan_test_bit(SECURITY_STATUS_FLAG,®)){ + if (++card->u.aft.chip_security_cnt > + AFT_MAX_CHIP_SECURITY_CNT){ + +#if 1 + if (WAN_NET_RATELIMIT()){ + DEBUG_EVENT("%s: Critical: Chip Security Compromised: Disabling Driver (%i)!\n", + card->devname,card->u.aft.chip_security_cnt); + } + card->u.aft.chip_security_cnt=0; +#else + + DEBUG_EVENT("%s: Critical: Chip Security Compromised: Disabling Driver (%i)!\n", + card->devname,card->u.aft.chip_security_cnt); + DEBUG_EVENT("%s: Please call Sangoma Tech Support (www.sangoma.com)!\n", + card->devname); + + disable_data_error_intr(card,DEVICE_DOWN); + port_set_state(card,WAN_DISCONNECTED); + goto isr_end; +#endif + } + }else{ + card->u.aft.chip_security_cnt=0; + } + + /* Note: If interrupts are received without pending + * flags, it usually indicates that the interrupt + * is being shared. (Check 'cat /proc/interrupts') + */ + + if (wan_test_bit(FRONT_END_INTR_ENABLE_BIT,®)){ + if (wan_test_bit(FRONT_END_INTR_FLAG,®)){ +#if defined(__LINUX__) + wan_set_bit(AFT_FE_INTR,&card->u.aft.port_task_cmd); + WAN_TASKQ_SCHEDULE((&card->u.aft.port_task)); + + __aft_fe_intr_ctrl(card,0); +#else + front_end_interrupt(card,reg); +#endif + } + } + + /* Test Fifo Error Interrupt, + * If set shutdown all interfaces and + * reconfigure */ + if (wan_test_bit(ERROR_INTR_ENABLE_BIT,®)){ + if (wan_test_bit(ERROR_INTR_FLAG,®)){ + + card->hw_iface.bus_read_4(card->hw,XILINX_HDLC_TX_INTR_PENDING_REG,&tx_fifo_status); + card->hw_iface.bus_read_4(card->hw,XILINX_HDLC_RX_INTR_PENDING_REG,&rx_fifo_status); + + rx_fifo_status&=card->u.aft.active_ch_map; + tx_fifo_status&=card->u.aft.active_ch_map; + + fifo_error_interrupt(card,reg,tx_fifo_status,rx_fifo_status); + } + } + + /* -----------------2/6/2003 9:37AM------------------ + * Checking for Interrupt source: + * 1. Receive DMA Engine + * 2. Transmit DMA Engine + * 3. Error conditions. + * --------------------------------------------------*/ + if (wan_test_bit(GLOBAL_INTR_ENABLE_BIT,®) && + (wan_test_bit(DMA_INTR_FLAG,®) || rx_fifo_status)){ + + int num_of_logic_ch; + + if (IS_TE3(&card->fe.fe_cfg)){ + num_of_logic_ch=1; + }else{ + num_of_logic_ch=card->u.xilinx.num_of_time_slots; + } + + /* Receive DMA Engine */ + card->hw_iface.bus_read_4(card->hw, + XILINX_DMA_RX_INTR_PENDING_REG, + &dma_rx_reg); + + + DEBUG_TEST("%s: DMA_RX_INTR_REG(0x%X) = 0x%X ActCH=0x%lX\n", + card->devname, + XILINX_DMA_RX_INTR_PENDING_REG,dma_rx_reg, + card->u.xilinx.active_ch_map); + + dma_rx_reg&=card->u.xilinx.active_ch_map; + + if (dma_rx_reg == 0 && rx_fifo_status == 0){ + goto isr_skb_rx; + } + + for (i=0; iu.xilinx.logic_ch_map)){ + + chan=(private_area_t*)card->u.xilinx.dev_to_ch_map[i]; + if (!chan){ + DEBUG_EVENT("%s: Error: No Dev for Rx logical ch=%i\n", + card->devname,i); + continue; + } + + if (!wan_test_bit(0,&chan->up)){ + DEBUG_EVENT("%s: Error: Dev not up for Rx logical ch=%i\n", + card->devname,i); + continue; + } + +#if 0 + chan->if_stats.rx_frame_errors++; +#endif + + DEBUG_ISR("%s: RX Interrupt pend. \n", + card->devname); + xilinx_dma_rx_complete(card,chan,0); + skip_rx_wtd=1; + } + } +isr_skb_rx: + + /* Transmit DMA Engine */ + + card->hw_iface.bus_read_4(card->hw, + XILINX_DMA_TX_INTR_PENDING_REG, + &dma_tx_reg); + + dma_tx_reg&=card->u.xilinx.active_ch_map; + + DEBUG_TEST("%s: DMA_TX_INTR_REG(0x%X) = 0x%X, ChMap=0x%lX NumofCh=%i\n", + card->devname, + XILINX_DMA_TX_INTR_PENDING_REG, + dma_tx_reg, + card->u.xilinx.active_ch_map, + num_of_logic_ch); + + if (dma_tx_reg == 0){ + goto isr_skb_tx; + } + + for (i=0; iu.xilinx.logic_ch_map)){ + chan=(private_area_t*)card->u.xilinx.dev_to_ch_map[i]; + if (!chan){ + DEBUG_EVENT("%s: Error: No Dev for Tx logical ch=%i\n", + card->devname,i); + continue; + } + + if (!wan_test_bit(0,&chan->up)){ + DEBUG_EVENT("%s: Error: Dev not up for Tx logical ch=%i\n", + card->devname,i); + continue; + } + + + DEBUG_TEST("---- TX Interrupt pend. --\n"); + xilinx_dma_tx_complete(card,chan,0); + + }else{ + DEBUG_EVENT("Failed Testing for Tx Timeslot %i TxReg=0x%X ChMap=0x%lX\n",i, + dma_tx_reg,card->u.xilinx.logic_ch_map); + } + } + } + +isr_skb_tx: + + DEBUG_ISR("---- ISR SKB TX end.-------------------\n"); + + if (wan_test_bit(AFT_TE3_TX_WDT_INTR_PND,®)){ + aft_reset_tx_watchdog(card); + chan=(private_area_t*)card->u.xilinx.dev_to_ch_map[0]; + if (chan && wan_test_bit(0,&chan->up)){ +#if 0 + ++chan->if_stats.tx_dropped; +#endif + xilinx_dma_tx_complete (card,chan,1); + } + DEBUG_TEST("%s: Tx WatchDog Expired!\n",card->devname); + aft_reset_tx_watchdog(card); + } + + if (wan_test_bit(AFT_TE3_RX_WDT_INTR_PND,®)){ + aft_reset_rx_watchdog(card); + chan=(private_area_t*)card->u.xilinx.dev_to_ch_map[0]; + if (!skip_rx_wtd && chan && wan_test_bit(0,&chan->up)){ +#if 0 + chan->if_stats.rx_dropped++; +#endif + xilinx_dma_rx_complete (card,chan,1); + }else{ + if (chan){ + DEBUG_TEST("%s: Skipping Rx WTD Flags=%d\n", + chan->if_name,wan_test_bit(0,&chan->up)); + } + aft_reset_rx_watchdog(card); + aft_enable_rx_watchdog(card,AFT_MAX_WTD_TIMEOUT); + } + + DEBUG_TEST("%s: Rx WatchDog Expired %p!\n", + card->devname,chan); + } + + + /* -----------------2/6/2003 10:36AM----------------- + * Finish of the interupt handler + * --------------------------------------------------*/ +#if 0 +isr_end: +#endif + DEBUG_ISR("---- ISR end.-------------------\n"); + wan_clear_bit(0,&card->in_isr); + return; +} + + + +/**SECTION*********************************************************** + * + * WANPIPE Debugging Interfaces + * + ********************************************************************/ + + + +/*============================================================================= + * process_udp_mgmt_pkt + * + * Process all "wanpipemon" debugger commands. This function + * performs all debugging tasks: + * + * Line Tracing + * Line/Hardware Statistics + * Protocol Statistics + * + * "wanpipemon" utility is a user-space program that + * is used to debug the WANPIPE product. + * + */ +#if 1 +static int process_udp_mgmt_pkt(sdla_t* card, struct net_device* dev, + private_area_t* chan, int local_dev ) +{ + unsigned short buffer_length; + wan_udp_pkt_t *wan_udp_pkt; + struct timeval tv; + wan_trace_t *trace_info=NULL; + + wan_udp_pkt = (wan_udp_pkt_t *)chan->udp_pkt_data; + + if (wan_atomic_read(&chan->udp_pkt_len) == 0){ + return -ENODEV; + } + + trace_info=&chan->trace_info; + wan_udp_pkt = (wan_udp_pkt_t *)chan->udp_pkt_data; + + { + + struct sk_buff *skb; + + wan_udp_pkt->wan_udp_opp_flag = 0; + + switch(wan_udp_pkt->wan_udp_command) { + + case READ_CONFIGURATION: + case READ_CODE_VERSION: + wan_udp_pkt->wan_udp_return_code = 0; + wan_udp_pkt->wan_udp_data_len=0; + break; + + + case ENABLE_TRACING: + + wan_udp_pkt->wan_udp_return_code = WAN_CMD_OK; + wan_udp_pkt->wan_udp_data_len = 0; + + if (!wan_test_bit(0,&trace_info->tracing_enabled)){ + + trace_info->trace_timeout = SYSTEM_TICKS; + + wan_trace_purge(trace_info); + + if (wan_udp_pkt->wan_udp_data[0] == 0){ + wan_clear_bit(1,&trace_info->tracing_enabled); + DEBUG_UDP("%s: ADSL L3 trace enabled!\n", + card->devname); + }else if (wan_udp_pkt->wan_udp_data[0] == 1){ + wan_clear_bit(2,&trace_info->tracing_enabled); + wan_set_bit(1,&trace_info->tracing_enabled); + DEBUG_UDP("%s: ADSL L2 trace enabled!\n", + card->devname); + }else{ + wan_clear_bit(1,&trace_info->tracing_enabled); + wan_set_bit(2,&trace_info->tracing_enabled); + DEBUG_UDP("%s: ADSL L1 trace enabled!\n", + card->devname); + } + set_bit (0,&trace_info->tracing_enabled); + + }else{ + DEBUG_EVENT("%s: Error: ATM trace running!\n", + card->devname); + wan_udp_pkt->wan_udp_return_code = 2; + } + + break; + + case DISABLE_TRACING: + + wan_udp_pkt->wan_udp_return_code = WAN_CMD_OK; + + if(wan_test_bit(0,&trace_info->tracing_enabled)) { + + wan_clear_bit(0,&trace_info->tracing_enabled); + wan_clear_bit(1,&trace_info->tracing_enabled); + wan_clear_bit(2,&trace_info->tracing_enabled); + + wan_trace_purge(trace_info); + + DEBUG_UDP("%s: Disabling ADSL trace\n", + card->devname); + + }else{ + /* set return code to line trace already + disabled */ + wan_udp_pkt->wan_udp_return_code = 1; + } + + break; + + case GET_TRACE_INFO: + + if(wan_test_bit(0,&trace_info->tracing_enabled)){ + trace_info->trace_timeout = SYSTEM_TICKS; + }else{ + DEBUG_EVENT("%s: Error ATM trace not enabled\n", + card->devname); + /* set return code */ + wan_udp_pkt->wan_udp_return_code = 1; + break; + } + + buffer_length = 0; + wan_udp_pkt->wan_udp_atm_num_frames = 0; + wan_udp_pkt->wan_udp_atm_ismoredata = 0; + +#if defined(__FreeBSD__) || defined(__OpenBSD__) + while (wan_trace_queue_len(trace_info)){ + WAN_IFQ_POLL(&trace_info->trace_queue, skb); + if (skb == NULL){ + DEBUG_EVENT("%s: No more trace packets in trace queue!\n", + card->devname); + break; + } + if ((WAN_MAX_DATA_SIZE - buffer_length) < skb->m_pkthdr.len){ + /* indicate there are more frames on board & exit */ + wan_udp_pkt->wan_udp_atm_ismoredata = 0x01; + break; + } + + m_copydata(skb, + 0, + skb->m_pkthdr.len, + &wan_udp_pkt->wan_udp_data[buffer_length]); + buffer_length += skb->m_pkthdr.len; + WAN_IFQ_DEQUEUE(&trace_info->trace_queue, skb); + if (skb){ + wan_skb_free(skb); + } + wan_udp_pkt->wan_udp_atm_num_frames++; + } +#elif defined(__LINUX__) + while ((skb=skb_dequeue(&trace_info->trace_queue)) != NULL){ + + if((MAX_TRACE_BUFFER - buffer_length) < wan_skb_len(skb)){ + /* indicate there are more frames on board & exit */ + wan_udp_pkt->wan_udp_atm_ismoredata = 0x01; + if (buffer_length != 0){ + wan_skb_queue_head(&trace_info->trace_queue, skb); + }else{ + /* If rx buffer length is greater than the + * whole udp buffer copy only the trace + * header and drop the trace packet */ + + memcpy(&wan_udp_pkt->wan_udp_atm_data[buffer_length], + wan_skb_data(skb), + sizeof(wan_trace_pkt_t)); + + buffer_length = sizeof(wan_trace_pkt_t); + wan_udp_pkt->wan_udp_atm_num_frames++; + wan_skb_free(skb); + } + break; + } + + memcpy(&wan_udp_pkt->wan_udp_atm_data[buffer_length], + wan_skb_data(skb), + wan_skb_len(skb)); + + buffer_length += wan_skb_len(skb); + wan_skb_free(skb); + wan_udp_pkt->wan_udp_atm_num_frames++; + } +#endif + /* set the data length and return code */ + wan_udp_pkt->wan_udp_data_len = buffer_length; + wan_udp_pkt->wan_udp_return_code = WAN_CMD_OK; + break; + + case ROUTER_UP_TIME: + do_gettimeofday( &tv ); + chan->router_up_time = tv.tv_sec - + chan->router_start_time; + *(unsigned long *)&wan_udp_pkt->wan_udp_data = + chan->router_up_time; + wan_udp_pkt->wan_udp_data_len = sizeof(unsigned long); + wan_udp_pkt->wan_udp_return_code = 0; + break; + + case WAN_GET_MEDIA_TYPE: + case WAN_FE_GET_STAT: + case WAN_FE_SET_LB_MODE: + case WAN_FE_FLUSH_PMON: + case WAN_FE_GET_CFG: + + if (IS_TE3(&card->fe.fe_cfg)){ + WAN_FECALL(&card->wandev, process_udp, + (&card->fe, + &wan_udp_pkt->wan_udp_cmd, + &wan_udp_pkt->wan_udp_data[0])); + }else{ + wan_udp_pkt->wan_udp_return_code = WAN_UDP_INVALID_CMD; + } + break; + + + + case WAN_GET_PROTOCOL: + wan_udp_pkt->wan_udp_aft_num_frames = card->wandev.config_id; + wan_udp_pkt->wan_udp_return_code = CMD_OK; + wan_udp_pkt->wan_udp_data_len = 1; + break; + + case WAN_GET_PLATFORM: + wan_udp_pkt->wan_udp_data[0] = WAN_LINUX_PLATFORM; + wan_udp_pkt->wan_udp_return_code = CMD_OK; + wan_udp_pkt->wan_udp_data_len = 1; + break; + + default: + wan_udp_pkt->wan_udp_data_len = 0; + wan_udp_pkt->wan_udp_return_code = 0xCD; + + if (net_ratelimit()){ + DEBUG_EVENT( + "%s: Warning, Illegal UDP command attempted from network: %x\n", + card->devname,wan_udp_pkt->wan_udp_command); + } + break; + } /* end of switch */ + } /* end of else */ + + /* Fill UDP TTL */ + wan_udp_pkt->wan_ip_ttl= card->wandev.ttl; + + wan_udp_pkt->wan_udp_request_reply = UDPMGMT_REPLY; + return 1; + +} +#endif + + + +/**SECTION************************************************************* + * + * TASK Functions and Triggers + * + **********************************************************************/ + + +/*============================================================================ + * port_set_state + * + * Set PORT state. + * + */ +static void port_set_state (sdla_t *card, int state) +{ + struct wan_dev_le *devle; + netdevice_t *dev; + + if (card->wandev.state != state) + { +#if 0 + switch (state) + { + case WAN_CONNECTED: + DEBUG_EVENT( "%s: Link connected!\n", + card->devname); + break; + + case WAN_CONNECTING: + DEBUG_EVENT( "%s: Link connecting...\n", + card->devname); + break; + + case WAN_DISCONNECTED: + DEBUG_EVENT( "%s: Link disconnected!\n", + card->devname); + break; + } +#endif + card->wandev.state = state; + WAN_LIST_FOREACH(devle, &card->wandev.dev_head, dev_link){ + dev = WAN_DEVLE2DEV(devle); + if (!dev) continue; + set_chan_state(card, dev, state); + } + } +} + +/*============================================================ + * handle_front_end_state + * + * Front end state indicates the physical medium that + * the Z80 backend connects to. + * + * S514-1/2/3: V32/RS232/FT1 Front End + * Front end state is determined via + * Modem/Status. + * S514-4/5/7/8: 56K/T1/E1 Front End + * Front end state is determined via + * link status interrupt received + * from the front end hardware. + * + * If the front end state handler is enabed by the + * user. The interface state will follow the + * front end state. I.E. If the front end goes down + * the protocol and interface will be declared down. + * + * If the front end state is UP, then the interface + * and protocol will be up ONLY if the protocol is + * also UP. + * + * Therefore, we must have three state variables + * 1. Front End State (card->wandev.front_end_status) + * 2. Protocol State (card->wandev.state) + * 3. Interface State (dev->flags & IFF_UP) + * + */ + +static void handle_front_end_state(void *card_id) +{ + sdla_t *card = (sdla_t*)card_id; + unsigned char status; + + if (card->wandev.ignore_front_end_status == WANOPT_YES){ + return; + } + + WAN_FECALL(&card->wandev, get_fe_status, (&card->fe, &status)); + if (status == FE_CONNECTED){ + if (card->wandev.state != WAN_CONNECTED){ + port_set_state(card,WAN_CONNECTED); + enable_data_error_intr(card); + aft_te3_led_ctrl(card, WAN_AFT_RED, 0,WAN_AFT_OFF); + aft_te3_led_ctrl(card, WAN_AFT_GREEN, 0, WAN_AFT_ON); + card->u.xilinx.state_change_exit_isr=1; + }else{ + } + }else{ + if (card->wandev.state != WAN_DISCONNECTED){ + port_set_state(card,WAN_DISCONNECTED); + disable_data_error_intr(card,LINK_DOWN); + aft_te3_led_ctrl(card, WAN_AFT_RED, 0,WAN_AFT_ON); + aft_te3_led_ctrl(card, WAN_AFT_GREEN, 0, WAN_AFT_OFF); + card->u.xilinx.state_change_exit_isr=1; + } + } +} + +#if 0 +static unsigned char read_cpld(sdla_t *card, unsigned short cpld_off) +{ + + u16 org_off; + u8 tmp; + + cpld_off &= ~BIT_DEV_ADDR_CLEAR; + cpld_off |= BIT_DEV_ADDR_CPLD; + + /*ALEX: Save the current address. */ + card->hw_iface.bus_read_2(card->hw, + XILINX_MCPU_INTERFACE_ADDR, + &org_off); + card->hw_iface.bus_write_2(card->hw, + XILINX_MCPU_INTERFACE_ADDR, + cpld_off); + + card->hw_iface.bus_read_1(card->hw,XILINX_MCPU_INTERFACE, &tmp); + + /*ALEX: Restore original address */ + card->hw_iface.bus_write_2(card->hw, + XILINX_MCPU_INTERFACE_ADDR, + org_off); + return tmp; + + +} +#endif + +static int write_cpld(void *pcard, unsigned short off,unsigned char data) +{ + sdla_t *card = (sdla_t*)pcard; + u16 org_off; + + off &= ~BIT_DEV_ADDR_CLEAR; + off |= BIT_DEV_ADDR_CPLD; + + /*ALEX: Save the current original address */ + card->hw_iface.bus_read_2(card->hw, + XILINX_MCPU_INTERFACE_ADDR, + &org_off); + + /* This delay is required to avoid bridge optimization + * (combining two writes together)*/ + udelay(5); + + card->hw_iface.bus_write_2(card->hw, + XILINX_MCPU_INTERFACE_ADDR, + off); + + /* This delay is required to avoid bridge optimization + * (combining two writes together)*/ + udelay(5); + + card->hw_iface.bus_write_1(card->hw, + XILINX_MCPU_INTERFACE, + data); + /*ALEX: Restore the original address */ + card->hw_iface.bus_write_2(card->hw, + XILINX_MCPU_INTERFACE_ADDR, + org_off); + return 0; +} + +#if 0 +static unsigned char write_front_end_reg (void* card1, unsigned short off, unsigned char value) +{ + sdla_t* card = (sdla_t*)card1; + + off &= ~BIT_DEV_ADDR_CLEAR; + card->hw_iface.bus_write_2(card->hw,XILINX_MCPU_INTERFACE_ADDR, off); + /* NC: Mar 25 2004 + * This delays are required to avoid bridge optimization + * (combining two writes together) + */ + udelay(5); + card->hw_iface.bus_write_1(card->hw,XILINX_MCPU_INTERFACE, value); + udelay(5); + + return 0; +} + +/*============================================================================ + * Read TE1/56K Front end registers + */ +static unsigned char read_front_end_reg (void* card1, unsigned short off) +{ + sdla_t* card = (sdla_t*)card1; + u8 tmp; + + off &= ~BIT_DEV_ADDR_CLEAR; + card->hw_iface.bus_write_2(card->hw, XILINX_MCPU_INTERFACE_ADDR, off); + card->hw_iface.bus_read_1(card->hw,XILINX_MCPU_INTERFACE, &tmp); + udelay(5); + + return tmp; +} +#endif + +static int xilinx_read(sdla_t *card, wan_cmd_api_t *api_cmd) +{ + + if (api_cmd->offset <= 0x3C){ + card->hw_iface.pci_read_config_dword(card->hw, + api_cmd->offset, + (u32*)&api_cmd->data[0]); + api_cmd->len=4; + + }else{ + card->hw_iface.peek(card->hw, api_cmd->offset, &api_cmd->data[0], api_cmd->len); + } + +#ifdef DEB_XILINX + DEBUG_EVENT("%s: Reading Bar%i Offset=0x%X Len=%i\n", + card->devname,api_cmd->bar,api_cmd->offset,api_cmd->len); +#endif + + return 0; +} + +static int xilinx_write(sdla_t *card, wan_cmd_api_t *api_cmd) +{ + +#ifdef DEB_XILINX + DEBUG_EVENT("%s: Writting Bar%i Offset=0x%X Len=%i\n", + card->devname, + api_cmd->bar,api_cmd->offset,api_cmd->len); +#endif + +#if 0 + card->hw_iface.poke(card->hw, api_cmd->offset, &api_cmd->data[0], api_cmd->len); +#endif + if (api_cmd->len == 1){ + card->hw_iface.bus_write_1( + card->hw, + api_cmd->offset, + (u8)api_cmd->data[0]); + }else if (api_cmd->len == 2){ + card->hw_iface.bus_write_2( + card->hw, + api_cmd->offset, + *(u16*)&api_cmd->data[0]); + }else if (api_cmd->len == 4){ + card->hw_iface.bus_write_4( + card->hw, + api_cmd->offset, + *(u32*)&api_cmd->data[0]); + }else{ + card->hw_iface.poke( + card->hw, + api_cmd->offset, + &api_cmd->data[0], + api_cmd->len); + } + + return 0; +} + +static int xilinx_write_bios(sdla_t *card, wan_cmd_api_t *api_cmd) +{ +#ifdef DEB_XILINX + DEBUG_EVENT("Setting PCI 0x%X=0x%08lX 0x3C=0x%08X\n", + (card->wandev.S514_cpu_no[0] == SDLA_CPU_A) ? 0x10 : 0x14, + card->u.xilinx.bar,card->wandev.irq); +#endif + card->hw_iface.pci_write_config_dword(card->hw, + (card->wandev.S514_cpu_no[0] == SDLA_CPU_A) ? 0x10 : 0x14, + card->u.xilinx.bar); + card->hw_iface.pci_write_config_dword(card->hw, 0x3C, card->wandev.irq); + card->hw_iface.pci_write_config_dword(card->hw, 0x0C, 0x0000ff00); + + return 0; +} + +static int aft_devel_ioctl(sdla_t *card,struct ifreq *ifr) +{ + wan_cmd_api_t api_cmd; + int err; + + if (!ifr || !ifr->ifr_data){ + DEBUG_EVENT("%s: Error: No ifr or ifr_data\n",__FUNCTION__); + return -EINVAL; + } + + if (copy_from_user(&api_cmd,ifr->ifr_data,sizeof(wan_cmd_api_t))){ + return -EFAULT; + } + + switch(api_cmd.cmd){ + + case SDLA_HDLC_READ_REG: + case SIOC_WAN_READ_REG: + err=xilinx_read(card, &api_cmd); + break; + + case SIOC_WAN_WRITE_REG: + case SDLA_HDLC_WRITE_REG: + err=xilinx_write(card, &api_cmd); + break; + + case SDLA_HDLC_SET_PCI_BIOS: + err=xilinx_write_bios(card, &api_cmd); + break; + } + + if (copy_to_user(ifr->ifr_data,&api_cmd,sizeof(wan_cmd_api_t))){ + return -EFAULT; + } + return 0; +} + +/*========================================= + * enable_data_error_intr + * + * Description: + * + * Run only after the front end comes + * up from down state. + * + * Clean the DMA Tx/Rx pending interrupts. + * (Ignore since we will reconfigure + * all dma descriptors. DMA controler + * was already disabled on link down) + * + * For all channels clean Tx/Rx Fifo + * + * Enable DMA controler + * (This starts the fifo cleaning + * process) + * + * For all channels reprogram Tx/Rx DMA + * descriptors. + * + * Clean the Tx/Rx Error pending interrupts. + * (Since dma fifo's are now empty) + * + * Enable global DMA and Error interrutps. + * + */ + +static void enable_data_error_intr(sdla_t *card) +{ + struct wan_dev_le *devle; + u32 reg; + netdevice_t *dev; + + DEBUG_TEST("%s: %s() !!!\n", + card->devname,__FUNCTION__); + + + /* Clean Tx/Rx DMA interrupts */ + card->hw_iface.bus_read_4(card->hw, + XILINX_DMA_RX_INTR_PENDING_REG, ®); + card->hw_iface.bus_read_4(card->hw, + XILINX_DMA_TX_INTR_PENDING_REG, ®); + + + /* For all channels clean Tx/Rx fifos */ + WAN_LIST_FOREACH(devle, &card->wandev.dev_head, dev_link){ + private_area_t *chan; + + dev = WAN_DEVLE2DEV(devle); + if (!dev || !wan_netif_priv(dev)) + continue; + chan = wan_netif_priv(dev); + + if (!wan_test_bit(0,&chan->up)){ + continue; + } + + aft_list_descriptors(chan); + + DEBUG_TEST("%s: 1) Free Used DMA CHAINS %s\n", + card->devname,chan->if_name); + + aft_rx_dma_chain_handler(chan,0,1); + aft_free_rx_complete_list(chan); + + + aft_list_descriptors(chan); + + DEBUG_TEST("%s: 1) Free UNUSED DMA CHAINS %s\n", + card->devname,chan->if_name); + + aft_free_rx_descriptors(chan); + + aft_free_tx_descriptors(chan); + + + DEBUG_TEST("%s: 2) Init interface fifo no wait %s\n", + card->devname,chan->if_name); + + xilinx_init_rx_dev_fifo(card, chan, WP_NO_WAIT); + xilinx_init_tx_dev_fifo(card, chan, WP_NO_WAIT); + + aft_list_descriptors(chan); + } + + + + if (card->fe.fe_cfg.cfg.te3_cfg.fractional){ + card->hw_iface.bus_read_4(card->hw,TE3_FRACT_ENCAPSULATION_REG,®); + + DEBUG_EVENT("%s: Rx Fractional Frame Size = 0x%lX\n", + card->devname, + get_te3_rx_fract_frame_size(reg)); + + /* FIXME: Setup bitrate and tx frame size */ + } + + + /* Enable DMA controler, in order to start the + * fifo cleaning */ + reg=0; + reg|=(AFT_T3_DMA_FIFO_MARK << DMA_FIFO_T3_MARK_BIT_SHIFT); + reg|=(MAX_AFT_DMA_CHAINS-1)&DMA_CHAIN_TE3_MASK; + + wan_set_bit(DMA_RX_ENGINE_ENABLE_BIT,®); + wan_set_bit(DMA_TX_ENGINE_ENABLE_BIT,®); + card->hw_iface.bus_write_4(card->hw,XILINX_DMA_CONTROL_REG,reg); + + /* For all channels clean Tx/Rx fifos */ + WAN_LIST_FOREACH(devle, &card->wandev.dev_head, dev_link){ + private_area_t *chan; + + dev = WAN_DEVLE2DEV(devle); + if (!dev || !wan_netif_priv(dev)) + continue; + chan = wan_netif_priv(dev); + + if (!wan_test_bit(0,&chan->up)){ + continue; + } + + DEBUG_TEST("%s: 3) Init interface fifo %s\n", + card->devname,chan->if_name); + + xilinx_init_rx_dev_fifo(card, chan, WP_WAIT); + xilinx_init_tx_dev_fifo(card, chan, WP_WAIT); + + DEBUG_TEST("%s: Clearing Fifo and idle_flag %s\n", + card->devname,chan->if_name); + wan_clear_bit(0,&chan->idle_start); + } + + /* For all channels, reprogram Tx/Rx DMA descriptors. + * For Tx also make sure that the BUSY flag is clear + * and previoulsy Tx packet is deallocated */ + + WAN_LIST_FOREACH(devle, &card->wandev.dev_head, dev_link){ + private_area_t *chan; + + dev = WAN_DEVLE2DEV(devle); + if (!dev || !wan_netif_priv(dev)) + continue; + chan = wan_netif_priv(dev); + + if (!wan_test_bit(0,&chan->up)){ + continue; + } + + DEBUG_TEST("%s: 4) Init interface %s\n", + card->devname,chan->if_name); + + xilinx_dma_rx(card,chan,-1); + + aft_list_descriptors(chan); + + DEBUG_TEST("%s: Clearing Fifo and idle_flag %s\n", + card->devname,chan->if_name); + + } + + /* Clean Tx/Rx Error interrupts, since fifos are now + * empty, and Tx fifo may generate an underrun which + * we want to ignore :) */ + + card->hw_iface.bus_read_4(card->hw, + XILINX_HDLC_RX_INTR_PENDING_REG, ®); + card->hw_iface.bus_read_4(card->hw, + XILINX_HDLC_TX_INTR_PENDING_REG, ®); + + /* Enable Global DMA and Error Interrupts */ + reg=0; + card->hw_iface.bus_read_4(card->hw,XILINX_CHIP_CFG_REG,®); + wan_set_bit(GLOBAL_INTR_ENABLE_BIT,®); + wan_set_bit(ERROR_INTR_ENABLE_BIT,®); + card->hw_iface.bus_write_4(card->hw,XILINX_CHIP_CFG_REG,reg); + + + card->hw_iface.bus_read_4(card->hw,XILINX_DMA_CONTROL_REG,®); + + aft_enable_rx_watchdog(card,AFT_RX_TIMEOUT); + aft_enable_tx_watchdog(card,AFT_TX_TIMEOUT); + + DEBUG_TEST("%s: END !!! Dma=0x%08X\n", + __FUNCTION__,reg); + +} + +static void disable_data_error_intr(sdla_t *card, unsigned char event) +{ + u32 reg; +#if 0 + private_area_t *chan; + + card->hw_iface.bus_read_4(card->hw,XILINX_CHIP_CFG_REG,®); + wan_clear_bit(GLOBAL_INTR_ENABLE_BIT,®); + wan_clear_bit(ERROR_INTR_ENABLE_BIT,®); + wan_clear_bit(FRONT_END_INTR_ENABLE_BIT,®); + wan_clear_bit(ENABLE_TE3_FRACTIONAL,®); + card->hw_iface.bus_write_4(card->hw,XILINX_CHIP_CFG_REG,reg); + + aft_reset_rx_watchdog(card); + aft_reset_tx_watchdog(card); + + chan=(private_area_t*)card->u.xilinx.dev_to_ch_map[0]; + if (chan && wan_test_bit(0,&chan->up)){ + xilinx_dev_close(card,chan); + WAN_NETIF_STOP_QUEUE(chan->common.dev); + WAN_TASKLET_KILL(&chan->common.bh_task); + } + + xilinx_t3_exar_chip_unconfigure(card); + + udelay(10500); + + xilinx_t3_exar_chip_configure(card); + if (chan && wan_test_bit(0,&chan->up)){ + udelay(500); + xilinx_t3_exar_dev_configure(card,chan); + udelay(500); + xilinx_dev_enable(card, chan); + WAN_TASKLET_INIT((&chan->common.bh_task),0,wp_bh,(unsigned long)chan); + } +#endif + + + card->hw_iface.bus_read_4(card->hw,XILINX_CHIP_CFG_REG,®); + wan_clear_bit(GLOBAL_INTR_ENABLE_BIT,®); + wan_clear_bit(ERROR_INTR_ENABLE_BIT,®); + if (event==DEVICE_DOWN){ + wan_clear_bit(FRONT_END_INTR_ENABLE_BIT,®); + wan_clear_bit(ENABLE_TE3_FRACTIONAL,®); + } + card->hw_iface.bus_write_4(card->hw,XILINX_CHIP_CFG_REG,reg); + + card->hw_iface.bus_read_4(card->hw,XILINX_DMA_CONTROL_REG,®); + wan_clear_bit(DMA_RX_ENGINE_ENABLE_BIT,®); + wan_clear_bit(DMA_TX_ENGINE_ENABLE_BIT,®); + card->hw_iface.bus_write_4(card->hw,XILINX_DMA_CONTROL_REG,reg); + + aft_reset_rx_watchdog(card); + aft_reset_tx_watchdog(card); + + if (event==DEVICE_DOWN){ + wan_set_bit(CARD_DOWN,&card->wandev.critical); + } + + + DEBUG_TEST("%s: Event = %s\n",__FUNCTION__, + event==DEVICE_DOWN?"Device Down": "Link Down"); + +} + +static void xilinx_init_tx_dma_descr(sdla_t *card, private_area_t *chan) +{ + unsigned long dma_descr; + unsigned long reg=0; + + dma_descr=(chan->logic_ch_num<<4) + XILINX_TxDMA_DESCRIPTOR_HI; + card->hw_iface.bus_write_4(card->hw,dma_descr, reg); +} + + + +/*============================================================================ + * Update communications error and general packet statistics. + */ +static int update_comms_stats(sdla_t* card) +{ + /* 1. On the first timer interrupt, update T1/E1 alarms + * and PMON counters (only for T1/E1 card) (TE1) + */ + + /* TE1 Update T1/E1 alarms */ + if (IS_TE3(&card->fe.fe_cfg)) { + WAN_FECALL(&card->wandev, read_alarm, (&card->fe, 0)); + /* TE1 Update T1/E1 perfomance counters */ + WAN_FECALL(&card->wandev, read_pmon, (&card->fe)); + } + + return 0; +} + +static void xilinx_tx_fifo_under_recover (sdla_t *card, private_area_t *chan) +{ + +#if 1 + u32 reg; + /* Enable DMA controler, in order to start the + * fifo cleaning */ + card->hw_iface.bus_read_4(card->hw,XILINX_DMA_CONTROL_REG,®); + wan_clear_bit(DMA_TX_ENGINE_ENABLE_BIT,®); + card->hw_iface.bus_write_4(card->hw,XILINX_DMA_CONTROL_REG,reg); +#endif + +#if 0 + aft_list_tx_descriptors(chan); +#endif + aft_free_tx_descriptors(chan); + +#if 1 + xilinx_init_tx_dev_fifo(card,chan,WP_NO_WAIT); + + card->hw_iface.bus_read_4(card->hw,XILINX_DMA_CONTROL_REG,®); + wan_set_bit(DMA_TX_ENGINE_ENABLE_BIT,®); + card->hw_iface.bus_write_4(card->hw,XILINX_DMA_CONTROL_REG,reg); + + xilinx_init_tx_dev_fifo(card,chan,WP_WAIT); +#endif + wan_clear_bit(0,&chan->idle_start); + + WAN_NETIF_WAKE_QUEUE(chan->common.dev); +#ifndef CONFIG_PRODUCT_WANPIPE_GENERIC + if (chan->common.usedby == API){ + wan_wakeup_api(chan); + }else if (chan->common.usedby == STACK){ + wanpipe_lip_kick(chan,0); + } +#endif + aft_enable_tx_watchdog(card,AFT_TX_TIMEOUT); +} + +static int xilinx_write_ctrl_hdlc(sdla_t *card, u32 timeslot, u8 reg_off, u32 data) +{ + /* M.F. for Exar T3 card direct access + * without analize current timeslot */ + + card->hw_iface.bus_write_4(card->hw,reg_off,data); + + return 0; +} + +static int set_chan_state(sdla_t* card, netdevice_t* dev, int state) +{ + private_area_t *chan = dev->priv; + + chan->common.state = state; + if (state == WAN_CONNECTED){ + wan_clear_bit(0,&chan->idle_start); + aft_te3_led_ctrl(card, WAN_AFT_RED, 1, WAN_AFT_OFF); + aft_te3_led_ctrl(card, WAN_AFT_GREEN, 1,WAN_AFT_ON); + WAN_NETIF_CARRIER_ON(dev); + WAN_NETIF_WAKE_QUEUE(dev); + }else{ + aft_te3_led_ctrl(card, WAN_AFT_RED, 1, WAN_AFT_ON); + aft_te3_led_ctrl(card, WAN_AFT_GREEN, 1,WAN_AFT_OFF); + WAN_NETIF_CARRIER_OFF(dev); + WAN_NETIF_STOP_QUEUE(dev); + } + +#if defined(__LINUX__) +# if !defined(CONFIG_PRODUCT_WANPIPE_GENERIC) + if (chan->common.usedby == API){ + wan_update_api_state(chan); + } + + if (chan->common.usedby == STACK){ + if (state == WAN_CONNECTED){ + wanpipe_lip_connect(chan,0); + }else{ + wanpipe_lip_disconnect(chan,0); + } + } +#endif +#endif + return 0; +} + + + +/**SECTION************************************************************* + * + * Protocol API Support Functions + * + **********************************************************************/ + + +static int protocol_init (sdla_t *card, netdevice_t *dev, + private_area_t *chan, + wanif_conf_t* conf) +{ + + chan->common.protocol = conf->protocol; + + DEBUG_TEST("%s: Protocol init 0x%X PPP=0x0%x FR=0x0%X\n", + wan_netif_name(dev), chan->common.protocol, + WANCONFIG_PPP, + WANCONFIG_FR); + +#ifndef CONFIG_PRODUCT_WANPIPE_GENERIC + + DEBUG_EVENT("%s: AFT Driver doesn't directly support any protocols!\n", + chan->if_name); + return -1; + +#else + if (chan->common.protocol == WANCONFIG_PPP || + chan->common.protocol == WANCONFIG_CHDLC){ + + struct ifreq ifr; + struct if_settings ifsettings; + + wanpipe_generic_register(card, dev, wan_netif_name(dev)); + chan->common.prot_ptr = dev; + + if (chan->common.protocol == WANCONFIG_CHDLC){ + DEBUG_EVENT("%s: Starting Kernel CISCO HDLC protocol\n", + chan->if_name); + ifsettings.type = IF_PROTO_CISCO; + }else{ + DEBUG_EVENT("%s: Starting Kernel Sync PPP protocol\n", + chan->if_name); + ifsettings.type = IF_PROTO_PPP; + + } + ifr.ifr_data = (caddr_t)&ifsettings; + if (wp_lite_set_proto(dev, &ifr)){ + wanpipe_generic_unregister(dev); + return -EINVAL; + } + + }else if (chan->common.protocol == WANCONFIG_GENERIC){ + chan->common.prot_ptr = dev; + + }else{ + DEBUG_EVENT("%s:%s: Unsupported protocol %d\n", + card->devname,chan->if_name,chan->common.protocol); + return -EPROTONOSUPPORT; + } +#endif + + return 0; +} + + +static int protocol_start (sdla_t *card, netdevice_t *dev) +{ + int err=0; + + private_area_t *chan=wan_netif_priv(dev); + + if (!chan) + return 0; + + return err; +} + +static int protocol_stop (sdla_t *card, netdevice_t *dev) +{ + private_area_t *chan=wan_netif_priv(dev); + int err = 0; + + if (!chan) + return 0; + + return err; +} + +static int protocol_shutdown (sdla_t *card, netdevice_t *dev) +{ + private_area_t *chan=wan_netif_priv(dev); + + if (!chan) + return 0; + +#ifndef CONFIG_PRODUCT_WANPIPE_GENERIC + + return 0; +#else + + if (chan->common.protocol == WANCONFIG_PPP || + chan->common.protocol == WANCONFIG_CHDLC){ + + chan->common.prot_ptr = NULL; + wanpipe_generic_unregister(dev); + + }else if (chan->common.protocol == WANCONFIG_GENERIC){ + DEBUG_EVENT("%s:%s Protocol shutdown... \n", + card->devname, chan->if_name); + } +#endif + return 0; +} + +void protocol_recv(sdla_t *card, private_area_t *chan, netskb_t *skb) +{ + +#ifdef CONFIG_PRODUCT_WANPIPE_GENERIC + if (chan->common.protocol == WANCONFIG_PPP || + chan->common.protocol == WANCONFIG_CHDLC){ + wanpipe_generic_input(chan->common.dev, skb); + return 0; + } +#endif + +#if defined(__LINUX__) && defined(CONFIG_PRODUCT_WANPIPE_GENERIC) + if (chan->common.protocol == WANCONFIG_GENERIC){ + skb->protocol = htons(ETH_P_HDLC); + skb->dev = chan->common.dev; + skb->mac.raw = wan_netif_data(skb); + netif_rx(skb); + return 0; + } +#endif + +#if defined(__LINUX__) + skb->protocol = htons(ETH_P_IP); + skb->dev = chan->common.dev; + skb->mac.raw = wan_skb_data(skb); + netif_rx(skb); +#else + DEBUG_EVENT("%s: Action not supported (IP)!\n", + card->devname); + wan_skb_free(skb); +#endif + + return; +} + + +/**SECTION************************************************************* + * + * T3 Exar Config Code + * + **********************************************************************/ + + +/*========================================================= + * xilinx_t3_exar_chip_configure + * + */ + +static int xilinx_t3_exar_chip_configure(sdla_t *card) +{ + u32 reg,tmp; + volatile unsigned char cnt=0; + int err=0; + + DEBUG_CFG("T3 Exar Chip Configuration. -- \n"); + + xilinx_delay(1); + + card->hw_iface.bus_read_4(card->hw,XILINX_CHIP_CFG_REG, ®); + + /* Enable the chip/hdlc reset condition */ + reg=0; + wan_set_bit(CHIP_RESET_BIT,®); + wan_set_bit(FRONT_END_RESET_BIT,®); + + /* Hardcode the AFT T3/E3 clock source + * to External/Normal */ + if (card->fe.fe_cfg.cfg.te3_cfg.clock == WAN_MASTER_CLK){ + wan_set_bit(AFT_T3_CLOCK_MODE,®); + }else{ + wan_clear_bit(AFT_T3_CLOCK_MODE,®); + } + + DEBUG_CFG("--- T3 Exar Chip Reset. -- \n"); + + card->hw_iface.bus_write_4(card->hw,XILINX_CHIP_CFG_REG,reg); + + udelay(10); + + /* Disable the chip/hdlc reset condition */ + wan_clear_bit(CHIP_RESET_BIT,®); + wan_clear_bit(FRONT_END_RESET_BIT,®); + + /* Disable ALL chip interrupts */ + wan_clear_bit(GLOBAL_INTR_ENABLE_BIT,®); + wan_clear_bit(ERROR_INTR_ENABLE_BIT,®); + wan_clear_bit(FRONT_END_INTR_ENABLE_BIT,®); + + /* Configure for T3 or E3 front end */ + + if (IS_DS3(&card->fe.fe_cfg)){ + card->u.xilinx.num_of_time_slots=NUM_OF_T1_CHANNELS; + wan_clear_bit(INTERFACE_TYPE_T3_E3_BIT,®); + if (card->fe.fe_cfg.frame == WAN_FR_DS3_Cbit){ + wan_set_bit(INTERFACE_MODE_DS3_C_BIT,®); + }else{ + wan_clear_bit(INTERFACE_MODE_DS3_C_BIT,®); + } + }else if (IS_E3(&card->fe.fe_cfg)){ + card->u.xilinx.num_of_time_slots=NUM_OF_E1_CHANNELS; + wan_set_bit(INTERFACE_TYPE_T3_E3_BIT,®); + if (card->fe.fe_cfg.frame == WAN_FR_E3_G832){ + wan_set_bit(INTERFACE_MODE_E3_G832,®); + }else{ + wan_clear_bit(INTERFACE_MODE_E3_G832,®); + } + }else{ + DEBUG_EVENT("%s: Error: T3 Exar doesn't support non T3/E3 interface!\n", + card->devname); + return -EINVAL; + } + + /* Hardcode the HDLC Conroller to + * HDLC mode. The transparent mode can be + * configured later in new_if() section + * + * HDLC =clear bit + * TRANSPARENT =set bit + * */ + wan_clear_bit(AFT_T3_HDLC_TRANS_MODE,®); + + + /* Enable/Disable TX and RX Fractional + * HDLC */ + + /* FIXME: HAVE A CONFIG OPTION HERE */ + + /* Enable Internal HDLC Encapsulation core */ + if (card->fe.fe_cfg.cfg.te3_cfg.fractional){ + DEBUG_EVENT("%s: BEFORE TE3 FRACT = 0x%X\n", + card->devname, reg); + + wan_set_bit(ENABLE_TE3_FRACTIONAL,®); + + //te3_enable_fractional(®, TE3_FRACT_VENDOR_KENTROX); + DEBUG_EVENT("%s: AFTER TE3 FRACT = 0x%X\n", + card->devname, reg); + }else{ + wan_clear_bit(ENABLE_TE3_FRACTIONAL,®); + } + + DEBUG_CFG("--- T3 Exar Chip enable/config. -- \n"); + + card->hw_iface.bus_write_4(card->hw,XILINX_CHIP_CFG_REG,reg); + + xilinx_delay(1); +#if 0 + framer_reset(card); /* was for A105 proto */ +#endif /* M.F. remove for A300 */ + +#if 0 + write_cpld(card,0x00, 0x00); /* M.F. was 0x01 for A105 proto */ + /* M.F. 0x00 for A300 */ + /* set DS3 interface mode */ + write_cpld(card,0x01, 0x00); /* clear TxAIS bit */ + + // 3. Setup Framer + write_framer(card,0x00, 0x6F); /* DS3 - mode (bit 6)*/ + /* Internal LOS enable (bit 5)*/ + /* Interrupt enabl.reset(bit 3)*/ + /* Frame format M13 (bit 2)*/ + /* TimRef - Mode 3 (code '1X')*/ + write_framer(card,0x01, 0xA2); /* */ +#else + +//FIXME: Alex to put in Exar T3/E3 Configuration + DEBUG_EVENT("%s: Config %s Front End: Clock=%s\n", + card->devname, + FE_MEDIA_DECODE(&card->fe), + (card->fe.fe_cfg.cfg.te3_cfg.clock == WAN_MASTER_CLK)? + "Master":"Normal"); + + if (sdla_te3_config(&card->fe, &card->wandev.fe_iface)){ + DEBUG_EVENT("%s: Failed %s configuratoin!\n", + card->devname, + FE_MEDIA_DECODE(&card->fe)); + return -EINVAL; + } +#endif + for (;;){ + card->hw_iface.bus_read_4(card->hw,XILINX_CHIP_CFG_REG, ®); + + if (!wan_test_bit(HDLC_CORE_READY_FLAG_BIT,®)){ + /* The HDLC Core is not ready! we have + * an error. */ + if (++cnt > 5){ + err = -EINVAL; + break; + }else{ + udelay(500); + /* FIXME: we cannot do this while in + * critical area */ + } + }else{ + err=0; + break; + } + } + + xilinx_delay(1); + + if (err != 0){ + DEBUG_EVENT("%s: Error: HDLC Core Not Ready!\n", + card->devname); + + card->hw_iface.bus_read_4(card->hw,XILINX_CHIP_CFG_REG, ®); + + /* Disable the chip/hdlc reset condition */ + wan_set_bit(CHIP_RESET_BIT,®); + + card->hw_iface.bus_write_4(card->hw,XILINX_CHIP_CFG_REG,reg); + return err; + } else{ + DEBUG_CFG("%s: HDLC Core Ready 0x%08X\n", + card->devname,reg); + } + + xilinx_delay(1); + + /* Setup global DMA parameters */ + reg=0; + reg|=(AFT_T3_DMA_FIFO_MARK << DMA_FIFO_T3_MARK_BIT_SHIFT); + reg|=(MAX_AFT_DMA_CHAINS-1)&DMA_CHAIN_TE3_MASK; + + /* Enable global DMA engine and set to default + * number of active channels. Note: this value will + * change in dev configuration */ + wan_set_bit(DMA_RX_ENGINE_ENABLE_BIT,®); + wan_set_bit(DMA_TX_ENGINE_ENABLE_BIT,®); + + DEBUG_CFG("--- Setup DMA control Reg. -- \n"); + + card->hw_iface.bus_write_4(card->hw,XILINX_DMA_CONTROL_REG,reg); + DEBUG_CFG("--- Tx/Rx global enable. -- \n"); + + xilinx_delay(1); + + reg=0; + card->hw_iface.bus_write_4(card->hw,XILINX_TIMESLOT_HDLC_CHAN_REG,reg); + + /* Clear interrupt pending registers befor first interrupt enable */ + card->hw_iface.bus_read_4(card->hw, XILINX_DMA_RX_INTR_PENDING_REG, &tmp); + card->hw_iface.bus_read_4(card->hw, XILINX_DMA_TX_INTR_PENDING_REG, &tmp); + card->hw_iface.bus_read_4(card->hw, XILINX_HDLC_RX_INTR_PENDING_REG, &tmp); + card->hw_iface.bus_read_4(card->hw, XILINX_HDLC_TX_INTR_PENDING_REG, &tmp); + + card->hw_iface.bus_read_4(card->hw, XILINX_CHIP_CFG_REG, (u32*)®); + + if (wan_test_bit(DMA_INTR_FLAG,®)){ + DEBUG_EVENT("%s: Error: Active DMA Interrupt Pending. !\n", + card->devname); + + reg = 0; + /* Disable the chip/hdlc reset condition */ + wan_set_bit(CHIP_RESET_BIT,®); + card->hw_iface.bus_write_4(card->hw,XILINX_CHIP_CFG_REG,reg); + return err; + } + if (wan_test_bit(ERROR_INTR_FLAG,®)){ + DEBUG_EVENT("%s: Error: Active Error Interrupt Pending. !\n", + card->devname); + + reg = 0; + /* Disable the chip/hdlc reset condition */ + wan_set_bit(CHIP_RESET_BIT,®); + card->hw_iface.bus_write_4(card->hw,XILINX_CHIP_CFG_REG,reg); + return err; + } + + + /* Alawys disable global data and error + * interrupts */ + wan_clear_bit(GLOBAL_INTR_ENABLE_BIT,®); + wan_clear_bit(ERROR_INTR_ENABLE_BIT,®); + +#ifndef AFT_XTEST_DEBUG + /* Always enable the front end interrupt */ + wan_set_bit(FRONT_END_INTR_ENABLE_BIT,®); +#endif + DEBUG_CFG("--- Set Global Interrupts (0x%X)-- \n",reg); + + xilinx_delay(1); + + card->hw_iface.bus_write_4(card->hw,XILINX_CHIP_CFG_REG,reg); + + DEBUG_CFG("--- Set Global Interrupt enabled. -- \n"); + + return err; +} + +static int xilinx_t3_exar_dev_configure(sdla_t *card, private_area_t *chan) +{ + + u32 reg,reg1; + + DEBUG_TEST("-- T3 Exar Dev Configure Xilinx. --\n"); + + + chan->logic_ch_num=0; + chan->first_time_slot=0; + card->u.xilinx.logic_ch_map=0x01; + + if (!card->u.xilinx.dev_to_ch_map[0]){ + card->u.xilinx.dev_to_ch_map[0]=(void*)chan; + } + + reg=0; + + if (chan->hdlc_eng){ + /* HDLC engine is enabled on the above logical channels */ + wan_clear_bit(HDLC_RX_PROT_DISABLE_BIT,®); + wan_clear_bit(HDLC_TX_PROT_DISABLE_BIT,®); + + wan_set_bit(HDLC_TX_CHAN_ENABLE_BIT,®); + + if (card->fe.fe_cfg.cfg.te3_cfg.fractional){ + DEBUG_EVENT("%s: Configuring for Fractional\n",card->devname); + wan_set_bit(HDLC_RX_ADDR_FIELD_DISC_BIT,®); + wan_set_bit(HDLC_TX_ADDR_INSERTION_BIT,®); + }else{ + wan_set_bit(HDLC_RX_ADDR_RECOGN_DIS_BIT,®); + } + + if (card->fe.fe_cfg.cfg.te3_cfg.fcs == 32){ + wan_set_bit(HDLC_TX_FCS_SIZE_BIT,®); + wan_set_bit(HDLC_RX_FCS_SIZE_BIT,®); + } + + DEBUG_EVENT("%s:%s: Config for HDLC mode: FCS=%d\n", + card->devname,chan->if_name, + card->fe.fe_cfg.cfg.te3_cfg.fcs); + }else{ + + /* Transprent Mode */ + + /* Do not start HDLC Core here, because + * we have to setup Tx/Rx DMA buffers first + * The transparent mode, will start + * comms as soon as the HDLC is enabled */ + + } + + /* Select an HDLC Tx channel for configuration */ + reg1=0; + card->hw_iface.bus_write_4(card->hw, AFT_T3_RXTX_ADDR_SELECT_REG, reg1); + + if (card->fe.fe_cfg.cfg.te3_cfg.fractional){ + xilinx_write_ctrl_hdlc(card, + chan->first_time_slot, + XILINX_HDLC_ADDR_REG, + 0xA5A5A5A5); + } + + xilinx_write_ctrl_hdlc(card, + chan->first_time_slot, + XILINX_HDLC_CONTROL_REG, + reg); + + + /* Select an HDLC Rx channel for configuration */ + reg1=1; + card->hw_iface.bus_write_4(card->hw, AFT_T3_RXTX_ADDR_SELECT_REG, reg1); + + if (card->fe.fe_cfg.cfg.te3_cfg.fractional){ + + xilinx_write_ctrl_hdlc(card, + chan->first_time_slot, + XILINX_HDLC_ADDR_REG, + 0xA5A5A5A5); + } + + xilinx_write_ctrl_hdlc(card, + chan->first_time_slot, + XILINX_HDLC_CONTROL_REG, + reg); + + return 0; + +} + +static void xilinx_t3_exar_dev_unconfigure(sdla_t *card, private_area_t *chan) +{ + /* Nothing to do for T3 Exar */ + unsigned long flags; + + wan_spin_lock_irq(&card->wandev.lock,&flags); + card->u.xilinx.dev_to_ch_map[0]=NULL; + aft_reset_rx_watchdog(card); + aft_reset_tx_watchdog(card); + wan_spin_unlock_irq(&card->wandev.lock,&flags); + +} + +static void xilinx_t3_exar_chip_unconfigure(sdla_t *card) +{ + + u32 reg=0; + + card->hw_iface.bus_read_4(card->hw,XILINX_CHIP_CFG_REG, ®); + + /* Enable the chip/hdlc reset condition */ + wan_set_bit(CHIP_RESET_BIT,®); + wan_set_bit(FRONT_END_RESET_BIT,®); + + card->hw_iface.bus_write_4(card->hw,XILINX_CHIP_CFG_REG,reg); + +} + + +static void xilinx_t3_exar_transparent_config(sdla_t *card,private_area_t *chan) +{ + u32 reg; + + DEBUG_EVENT("%s: Configuring for Transparent mode!\n", + card->devname); + + /* T3/E3 Exar Card */ + card->hw_iface.bus_read_4(card->hw,XILINX_CHIP_CFG_REG, ®); + /* Enable hdlc transparent mode */ + wan_set_bit(AFT_T3_HDLC_TRANS_MODE,®); + card->hw_iface.bus_write_4(card->hw,XILINX_CHIP_CFG_REG,reg); +} + + +#define BIT_DEV_ADDR_CLEAR 0x600 + +static int write_framer(void *pcard, unsigned short framer_off,unsigned short framer_data) +{ + sdla_t *card = (sdla_t*)pcard; + + framer_off &= ~BIT_DEV_ADDR_CLEAR; + + card->hw_iface.bus_write_2(card->hw, + 0x46, + framer_off); + + card->hw_iface.bus_write_2(card->hw, + 0x44, + framer_data); + return 0; +} + +static unsigned int read_framer(void *pcard,unsigned short framer_off) +{ + sdla_t *card = (sdla_t*)pcard; + unsigned int framer_data; + + framer_off &= ~BIT_DEV_ADDR_CLEAR; + + card->hw_iface.bus_write_2(card->hw, + 0x46, + framer_off); + + card->hw_iface.bus_read_4(card->hw, + 0x44, + &framer_data); + return framer_data; +} + +#if 0 +static void framer_reset(sdla_t *card) +{ + int i = 0; + unsigned short j = 0; + + j = (unsigned short)read_cpld(card,0x00); + j = j & 0x00FE; + write_cpld(card,0x00, j); + // delay + for(i=0;i<10;i++); + j = j | 0x0001; + write_cpld(card,0x00, j); +} +#endif + +/**SECTION************************************************************* + * + * TE3 Exar Tx Functions + * DMA Chains + * + **********************************************************************/ + + +/*=============================================== + * aft_tx_dma_chain_handler + * + */ +static void aft_tx_dma_chain_handler(unsigned long data) +{ + private_area_t *chan = (private_area_t *)data; + sdla_t *card = chan->card; + int dma_free=0; + u32 reg,dma_descr; + aft_dma_chain_t *dma_chain; + + if (wan_test_and_set_bit(TX_HANDLER_BUSY,&chan->dma_status)){ + DEBUG_EVENT("%s: SMP Critical in %s\n", + chan->if_name,__FUNCTION__); + return; + } + + dma_chain = &chan->tx_dma_chain_table[chan->tx_pending_chain_indx]; + + for (;;){ + + /* If the current DMA chain is in use,then + * all chains are busy */ + if (!wan_test_bit(0,&dma_chain->init)){ + break; + } + + dma_descr=(chan->tx_pending_chain_indx<<4) + XILINX_TxDMA_DESCRIPTOR_HI; + card->hw_iface.bus_read_4(card->hw,dma_descr,®); + + /* If GO bit is set, then the current DMA chain + * is in process of being transmitted, thus + * all are busy */ + if (wan_test_bit(TxDMA_HI_DMA_GO_READY_BIT,®)){ + break; + } + + DEBUG_TEST("%s: TX DMA Handler Chain %i\n",chan->if_name,dma_chain->index); + + if (dma_chain->skb){ +//NENAD +#if 1 + wan_skb_set_csum(dma_chain->skb, reg); + wan_skb_queue_tail(&chan->wp_tx_complete_list,dma_chain->skb); + dma_chain->skb=NULL; +#else + chan->if_stats.tx_packets++; + chan->if_stats.tx_bytes+=wan_skb_len(dma_chain->skb); +#endif + } + + aft_tx_dma_chain_init(chan,dma_chain); + + if (++chan->tx_pending_chain_indx >= MAX_AFT_DMA_CHAINS){ + chan->tx_pending_chain_indx=0; + } + + dma_chain = &chan->tx_dma_chain_table[chan->tx_pending_chain_indx]; + dma_free=1; + } + + wan_clear_bit(TX_HANDLER_BUSY,&chan->dma_status); + + if (wan_skb_queue_len(&chan->wp_tx_complete_list)){ + WAN_TASKLET_SCHEDULE((&chan->common.bh_task)); + } + + return; +} + +/*=============================================== + * aft_dma_chain_tx + * + */ +static int aft_dma_chain_tx(aft_dma_chain_t *dma_chain,private_area_t *chan, int intr) +{ + +#define dma_descr dma_chain->dma_descr +#define reg dma_chain->reg +#define len dma_chain->dma_len +#define dma_ch_indx dma_chain->index +#define len_align dma_chain->len_align +#define card chan->card + + dma_descr=(dma_ch_indx<<4) + XILINX_TxDMA_DESCRIPTOR_HI; + + DEBUG_TEST("%s:%d: chan logic ch=%i chain=%li dma_descr=0x%x set!\n", + __FUNCTION__,__LINE__,chan->logic_ch_num,dma_ch_indx,dma_descr); + + card->hw_iface.bus_read_4(card->hw,dma_descr,®); + + if (wan_test_bit(TxDMA_HI_DMA_GO_READY_BIT,®)){ + DEBUG_EVENT("%s: Error: TxDMA GO Ready bit set on dma (chain=%i) Tx 0x%X\n", + card->devname,dma_ch_indx,reg); + return -EBUSY; + } + + dma_descr=(dma_ch_indx<<4) + XILINX_TxDMA_DESCRIPTOR_LO; + + /* Write the pointer of the data packet to the + * DMA address register */ + reg=dma_chain->dma_addr; + + /* Set the 32bit alignment of the data length. + * Used to pad the tx packet to the 32 bit + * boundary */ + reg&=~(TxDMA_LO_ALIGNMENT_BIT_MASK); + reg|=(len&0x03); + + len_align=0; + if (len&0x03){ + len_align=1; + } + + DEBUG_TEST("%s: TXDMA_LO=0x%X PhyAddr=0x%X DmaDescr=0x%X\n", + __FUNCTION__,reg,dma_chain->dma_addr,dma_descr); + + card->hw_iface.bus_write_4(card->hw,dma_descr,reg); + + dma_descr=(dma_ch_indx<<4) + XILINX_TxDMA_DESCRIPTOR_HI; + + reg=0; + + reg|=(((len>>2)+len_align)&TxDMA_HI_DMA_DATA_LENGTH_MASK); + + reg|=(chan->fifo_size_code&DMA_FIFO_SIZE_MASK)<fifo_base_addr&DMA_FIFO_BASE_ADDR_MASK)<< + DMA_FIFO_BASE_ADDR_SHIFT; + + wan_set_bit(DMA_HI_TE3_NOT_LAST_FRAME_BIT,®); + + if (intr){ + DEBUG_TEST("%s: Setting Interrupt on index=%i\n", + chan->if_name,dma_ch_indx); + wan_clear_bit(DMA_HI_TE3_INTR_DISABLE_BIT,®); + }else{ + wan_set_bit(DMA_HI_TE3_INTR_DISABLE_BIT,®); + } + + if (chan->hdlc_eng){ + /* Only enable the Frame Start/Stop on + * non-transparent hdlc configuration */ + + wan_set_bit(TxDMA_HI_DMA_FRAME_START_BIT,®); + wan_set_bit(TxDMA_HI_DMA_FRAME_END_BIT,®); + } + + wan_set_bit(TxDMA_HI_DMA_GO_READY_BIT,®); + + DEBUG_TEST("%s: TXDMA_HI=0x%X DmaDescr=0x%lX len=%i\n", + __FUNCTION__,reg,dma_descr,len); + + card->hw_iface.bus_write_4(card->hw,dma_descr,reg); + +#if 0 + ++chan->if_stats.tx_fifo_errors; +#endif + + return 0; + +#undef dma_descr +#undef reg +#undef len +#undef dma_ch_indx +#undef len_align +#undef card +} + +/*=============================================== + * aft_dma_chain_init + * + */ +static void aft_tx_dma_chain_init(private_area_t *chan, aft_dma_chain_t *dma_chain) +{ + + if (dma_chain->dma_addr){ + chan->card->hw_iface.pci_unmap_dma(chan->card->hw, + dma_chain->dma_addr, + dma_chain->dma_len, + PCI_DMA_TODEVICE); + } + + + if (dma_chain->skb){ + wan_skb_free(dma_chain->skb); + dma_chain->skb=NULL; + } + + dma_chain->dma_addr=0; + dma_chain->dma_len=0; + + wan_clear_bit(0,&dma_chain->init); +} + +static void aft_rx_dma_chain_init(private_area_t *chan, aft_dma_chain_t *dma_chain) +{ + + if (dma_chain->dma_addr){ + chan->card->hw_iface.pci_unmap_dma(chan->card->hw, + dma_chain->dma_addr, + dma_chain->dma_len, + PCI_DMA_FROMDEVICE); + } + + + if (dma_chain->skb){ + aft_init_requeue_free_skb(chan,dma_chain->skb); + dma_chain->skb=NULL; + } + + dma_chain->dma_addr=0; + dma_chain->dma_len=0; + + wan_clear_bit(0,&dma_chain->init); +} + +static int aft_realign_skb_pkt(private_area_t *chan, netskb_t *skb) +{ + unsigned char *data=wan_skb_data(skb); + int len = wan_skb_len(skb); + + if (len > chan->dma_mtu){ + DEBUG_EVENT("%s: Critical error: Tx unalign pkt(%d) > MTU buf(%d)!\n", + chan->if_name,len,chan->dma_mtu); + return -ENOMEM; + } + + if (!chan->tx_realign_buf){ + chan->tx_realign_buf=wan_malloc(chan->dma_mtu); + if (!chan->tx_realign_buf){ + DEBUG_EVENT("%s: Error: Failed to allocate tx memory buf\n", + chan->if_name); + return -ENOMEM; + }else{ + DEBUG_EVENT("%s: AFT Realign buffer allocated Len=%d\n", + chan->if_name,chan->dma_mtu); + + } + } + + memcpy(chan->tx_realign_buf,data,len); + + wan_skb_init(skb,0); + wan_skb_trim(skb,0); + + if (wan_skb_tailroom(skb) < len){ + DEBUG_EVENT("%s: Critical error: Tx unalign pkt tail room(%i) < unalign len(%i)!\n", + chan->if_name,wan_skb_tailroom(skb),len); + + return -ENOMEM; + } + + data=wan_skb_put(skb,len); + + if ((unsigned long)data & 0x03){ + /* At this point pkt should be realigned. If not + * there is something really wrong! */ + return -EINVAL; + } + + memcpy(data,chan->tx_realign_buf,len); + + return 0; +} + + + +/*=============================================== + * xilinx_dma_te3_tx + * + */ +static int xilinx_dma_te3_tx (sdla_t *card,private_area_t *chan, struct sk_buff *skb) +{ + int err=0, intr=0; + aft_dma_chain_t *dma_chain; + + if (wan_test_and_set_bit(TX_DMA_BUSY,&chan->dma_status)){ + DEBUG_EVENT("%s: SMP Critical in %s\n", + chan->if_name,__FUNCTION__); + + return -EBUSY; + } + + if (chan->tx_chain_indx >= MAX_AFT_DMA_CHAINS){ + DEBUG_EVENT("%s: MAJOR ERROR: TE3 Tx: Dma tx chain = %i\n", + chan->if_name,chan->tx_chain_indx); + aft_enable_tx_watchdog(card,AFT_TX_TIMEOUT); + return -EBUSY; + } + + dma_chain = &chan->tx_dma_chain_table[chan->tx_chain_indx]; + + aft_reset_tx_watchdog(card); + + /* If the current DMA chain is in use,then + * all chains are busy */ + if (wan_test_and_set_bit(0,&dma_chain->init)){ + wan_clear_bit(TX_DMA_BUSY,&chan->dma_status); + return -EBUSY; + } + + if ((unsigned long)wan_skb_data(skb) & 0x03){ + err=aft_realign_skb_pkt(chan,skb); + if (err){ + if (WAN_NET_RATELIMIT()){ + DEBUG_EVENT("%s: Tx Error: Non Aligned packet %p: dropping...\n", + chan->if_name,wan_skb_data(skb)); + } + wan_skb_free(skb); + wan_clear_bit(0,&dma_chain->init); + chan->if_stats.tx_errors++; + return -EINVAL; + } + } + + dma_chain->skb=skb; + + dma_chain->dma_addr = + card->hw_iface.pci_map_dma(card->hw, + wan_skb_data(dma_chain->skb), + wan_skb_len(dma_chain->skb), + PCI_DMA_TODEVICE); + + dma_chain->dma_len = wan_skb_len(dma_chain->skb); + + + DEBUG_TEST("%s: DMA Chain %i: Cur=%i Pend=%i\n", + chan->if_name,dma_chain->index, + chan->tx_chain_indx,chan->tx_pending_chain_indx); + + //FIXME: BIT FAT WARNING: THE index Values + //are not SMP protected figure it out !!!!! + + intr=0; + if (!wan_test_bit(TX_INTR_PENDING,&chan->dma_chain_status)){ + int pending_indx=chan->tx_pending_chain_indx; + if (chan->tx_chain_indx >= pending_indx){ + intr = ((MAX_AFT_DMA_CHAINS-(chan->tx_chain_indx - + pending_indx))<=2); + }else{ + intr = ((pending_indx - chan->tx_chain_indx)<=2); + } + + if (intr){ + DEBUG_TEST("%s: Setting tx interrupt on chain=%i\n", + chan->if_name,dma_chain->index); + wan_set_bit(TX_INTR_PENDING,&chan->dma_chain_status); + } + } + + err=aft_dma_chain_tx(dma_chain,chan,intr); + if (err){ + DEBUG_EVENT("%s: Tx dma chain %i overrun error: should never happen!\n", + chan->if_name,dma_chain->index); + aft_tx_dma_chain_init(chan,dma_chain); + chan->if_stats.tx_errors++; + + wan_clear_bit(TX_DMA_BUSY,&chan->dma_status); + return -EINVAL; + } + + + /* We are sure that the packet will + * be bound and transmitted, thus unhook + * it from the protocol stack */ + wan_skb_unlink(skb); + + if (++chan->tx_chain_indx >= MAX_AFT_DMA_CHAINS){ + chan->tx_chain_indx=0; + } + + if (!wan_test_bit(TX_INTR_PENDING,&chan->dma_chain_status)){ + aft_enable_tx_watchdog(card,AFT_TX_TIMEOUT); + } + + wan_clear_bit(TX_DMA_BUSY,&chan->dma_status); + + return 0; +} + + + +static void aft_pending_tx(sdla_t *card, private_area_t *chan) +{ + struct sk_buff *skb; + int err; + + while ((skb=wan_skb_dequeue(&chan->wp_tx_pending_list))!=NULL){ + err=xilinx_dma_te3_tx(card,chan,skb); + if (err==-EBUSY){ + wan_skb_queue_head(&chan->wp_tx_pending_list,skb); + break; + } + } +} + + +/**SECTION************************************************************* + * + * TE3 Exar Rx Functions + * DMA Chains + * + **********************************************************************/ + +static int aft_dma_chain_rx(aft_dma_chain_t *dma_chain, private_area_t *chan, int intr) +{ +#define dma_descr dma_chain->dma_descr +#define reg dma_chain->reg +#define len dma_chain->dma_len +#define dma_ch_indx dma_chain->index +#define len_align dma_chain->len_align +#define card chan->card + + /* Write the pointer of the data packet to the + * DMA address register */ + reg=dma_chain->dma_addr; + + /* Set the 32bit alignment of the data length. + * Since we are setting up for rx, set this value + * to Zero */ + reg&=~(RxDMA_LO_ALIGNMENT_BIT_MASK); + + dma_descr=(dma_ch_indx<<4) + XILINX_RxDMA_DESCRIPTOR_LO; + +// DEBUG_RX("%s: RxDMA_LO = 0x%X, BusAddr=0x%X DmaDescr=0x%X\n", +// __FUNCTION__,reg,bus_addr,dma_descr); + + card->hw_iface.bus_write_4(card->hw,dma_descr,reg); + + dma_descr=(unsigned long)(dma_ch_indx<<4) + XILINX_RxDMA_DESCRIPTOR_HI; + + reg =0; + + wan_set_bit(DMA_HI_TE3_NOT_LAST_FRAME_BIT,®); + + if (intr){ + DEBUG_TEST("%s: Setting Rx Interrupt on index=%i\n", + chan->if_name,dma_ch_indx); + wan_clear_bit(DMA_HI_TE3_INTR_DISABLE_BIT,®); + }else{ + wan_set_bit(DMA_HI_TE3_INTR_DISABLE_BIT,®); + } + + if (chan->hdlc_eng){ + //reg|=(chan->dma_mtu>>2)&RxDMA_HI_DMA_DATA_LENGTH_MASK; +//NENAD FIXME: USE ABOVE + reg|=((chan->dma_mtu>>2)-1)&RxDMA_HI_DMA_DATA_LENGTH_MASK; + }else{ + reg|=(card->wandev.mtu>>2)&RxDMA_HI_DMA_DATA_LENGTH_MASK; + } + + reg|=(chan->fifo_size_code&DMA_FIFO_SIZE_MASK)<fifo_base_addr&DMA_FIFO_BASE_ADDR_MASK)<< + DMA_FIFO_BASE_ADDR_SHIFT; + + wan_set_bit(RxDMA_HI_DMA_GO_READY_BIT,®); + +#if 0 + DEBUG_RX("%s: RXDMA_HI = 0x%X, BusAddr=0x%X DmaDescr=0x%X\n", + __FUNCTION__,reg,bus_addr,dma_descr); +#endif + card->hw_iface.bus_write_4(card->hw,dma_descr,reg); + + return 0; + +#undef dma_descr +#undef reg +#undef len +#undef dma_ch_indx +#undef len_align +#undef card +} + +static int xilinx_dma_rx(sdla_t *card, private_area_t *chan, int gcur_ptr) +{ + int err=0, intr=0; + aft_dma_chain_t *dma_chain; + int cur_dma_ptr, i,max_dma_cnt,free_queue_len; + u32 reg; + + if (wan_test_and_set_bit(RX_DMA_BUSY,&chan->dma_status)){ + DEBUG_EVENT("%s: SMP Critical in %s\n", + chan->if_name,__FUNCTION__); + return -EBUSY; + } + + aft_reset_rx_watchdog(card); + + free_queue_len=wan_skb_queue_len(&chan->wp_rx_free_list); + if (free_queue_len == 0){ + aft_free_rx_complete_list(chan); + free_queue_len=wan_skb_queue_len(&chan->wp_rx_free_list); + if (free_queue_len == 0){ + DEBUG_EVENT("%s: %s() CRITICAL ERROR: No free rx buffers\n", + card->devname,__FUNCTION__); + goto te3_rx_skip; + } + } + + if (gcur_ptr >= 0){ + cur_dma_ptr=gcur_ptr; + }else{ + card->hw_iface.bus_read_4(card->hw,AFT_TE3_CRNT_DMA_DESC_ADDR_REG,®); + cur_dma_ptr=get_current_rx_dma_ptr(reg); + } + + if (chan->rx_chain_indx >= cur_dma_ptr){ + max_dma_cnt = MAX_AFT_DMA_CHAINS - (chan->rx_chain_indx-cur_dma_ptr); + }else{ + max_dma_cnt = cur_dma_ptr - chan->rx_chain_indx; + } + + if (free_queue_len < max_dma_cnt){ +#if 0 + if (WAN_NET_RATELIMIT()){ + DEBUG_EVENT("%s: Free List(%d) lower than max dma %d\n", + card->devname, + free_queue_len, + max_dma_cnt); + } +#endif + max_dma_cnt = free_queue_len; + } + + + DEBUG_TEST("%s: DMA RX: CBoardPtr=%i Driver=%i MaxDMA=%i\n", + card->devname,cur_dma_ptr,chan->rx_chain_indx,max_dma_cnt); + + for (i=0;irx_dma_chain_table[chan->rx_chain_indx]; + + /* If the current DMA chain is in use,then + * all chains are busy */ + if (wan_test_and_set_bit(0,&dma_chain->init)){ + DEBUG_TEST("%s: Warning: %s():%d dma chain busy %i!\n", + card->devname, __FUNCTION__, __LINE__, + dma_chain->index); + + err=-EBUSY; + break; + } + + dma_chain->skb=wan_skb_dequeue(&chan->wp_rx_free_list); + if (!dma_chain->skb){ + DEBUG_EVENT("%s: Warning Rx chain = %i: no free rx bufs\n", + chan->if_name,dma_chain->index); + wan_clear_bit(0,&dma_chain->init); + err=-EINVAL; + break; + } + + dma_chain->dma_addr = + card->hw_iface.pci_map_dma(card->hw, + wan_skb_tail(dma_chain->skb), + chan->dma_mtu, + PCI_DMA_FROMDEVICE); + + dma_chain->dma_len = chan->dma_mtu; + + intr=0; + if (!wan_test_bit(RX_INTR_PENDING,&chan->dma_chain_status)){ + + free_queue_len--; + + if (free_queue_len <= 2){ + DEBUG_TEST("%s: DBG: Setting intr queue size low\n", + card->devname); + intr=1; + }else{ + if (chan->rx_chain_indx >= cur_dma_ptr){ + intr = ((MAX_AFT_DMA_CHAINS - + (chan->rx_chain_indx-cur_dma_ptr)) <=4); + }else{ + intr = ((cur_dma_ptr - chan->rx_chain_indx)<=4); + } + } + + if (intr){ + DEBUG_TEST("%s: Setting Rx interrupt on chain=%i\n", + chan->if_name,dma_chain->index); + wan_set_bit(RX_INTR_PENDING,&chan->dma_chain_status); + } + } + + DEBUG_TEST("%s: Setting Buffer on Rx Chain = %i Intr=%i\n", + chan->if_name,dma_chain->index, intr); + + err=aft_dma_chain_rx(dma_chain,chan,intr); + if (err){ + DEBUG_EVENT("%s: Rx dma chain %i overrun error: should never happen!\n", + chan->if_name,dma_chain->index); + aft_rx_dma_chain_init(chan,dma_chain); + chan->if_stats.rx_dropped++; + break; + } + + if (++chan->rx_chain_indx >= MAX_AFT_DMA_CHAINS){ + chan->rx_chain_indx=0; + } + } + +te3_rx_skip: + + aft_enable_rx_watchdog(card,AFT_RX_TIMEOUT); + + wan_clear_bit(RX_DMA_BUSY,&chan->dma_status); + + return err; +} + +/*=============================================== + * aft_rx_dma_chain_handler + * + */ +//N1 +static void aft_rx_dma_chain_handler(private_area_t *chan, int wtd, int reset) +{ + sdla_t *card = chan->card; + u32 reg,dma_descr; + wp_rx_element_t *rx_el; + aft_dma_chain_t *dma_chain; + int i,max_dma_cnt, cur_dma_ptr; + + if (wan_test_and_set_bit(RX_HANDLER_BUSY,&chan->dma_status)){ + DEBUG_EVENT("%s: SMP Critical in %s\n", + chan->if_name,__FUNCTION__); + return; + } + + if (!wtd){ + /* Not watchdog, thus called from an interrupt. + * Clear the RX INTR Pending flag */ + wan_clear_bit(RX_INTR_PENDING,&chan->dma_chain_status); + } + + card->hw_iface.bus_read_4(card->hw,AFT_TE3_CRNT_DMA_DESC_ADDR_REG,®); + cur_dma_ptr=get_current_rx_dma_ptr(reg); + + if (cur_dma_ptr == chan->rx_pending_chain_indx){ + max_dma_cnt = MAX_AFT_DMA_CHAINS; + }else if (cur_dma_ptr > chan->rx_pending_chain_indx){ + max_dma_cnt = cur_dma_ptr-chan->rx_pending_chain_indx; + }else{ + max_dma_cnt = MAX_AFT_DMA_CHAINS - (chan->rx_pending_chain_indx-cur_dma_ptr); + } + + DEBUG_TEST("%s: DMA RX %s: CBoardPtr=%i Driver=%i MaxDMA=%i\n", + card->devname, + wtd?"WTD":"Intr", + cur_dma_ptr, + chan->rx_chain_indx,max_dma_cnt); + + for (i=0;irx_dma_chain_table[chan->rx_pending_chain_indx]; + if (!dma_chain){ + DEBUG_EVENT("%s:%d Assertion Error !!!!\n", + __FUNCTION__,__LINE__); + break; + } + + /* If the current DMA chain is in use,then + * all chains are busy */ + if (!wan_test_bit(0,&dma_chain->init)){ + DEBUG_TEST("%s: Warning (%s) Pending chain %i empty!\n", + chan->if_name,__FUNCTION__,dma_chain->index); + + break; + } + + dma_descr=(dma_chain->index<<4) + XILINX_RxDMA_DESCRIPTOR_HI; + card->hw_iface.bus_read_4(card->hw,dma_descr,®); + + /* If GO bit is set, then the current DMA chain + * is in process of being transmitted, thus + * all are busy */ + if (wan_test_bit(RxDMA_HI_DMA_GO_READY_BIT,®)){ + DEBUG_TEST("%s: Warning (%s) Pending chain %i Go bit still set!\n", + chan->if_name,__FUNCTION__,dma_chain->index); + break; + } + + card->hw_iface.pci_unmap_dma(card->hw, + dma_chain->dma_addr, + chan->dma_mtu, + PCI_DMA_FROMDEVICE); + + rx_el=(wp_rx_element_t *)wan_skb_push(dma_chain->skb, sizeof(wp_rx_element_t)); + memset(rx_el,0,sizeof(wp_rx_element_t)); + +#if 0 + chan->if_stats.rx_frame_errors++; +#endif + + /* Reading Rx DMA descriptor information */ + dma_descr=(dma_chain->index<<4) + XILINX_RxDMA_DESCRIPTOR_LO; + card->hw_iface.bus_read_4(card->hw,dma_descr, &rx_el->align); + rx_el->align&=RxDMA_LO_ALIGNMENT_BIT_MASK; + + dma_descr=(dma_chain->index<<4) + XILINX_RxDMA_DESCRIPTOR_HI; + card->hw_iface.bus_read_4(card->hw,dma_descr, &rx_el->reg); + + rx_el->pkt_error= dma_chain->pkt_error; + rx_el->dma_addr = dma_chain->dma_addr; + + wan_skb_queue_tail(&chan->wp_rx_complete_list,dma_chain->skb); + + DEBUG_RX("%s: RxInr Pending chain %i Rxlist=%i LO:0x%X HI:0x%X Data=0x%X Len=%i!\n", + chan->if_name,dma_chain->index, + wan_skb_queue_len(&chan->wp_rx_complete_list), + rx_el->align,rx_el->reg, + (*(unsigned char*)wan_skb_data(dma_chain->skb)), + wan_skb_len(dma_chain->skb)); + + dma_chain->skb=NULL; + dma_chain->dma_addr=0; + dma_chain->dma_len=0; + dma_chain->pkt_error=0; + wan_clear_bit(0,&dma_chain->init); + + if (++chan->rx_pending_chain_indx >= MAX_AFT_DMA_CHAINS){ + chan->rx_pending_chain_indx=0; + } + + } + + if (reset){ + goto reset_skip_rx_setup; + } + + xilinx_dma_rx(card,chan,cur_dma_ptr); + + if (wan_skb_queue_len(&chan->wp_rx_complete_list)){ + DEBUG_TEST("%s: Rx Queued list triggering\n",chan->if_name); + WAN_TASKLET_SCHEDULE((&chan->common.bh_task)); + chan->rx_no_data_cnt=0; + }else{ + if ((chan->rx_no_data_cnt >= 0) && (++chan->rx_no_data_cnt < 3)){ + aft_enable_rx_watchdog(card,AFT_RX_TIMEOUT); + }else{ + /* Enable Rx Interrupt on pending rx descriptor */ + DEBUG_TEST("%s: Setting Max Rx Watchdog Timeout\n", + chan->if_name); + aft_enable_rx_watchdog(card,AFT_MAX_WTD_TIMEOUT); + chan->rx_no_data_cnt=-1; + } + } + +reset_skip_rx_setup: + + wan_clear_bit(RX_HANDLER_BUSY,&chan->dma_status); + + + return; +} + +static void aft_index_tx_rx_dma_chains(private_area_t *chan) +{ + int i; + + for (i=0;itx_dma_chain_table[i].index=i; + chan->rx_dma_chain_table[i].index=i; + } +} + + +static void aft_init_tx_rx_dma_descr(private_area_t *chan) +{ + int i; + u32 reg=0; + sdla_t *card=chan->card; + unsigned long tx_dma_descr,rx_dma_descr; + + for (i=0;ihw_iface.bus_write_4(card->hw,tx_dma_descr,reg); + card->hw_iface.bus_write_4(card->hw,rx_dma_descr,reg); + + aft_tx_dma_chain_init(chan,&chan->tx_dma_chain_table[i]); + aft_tx_dma_chain_init(chan,&chan->rx_dma_chain_table[i]); + } +} + +#if 0 +static void aft_dma_te3_set_intr(aft_dma_chain_t *dma_chain, private_area_t *chan) +{ +#define dma_ch_indx dma_chain->index +#define card chan->card + + u32 reg=0; + u32 len; + u32 dma_descr; + + /* If the current DMA chain is in use,then + * all chains are busy */ + if (!wan_test_bit(0,&dma_chain->init)){ + DEBUG_EVENT("%s: (%s) Error: Pending chain %i empty!\n", + chan->if_name,__FUNCTION__,dma_chain->index); + return; + } + + dma_descr=(unsigned long)(dma_ch_indx<<4) + XILINX_RxDMA_DESCRIPTOR_HI; + + card->hw_iface.bus_read_4(card->hw,dma_descr,®); + + /* If GO bit is set, then the current DMA chain + * is in process of being Received, thus + * all are busy */ + if (!wan_test_bit(RxDMA_HI_DMA_GO_READY_BIT,®)){ + DEBUG_EVENT("%s: (%s) Error: Pending chain %i Go bit is not set!\n", + chan->if_name,__FUNCTION__,dma_chain->index); + return; + } + + len=reg&RxDMA_HI_DMA_DATA_LENGTH_MASK; + + DEBUG_TEST("%s: Set Rx Intr on 1st Pending Chain: index=%i Len=%i (dmalen=%i)\n", + chan->if_name,dma_ch_indx,len,dma_chain->dma_len); + + wan_clear_bit(DMA_HI_TE3_INTR_DISABLE_BIT,®); + + card->hw_iface.bus_write_4(card->hw,dma_descr,reg); + +#undef dma_ch_indx +#undef card +} +#endif + +/* + * ****************************************************************** + * Proc FS function + */ +static int wan_aft3_get_info(void* pcard, struct seq_file *m, int *stop_cnt) +{ + sdla_t *card = (sdla_t*)pcard; + + m->count = + WAN_FECALL(&card->wandev, update_alarm_info, (&card->fe, m, stop_cnt)); + m->count = + WAN_FECALL(&card->wandev, update_pmon_info, (&card->fe, m, stop_cnt)); + + return m->count; +} + + +static void aft_free_rx_complete_list(private_area_t *chan) +{ + void *skb; + while((skb=wan_skb_dequeue(&chan->wp_rx_complete_list)) != NULL){ + + chan->if_stats.rx_dropped++; + aft_init_requeue_free_skb(chan, skb); + } +} + +static void aft_list_descriptors(private_area_t *chan) +{ +#if 0 + u32 reg,cur_dma_ptr; + sdla_t *card=chan->card; + aft_dma_chain_t *dma_chain; + u32 dma_descr; + int i; + + card->hw_iface.bus_read_4(card->hw,AFT_TE3_CRNT_DMA_DESC_ADDR_REG,®); + cur_dma_ptr=get_current_rx_dma_ptr(reg); + + DEBUG_EVENT("%s: List Descritpors:\n",chan->if_name); + + DEBUG_EVENT("%s: Chain DMA Status=0x%lX, TxCur=%i, TxPend=%i RxCur=%i RxPend=%i HwCur=%i RC=%i RFree=%i\n", + chan->if_name, + chan->dma_chain_status, + chan->tx_chain_indx, + chan->tx_pending_chain_indx, + chan->rx_chain_indx, + chan->rx_pending_chain_indx, + cur_dma_ptr, + wan_skb_queue_len(&chan->wp_rx_complete_list), + wan_skb_queue_len(&chan->wp_rx_free_list)); + + + for (i=0;irx_dma_chain_table[i]; + if (!dma_chain){ + DEBUG_EVENT("%s:%d Assertion Error !!!!\n", + __FUNCTION__,__LINE__); + break; + } + + dma_descr=(dma_chain->index<<4) + XILINX_RxDMA_DESCRIPTOR_HI; + card->hw_iface.bus_read_4(card->hw,dma_descr,®); + + DEBUG_EVENT("%s: DMA=%i : Init=%li Go=%u Intr=%u Addr=%s Skb=%s\n", + chan->if_name, + dma_chain->index, + dma_chain->init, + wan_test_bit(RxDMA_HI_DMA_GO_READY_BIT,®), + wan_test_bit(DMA_HI_TE3_INTR_DISABLE_BIT,®), + dma_chain->dma_addr?"Yes":"No", + dma_chain->skb?"Yes":"No"); + } +#endif +} + +static void aft_list_tx_descriptors(private_area_t *chan) +{ +#if 1 + u32 reg,cur_dma_ptr,low,dma_ctrl; + sdla_t *card=chan->card; + aft_dma_chain_t *dma_chain; + u32 dma_descr; + int i; + + card->hw_iface.bus_read_4(card->hw,AFT_TE3_CRNT_DMA_DESC_ADDR_REG,®); + cur_dma_ptr=get_current_tx_dma_ptr(reg); + + card->hw_iface.bus_read_4(card->hw,XILINX_DMA_CONTROL_REG,&dma_ctrl); + + DEBUG_EVENT("%s: List TX Descritpors:\n",chan->if_name); + + DEBUG_EVENT("%s: Chain DMA Status=0x%lX, TxCur=%i, TxPend=%i HwCur=%i RP=%i RC=%i RFree=%i Ctrl=0x%X\n", + chan->if_name, + chan->dma_chain_status, + chan->tx_chain_indx, + chan->tx_pending_chain_indx, + cur_dma_ptr, + wan_skb_queue_len(&chan->wp_tx_pending_list), + wan_skb_queue_len(&chan->wp_tx_complete_list), + wan_skb_queue_len(&chan->wp_tx_free_list), + dma_ctrl); + + + for (i=0;itx_dma_chain_table[i]; + if (!dma_chain){ + DEBUG_EVENT("%s:%d Assertion Error !!!!\n", + __FUNCTION__,__LINE__); + break; + } + + dma_descr=(dma_chain->index<<4) + XILINX_TxDMA_DESCRIPTOR_HI; + card->hw_iface.bus_read_4(card->hw,dma_descr,®); + + dma_descr=(dma_chain->index<<4) + XILINX_TxDMA_DESCRIPTOR_LO; + card->hw_iface.bus_read_4(card->hw,dma_descr,&low); + + DEBUG_EVENT("%s: DMA=%i : Init=%lu Go=%u Intr=%u Addr=%s Skb=%s HI=0x%X LO=0x%X\n", + chan->if_name, + dma_chain->index, + dma_chain->init, + wan_test_bit(TxDMA_HI_DMA_GO_READY_BIT,®), + wan_test_bit(DMA_HI_TE3_INTR_DISABLE_BIT,®), + dma_chain->dma_addr?"Yes":"No", + dma_chain->skb?"Yes":"No", + reg,low); + } +#endif +} + + +static void aft_free_rx_descriptors(private_area_t *chan) +{ + u32 reg; + sdla_t *card=chan->card; + aft_dma_chain_t *dma_chain; + u32 dma_descr; + int i; + + for (i=0;irx_dma_chain_table[i]; + if (!dma_chain){ + DEBUG_EVENT("%s:%d Assertion Error !!!!\n", + __FUNCTION__,__LINE__); + break; + } + + /* If the current DMA chain is in use,then + * all chains are busy */ + if (!wan_test_bit(0,&dma_chain->init)){ + continue; + } + + dma_descr=(dma_chain->index<<4) + XILINX_RxDMA_DESCRIPTOR_HI; + card->hw_iface.bus_read_4(card->hw,dma_descr,®); + + /* If GO bit is set, then the current DMA chain + * is in process of being transmitted, thus + * all are busy */ + reg=0; + card->hw_iface.bus_write_4(card->hw,dma_descr,reg); + + card->hw_iface.pci_unmap_dma(card->hw, + dma_chain->dma_addr, + chan->dma_mtu, + PCI_DMA_FROMDEVICE); + + aft_init_requeue_free_skb(chan, dma_chain->skb); + + dma_chain->skb=NULL; + dma_chain->dma_addr=0; + dma_chain->dma_len=0; + dma_chain->pkt_error=0; + wan_clear_bit(0,&dma_chain->init); + } + + chan->rx_pending_chain_indx = chan->rx_chain_indx; + +} + +static void aft_reset_tx_chain_cnt(private_area_t *chan) +{ + u32 reg,cur_dma_ptr; + sdla_t *card=chan->card; + card->hw_iface.bus_read_4(card->hw,AFT_TE3_CRNT_DMA_DESC_ADDR_REG,®); + cur_dma_ptr=get_current_tx_dma_ptr(reg); + chan->tx_pending_chain_indx = chan->tx_chain_indx = cur_dma_ptr; + return; +} + +static void aft_free_tx_descriptors(private_area_t *chan) +{ + u32 reg; + sdla_t *card=chan->card; + aft_dma_chain_t *dma_chain; + u32 dma_descr; + int i; + void *skb; + + DEBUG_TEST("%s:%s: Tx: Freeing Descripors\n",card->devname,chan->if_name); + + wan_clear_bit(TX_INTR_PENDING,&chan->dma_chain_status); + wan_clear_bit(TX_DMA_BUSY,&chan->dma_status); + + for (i=0;itx_dma_chain_table[i]; + if (!dma_chain){ + DEBUG_EVENT("%s:%d Assertion Error !!!!\n", + __FUNCTION__,__LINE__); + break; + } + + dma_descr=(dma_chain->index<<4) + XILINX_TxDMA_DESCRIPTOR_HI; + reg=0; + card->hw_iface.bus_write_4(card->hw,dma_descr,reg); + + aft_tx_dma_chain_init(chan, dma_chain); + } + + chan->tx_chain_indx = chan->tx_pending_chain_indx; + + aft_reset_tx_chain_cnt(chan); + + while((skb=wan_skb_dequeue(&chan->wp_tx_complete_list)) != NULL){ + wan_skb_free(skb); + } +} + + + +static void aft_te3_led_ctrl(sdla_t *card, int color, int led_pos, int on) +{ + u32 reg; + card->hw_iface.bus_read_4(card->hw,TE3_LOCAL_CONTROL_STATUS_REG,®); + aft_te3_set_led(color, led_pos, on, ®); + card->hw_iface.bus_write_4(card->hw,TE3_LOCAL_CONTROL_STATUS_REG,reg); +} + + +static void __aft_fe_intr_ctrl(sdla_t *card, int status) +{ + u32 reg; + + card->hw_iface.bus_read_4(card->hw,XILINX_CHIP_CFG_REG,®); + if (status){ + wan_set_bit(FRONT_END_INTR_ENABLE_BIT,®); + }else{ + wan_clear_bit(FRONT_END_INTR_ENABLE_BIT,®); + } + card->hw_iface.bus_write_4(card->hw,XILINX_CHIP_CFG_REG,reg); +} + +static void aft_fe_intr_ctrl(sdla_t *card, int status) +{ + wan_smp_flag_t smp_flags; + + wan_spin_lock_irq(&card->wandev.lock,&smp_flags); + __aft_fe_intr_ctrl(card, status); + wan_spin_unlock_irq(&card->wandev.lock,&smp_flags); +} + + +#if defined(__LINUX__) +static void aft_port_task (void * card_ptr) +#else +static void aft_port_task (void * card_ptr, int arg) +#endif +{ + sdla_t *card = (sdla_t *)card_ptr; + wan_smp_flag_t smp_flags,isr_flags; + + if (wan_test_bit(CARD_DOWN,&card->wandev.critical)){ + return; + } + + DEBUG_TEST("%s: AFT PORT TASK CMD=0x%X!\n", + card->devname,card->u.aft.port_task_cmd); + + if (wan_test_bit(AFT_FE_INTR,&card->u.aft.port_task_cmd)){ + card->hw_iface.hw_lock(card->hw,&smp_flags); + + aft_fe_intr_ctrl(card, 0); + wan_spin_lock_irq(&card->wandev.lock,&isr_flags); + front_end_interrupt(card,0); + wan_spin_unlock_irq(&card->wandev.lock,&isr_flags); + aft_fe_intr_ctrl(card, 1); + + wan_clear_bit(AFT_FE_INTR,&card->u.aft.port_task_cmd); + card->hw_iface.hw_unlock(card->hw,&smp_flags); + } + + if (wan_test_bit(AFT_FE_POLL,&card->u.aft.port_task_cmd)){ + card->hw_iface.hw_lock(card->hw,&smp_flags); + + aft_fe_intr_ctrl(card, 0); + wan_spin_lock_irq(&card->wandev.lock,&isr_flags); + WAN_FECALL(&card->wandev, polling, (&card->fe)); + wan_spin_unlock_irq(&card->wandev.lock,&isr_flags); + aft_fe_intr_ctrl(card, 1); + + wan_clear_bit(AFT_FE_POLL,&card->u.aft.port_task_cmd); + card->hw_iface.hw_unlock(card->hw,&smp_flags); + } +} + +#if 0 +static int aft_hdlc_core_ready(sdla_t *card) +{ + u32 reg; + int i,err=1; + + for (i=0;i<5;i++){ + card->hw_iface.bus_read_4(card->hw,XILINX_CHIP_CFG_REG, ®); + + if (!wan_test_bit(HDLC_CORE_READY_FLAG_BIT,®)){ + udelay(500); + }else{ + err=0; + break; + } + } + + if (err){ + DEBUG_EVENT("%s: Critical Error: HDLC Core not ready!\n", + card->devname); + } + return err; +} +#endif +/****** End ****************************************************************/ diff -Nur linux.org/drivers/net/wan/sdla_asyhdlc.c linux-2.6.17/drivers/net/wan/sdla_asyhdlc.c --- linux.org/drivers/net/wan/sdla_asyhdlc.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/drivers/net/wan/sdla_asyhdlc.c 2006-08-30 10:07:16.000000000 +0000 @@ -0,0 +1,3243 @@ +/***************************************************************************** +* sdla_asyhdlc.c WANPIPE(tm) Multiprotocol WAN Link Driver. Cisco HDLC module. +* +* Authors: Nenad Corbic +* Gideon Hack +* +* Copyright: (c) 1995-2004 Sangoma Technologies Inc. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version +* 2 of the License, or (at your option) any later version. +* ============================================================================ +* Jan 03, 2002 Nenad Corbic Memory leak bug fix under Bridge Mode. +* If not an ethernet frame skb buffer was +* not deallocated. +* Oct 18, 2002 Nenad Corbic Added BRIDGE support +* Jan 14, 2002 Nenad Corbic Removed the 2.0.X kernel support and added +* front end state handling. +* Dec 12, 2001 Nenad Corbic Re-wrote the tty receive algorithm, using +* task queues, because ISA cards cannot call +* receive_buf() from the rx interrupt. +* Dec 03, 2001 Gideon Hack Updated for S514-5 56K adapter. +* Sep 20, 2001 Nenad Corbic The min() function has changed for 2.4.9 +* kernel. Thus using the wp_min() defined in +* wanpipe.h +* Sept 6, 2001 Alex Feldman Add SNMP support. +* Aug 23, 2001 Nenad Corbic Removed the if_header and set the hard_header +* length to zero. Caused problems with Checkpoint +* firewall. +* May 13, 2001 Alex Feldman Added T1/E1 support (TE1). +* Feb 28, 2001 Nenad Corbic Updated if_tx_timeout() routine for +* 2.4.X kernels. +* Jan 25, 2001 Nenad Corbic Added a TTY Sync serial driver over the +* HDLC streaming protocol +* Added a TTY Async serial driver over the +* Async protocol. +* Dec 15, 2000 Nenad Corbic Updated for 2.4.X Kernel support +* Nov 13, 2000 Nenad Corbic Added true interface type encoding option. +* Tcpdump doesn't support CHDLC inteface +* types, to fix this "true type" option will set +* the interface type to RAW IP mode. +* Nov 07, 2000 Nenad Corbic Added security features for UDP debugging: +* Deny all and specify allowed requests. +* Jun 20, 2000 Nenad Corbic Fixed the API IP ERROR bug. Caused by the +* latest update. +* May 09, 2000 Nenad Corbic Option to bring down an interface +* upon disconnect. +* Mar 23, 2000 Nenad Corbic Improved task queue, bh handling. +* Mar 16, 2000 Nenad Corbic Fixed the SLARP Dynamic IP addressing. +* Mar 06, 2000 Nenad Corbic Bug Fix: corrupted mbox recovery. +* Feb 10, 2000 Gideon Hack Added ASYNC support. +* Feb 09, 2000 Nenad Corbic Fixed two shutdown bugs in update() and +* if_stats() functions. +* Jan 24, 2000 Nenad Corbic Fixed a startup wanpipe state racing, +* condition between if_open and isr. +* Jan 10, 2000 Nenad Corbic Added new socket API support. +* Dev 15, 1999 Nenad Corbic Fixed up header files for 2.0.X kernels +* Nov 20, 1999 Nenad Corbic Fixed zero length API bug. +* Sep 30, 1999 Nenad Corbic Fixed dynamic IP and route setup. +* Sep 23, 1999 Nenad Corbic Added SMP support, fixed tracing +* Sep 13, 1999 Nenad Corbic Split up Port 0 and 1 into separate devices. +* Jun 02, 1999 Gideon Hack Added support for the S514 adapter. +* Oct 30, 1998 Jaspreet Singh Added Support for CHDLC API (HDLC STREAMING). +* Oct 28, 1998 Jaspreet Singh Added Support for Dual Port CHDLC. +* Aug 07, 1998 David Fong Initial version. +*****************************************************************************/ + +#include +#include +#include /* WANPIPE common user API definitions */ +#include +#include +#include /* CHDLC firmware API definitions */ +#include /* Socket Driver common area */ +#include + +/****** Defines & Macros ****************************************************/ + +/* Private critical flags */ +enum { + POLL_CRIT = PRIV_CRIT, + TX_INTR, + TASK_POLL, + TTY_HANGUP +}; + + +/* reasons for enabling the timer interrupt on the adapter */ +#define TMR_INT_ENABLED_UDP 0x01 +#define TMR_INT_ENABLED_UPDATE 0x02 +#define TMR_INT_ENABLED_CONFIG 0x10 +#define TMR_INT_ENABLED_TE 0x20 + +#define MAX_IP_ERRORS 10 + +#define TTY_CHDLC_MAX_MTU 2000 +#define CHDLC_DFLT_DATA_LEN 1500 /* default MTU */ +#define CHDLC_HDR_LEN 1 + +#define CHDLC_API 0x01 + +#define PORT(x) (x == 0 ? "PRIMARY" : "SECONDARY" ) +#define MAX_BH_BUFF 10 + + +/******Data Structures*****************************************************/ + +/* This structure is placed in the private data area of the device structure. + * The card structure used to occupy the private area but now the following + * structure will incorporate the card structure along with CHDLC specific data + */ + +typedef struct chdlc_private_area +{ + wanpipe_common_t common; + sdla_t *card; + int TracingEnabled; /* For enabling Tracing */ + unsigned long curr_trace_addr; /* Used for Tracing */ + unsigned long start_trace_addr; + unsigned long end_trace_addr; + unsigned long base_addr_trace_buffer; + unsigned long end_addr_trace_buffer; + unsigned short number_trace_elements; + unsigned available_buffer_space; + unsigned long router_start_time; + unsigned char route_status; + unsigned char route_removed; + unsigned long tick_counter; /* For 5s timeout counter */ + unsigned long router_up_time; + u32 IP_address; /* IP addressing */ + u32 IP_netmask; + u32 ip_local; + u32 ip_remote; + u32 ip_local_tmp; + u32 ip_remote_tmp; + u8 ip_error; + unsigned long config_chdlc; + u8 config_chdlc_timeout; + unsigned char mc; /* Mulitcast support on/off */ + unsigned char udp_pkt_src; /* udp packet processing */ + unsigned short timer_int_enabled; + unsigned long update_comms_stats; /* updating comms stats */ + + unsigned long interface_down; + + /* Polling task queue. Each interface + * has its own task queue, which is used + * to defer events from the interrupt */ + struct tq_struct poll_task; + struct timer_list poll_delay_timer; + + u8 gateway; + u8 true_if_encoding; + //FIXME: add driver stats as per frame relay! + + /* Entry in proc fs per each interface */ + struct proc_dir_entry* dent; + + unsigned char udp_pkt_data[sizeof(wan_udp_pkt_t)+10]; + atomic_t udp_pkt_len; + + char if_name[WAN_IFNAME_SZ+1]; + + netdevice_t *annexg_dev; + unsigned char label[WAN_IF_LABEL_SZ+1]; + +} chdlc_private_area_t; + +/* Route Status options */ +#define NO_ROUTE 0x00 +#define ADD_ROUTE 0x01 +#define ROUTE_ADDED 0x02 +#define REMOVE_ROUTE 0x03 + + +/* variable for tracking how many interfaces to open for WANPIPE on the + two ports */ + +extern void disable_irq(unsigned int); +extern void enable_irq(unsigned int); + + +/****** Function Prototypes *************************************************/ +/* WAN link driver entry points. These are called by the WAN router module. */ +static int update (wan_device_t* wandev); +static int new_if (wan_device_t* wandev, netdevice_t* dev, + wanif_conf_t* conf); +static int del_if(wan_device_t *wandev, netdevice_t *dev); + +/* Network device interface */ +static int if_init (netdevice_t* dev); +static int if_open (netdevice_t* dev); +static int if_close (netdevice_t* dev); +static int if_do_ioctl(netdevice_t *dev, struct ifreq *ifr, int cmd); + + +static struct net_device_stats* if_stats (netdevice_t* dev); + +static int if_send (struct sk_buff* skb, netdevice_t* dev); + +/* CHDLC Firmware interface functions */ +static int chdlc_comm_enable (sdla_t* card); +static int chdlc_comm_disable (sdla_t* card); +static int chdlc_read_version (sdla_t* card, char* str, int str_size); +static int chdlc_set_intr_mode (sdla_t* card, unsigned mode); +static int set_adapter_config (sdla_t* card); +static int chdlc_send (sdla_t* card, void* data, unsigned len, unsigned char tx_bits); +static int chdlc_read_comm_err_stats (sdla_t* card); +static int chdlc_error (sdla_t *card, int err, wan_mbox_t *mb); + + +static int chdlc_disable_comm_shutdown (sdla_t *card); +static void if_tx_timeout (netdevice_t *dev); + + +/* Miscellaneous CHDLC Functions */ +static void init_chdlc_tx_rx_buff( sdla_t* card); +static int process_global_exception(sdla_t *card); +static int update_comms_stats(sdla_t* card, + chdlc_private_area_t* chdlc_priv_area); +static void port_set_state (sdla_t *card, int); +static int config_chdlc (sdla_t *card, netdevice_t *dev); +static void disable_comm (sdla_t *card); + + +/* Miscellaneous asynchronous interface Functions */ +static int set_asy_config (sdla_t* card); +static int asy_comm_enable (sdla_t* card); + +/* Interrupt handlers */ +static void wpc_isr (sdla_t* card); +static void rx_intr (sdla_t* card); +static void timer_intr(sdla_t *); + +/* Bottom half handlers */ +static void chdlc_bh (unsigned long data); + +/* Miscellaneous functions */ +static int chk_bcast_mcast_addr(sdla_t* card, netdevice_t* dev, + struct sk_buff *skb); +static int reply_udp( unsigned char *data, unsigned int mbox_len ); +static int intr_test( sdla_t* card); +static int udp_pkt_type( struct sk_buff *skb , sdla_t* card); +static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, + struct sk_buff *skb, netdevice_t* dev, + chdlc_private_area_t* chdlc_priv_area); +static int process_udp_mgmt_pkt(sdla_t* card, netdevice_t* dev, + chdlc_private_area_t* chdlc_priv_area, + int local_dev); +static unsigned short calc_checksum (char *, int); +static void s508_lock (sdla_t *card, unsigned long *smp_flags); +static void s508_unlock (sdla_t *card, unsigned long *smp_flags); + +#define CRC_LENGTH 2 + + +static int chdlc_get_config_info(void* priv, struct seq_file* m, int*); +static int chdlc_get_status_info(void* priv, struct seq_file* m, int*); +static int chdlc_set_dev_config(struct file*, const char*, unsigned long, void *); +static int chdlc_set_if_info(struct file*, const char*, unsigned long, void *); + +/* TE1 */ +static WRITE_FRONT_END_REG_T write_front_end_reg; +static READ_FRONT_END_REG_T read_front_end_reg; +static void chdlc_enable_timer(void* card_id); +static void chdlc_handle_front_end_state(void* card_id); + +/****** Public Functions ****************************************************/ + +/*============================================================================ + * wp_asyhdlc_init - Cisco HDLC protocol initialization routine. + * + * @card: Wanpipe card pointer + * @conf: User hardware/firmware/general protocol configuration + * pointer. + * + * This routine is called by the main WANPIPE module + * during setup: ROUTER_SETUP ioctl(). + * + * At this point adapter is completely initialized + * and firmware is running. + * o read firmware version (to make sure it's alive) + * o configure adapter + * o initialize protocol-specific fields of the adapter data space. + * + * Return: 0 o.k. + * < 0 failure. + */ +int wp_asyhdlc_init (sdla_t* card, wandev_conf_t* conf) +{ + unsigned char port_num; + int err; + unsigned long max_permitted_baud = 0; + + char str[80]; + volatile wan_mbox_t* mb; + wan_mbox_t* mb1; + unsigned long timeout; + + /* Verify configuration ID */ + if (conf->config_id != WANCONFIG_ASYHDLC) { + printk(KERN_INFO "%s: invalid configuration ID %u!\n", + card->devname, conf->config_id); + return -EINVAL; + } + /* Find out which Port to use */ + if ((conf->comm_port == WANOPT_PRI) || (conf->comm_port == WANOPT_SEC)){ + if (card->next){ + + if (conf->comm_port != card->next->u.c.comm_port){ + card->u.c.comm_port = conf->comm_port; + }else{ + printk(KERN_INFO "%s: ERROR - %s port used!\n", + card->wandev.name, PORT(conf->comm_port)); + return -EINVAL; + } + }else{ + card->u.c.comm_port = conf->comm_port; + } + }else{ + printk(KERN_INFO "%s: ERROR - Invalid Port Selected!\n", + card->wandev.name); + return -EINVAL; + } + + + /* Initialize protocol-specific fields */ + /* ALEX: Apr 8 2004 SANGOMA ISA CARD */ + /* for a PCI/ISA adapters, set a pointer to the actual mailbox in the */ + /* allocated virtual memory area */ + if (card->u.c.comm_port == WANOPT_PRI){ + card->mbox_off = PRI_BASE_ADDR_MB_STRUCT; + }else{ + card->mbox_off = SEC_BASE_ADDR_MB_STRUCT; + } + + mb = &card->wan_mbox; + mb1 = &card->wan_mbox; + + if (!card->configured){ + unsigned char return_code = 0x00; + /* The board will place an 'I' in the return code to indicate that it is + ready to accept commands. We expect this to be completed in less + than 1 second. */ + + timeout = jiffies; + do { + return_code = 0x00; + card->hw_iface.peek(card->hw, + card->mbox_off+offsetof(wan_mbox_t, wan_return_code), + &return_code, + sizeof(unsigned char)); + if ((jiffies - timeout) > 1*HZ) break; + }while(return_code != 'I'); + if (return_code != 'I') { + printk(KERN_INFO + "%s: Initialization not completed by adapter\n", + card->devname); + printk(KERN_INFO "Please contact Sangoma representative.\n"); + return -EIO; + } + } + + card->wandev.clocking = conf->clocking; + card->wandev.ignore_front_end_status = conf->ignore_front_end_status; + + card->wandev.line_idle = conf->line_idle; + card->wandev.line_coding = conf->line_coding; + card->wandev.connection = conf->connection; + + err = (card->hw_iface.check_mismatch) ? + card->hw_iface.check_mismatch(card->hw,conf->fe_cfg.media) : -EINVAL; + if (err){ + return err; + } + + /* TE1 Make special hardware initialization for T1/E1 board */ + if (IS_TE1_MEDIA(&conf->fe_cfg)){ + + memcpy(&card->fe.fe_cfg, &conf->fe_cfg, sizeof(sdla_fe_cfg_t)); + sdla_te_iface_init(&card->wandev.fe_iface); + card->fe.name = card->devname; + card->fe.card = card; + card->fe.write_fe_reg = write_front_end_reg; + card->fe.read_fe_reg = read_front_end_reg; + + card->wandev.fe_enable_timer = chdlc_enable_timer; + card->wandev.te_link_state = chdlc_handle_front_end_state; + conf->interface = + (IS_T1_CARD(card)) ? WANOPT_V35 : WANOPT_RS232; + + if (card->u.c.comm_port == WANOPT_PRI){ + conf->clocking = WANOPT_EXTERNAL; + } + + }else if (IS_56K_MEDIA(&conf->fe_cfg)){ + + memcpy(&card->fe.fe_cfg, &conf->fe_cfg, sizeof(sdla_fe_cfg_t)); + sdla_56k_iface_init(&card->wandev.fe_iface); + card->fe.name = card->devname; + card->fe.card = card; + card->fe.write_fe_reg = write_front_end_reg; + card->fe.read_fe_reg = read_front_end_reg; + + if (card->u.c.comm_port == WANOPT_PRI){ + conf->clocking = WANOPT_EXTERNAL; + } + + }else{ + card->fe.fe_status = FE_CONNECTED; + } + + if (card->wandev.ignore_front_end_status == WANOPT_NO){ + printk(KERN_INFO + "%s: Enabling front end link monitor\n", + card->devname); + }else{ + printk(KERN_INFO + "%s: Disabling front end link monitor\n", + card->devname); + } + + + /* Read firmware version. Note that when adapter initializes, it + * clears the mailbox, so it may appear that the first command was + * executed successfully when in fact it was merely erased. To work + * around this, we execute the first command twice. + */ + + if (chdlc_read_version(card, str, sizeof(str))) + return -EIO; + + printk(KERN_INFO "%s: Running Cisco HDLC firmware v%s\n", + card->devname, str); + + if (set_adapter_config(card)) { + return -EIO; + } + + + card->isr = &wpc_isr; + card->poll = NULL; + card->exec = NULL; + card->wandev.update = &update; + card->wandev.new_if = &new_if; + card->wandev.del_if = &del_if; + + card->wandev.udp_port = conf->udp_port; + card->wandev.new_if_cnt = 0; + atomic_set(&card->wandev.if_cnt,0); + + // Proc fs functions + card->wandev.get_config_info = &chdlc_get_config_info; + card->wandev.get_status_info = &chdlc_get_status_info; + card->wandev.set_dev_config = &chdlc_set_dev_config; + card->wandev.set_if_info = &chdlc_set_if_info; + + /* reset the number of times the 'update()' proc has been called */ + card->u.c.update_call_count = 0; + + card->wandev.ttl = conf->ttl; + card->wandev.interface = conf->interface; + + if ((card->u.c.comm_port == WANOPT_SEC && conf->interface == WANOPT_V35)&& + card->type != SDLA_S514){ + printk(KERN_INFO "%s: ERROR - V35 Interface not supported on S508 %s port \n", + card->devname, PORT(card->u.c.comm_port)); + return -EIO; + } + + + port_num = card->u.c.comm_port; + + /* in API mode, we can configure for "receive only" buffering */ + if(card->type == SDLA_S514) { + card->u.c.receive_only = conf->receive_only; + if(conf->receive_only) { + printk(KERN_INFO + "%s: Configured for 'receive only' mode\n", + card->devname); + } + } + + /* Setup Port Bps */ + + if(card->wandev.clocking) { + max_permitted_baud = MAX_ASY_BAUD_RATE; + + if(conf->bps > max_permitted_baud) { + conf->bps = max_permitted_baud; + printk(KERN_INFO "%s: Baud too high!\n", + card->wandev.name); + printk(KERN_INFO "%s: Baud rate set to %lu bps\n", + card->wandev.name, max_permitted_baud); + } + card->wandev.bps = conf->bps; + }else{ + card->wandev.bps = 0; + } + + card->wandev.mtu = conf->mtu; + + + /* Set up the interrupt status area */ + /* Read the CHDLC Configuration and obtain: + * Ptr to shared memory infor struct + * Use this pointer to calculate the value of card->u.c.flags ! + */ + mb1->wan_data_len = 0; + mb1->wan_command = READ_ASY_CONFIGURATION; + + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb1); + if(err != COMMAND_OK) { + + DEBUG_EVENT("%s: CHDLC READ CONFIG cmd rc=0x%X\n", + card->devname,err); + + if(card->type != SDLA_S514) + enable_irq(card->wandev.irq); + + chdlc_error(card, err, mb1); + + return -EIO; + } + + /* ALEX: Apr 8 2004 SANGOMA ISA CARD */ + card->flags_off = + ((ASY_CONFIGURATION_STRUCT *)mb1->wan_data)-> + ptr_shared_mem_info_struct; + + card->intr_type_off = + card->flags_off + + offsetof(SHARED_MEMORY_INFO_STRUCT, interrupt_info_struct) + + offsetof(INTERRUPT_INFORMATION_STRUCT, interrupt_type); + card->intr_perm_off = + card->flags_off + + offsetof(SHARED_MEMORY_INFO_STRUCT, interrupt_info_struct) + + offsetof(INTERRUPT_INFORMATION_STRUCT, interrupt_permission); + card->fe_status_off = + card->flags_off + + offsetof(SHARED_MEMORY_INFO_STRUCT, FT1_info_struct) + + offsetof(FT1_INFORMATION_STRUCT, parallel_port_A_input); + + /* This is for the ports link state */ + card->wandev.state = WAN_DUALPORT; + + + if (!card->wandev.piggyback){ + int err; + + /* Perform interrupt testing */ + err = intr_test(card); + + if(err || (card->timer_int_enabled < 1)) { + printk(KERN_INFO "%s: Interrupt test failed (%i)\n", + card->devname, card->timer_int_enabled); + printk(KERN_INFO "%s: Please choose another interrupt\n", + card->devname); + return -EIO; + } + printk(KERN_INFO "%s: Interrupt test passed (%i)\n", + card->devname, card->timer_int_enabled); + card->configured = 1; + } + + if (chdlc_set_intr_mode(card, APP_INT_ON_TIMER)){ + printk (KERN_INFO "%s: Failed to set interrupt triggers!\n", + card->devname); + return -EIO; + } + + /* Mask the Timer interrupt */ + card->hw_iface.clear_bit(card->hw, card->intr_perm_off, APP_INT_ON_TIMER); + + /* If we are using CHDLC in backup mode, this flag will + * indicate not to look for IP addresses in config_chdlc()*/ + card->u.c.backup = conf->backup; + card->disable_comm = &disable_comm; + + printk(KERN_INFO "\n"); + + return 0; +} + +/******* WAN Device Driver Entry Points *************************************/ + +/*============================================================================ + * update - Update wanpipe device status & statistics + * + * @wandev: Wanpipe device pointer + * + * This procedure is called when updating the PROC file system. + * It returns various communications statistics. + * + * cat /proc/net/wanrouter/wanpipe# (where #=1,2,3...) + * + * These statistics are accumulated from 3 + * different locations: + * 1) The 'if_stats' recorded for the device. + * 2) Communication error statistics on the adapter. + * 3) CHDLC operational statistics on the adapter. + * + * The board level statistics are read during a timer interrupt. + * Note that we read the error and operational statistics + * during consecitive timer ticks so as to minimize the time + * that we are inside the interrupt handler. + * + */ +static int update (wan_device_t* wandev) +{ + sdla_t* card = wandev->private; + netdevice_t *dev; + chdlc_private_area_t* chdlc_priv_area; + unsigned long smp_flags; +#if 0 + SHARED_MEMORY_INFO_STRUCT *flags; + unsigned long timeout; +#endif + + /* sanity checks */ + if((wandev == NULL) || (wandev->private == NULL)) + return -EFAULT; + + if(wandev->state == WAN_UNCONFIGURED) + return -ENODEV; + + /* more sanity checks */ + if(test_bit(PERI_CRIT, (void*)&card->wandev.critical)) + return -EAGAIN; + + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + if (dev == NULL) + return -ENODEV; + + if((chdlc_priv_area = wan_netif_priv(dev)) == NULL) + return -ENODEV; + +#if 0 + flags = card->u.c.flags; +#endif + + if(test_and_set_bit(0,&chdlc_priv_area->update_comms_stats)){ + return -EAGAIN; + } + + /* TE1 Change the update_comms_stats variable to 3, + * only for T1/E1 card, otherwise 2 for regular + * S514/S508 card. + * Each timer interrupt will update only one type + * of statistics. + */ + + +#if 0 + chdlc_priv_area->update_comms_stats = + (IS_TE1_CARD(card) || IS_56K_CARD(card)) ? 3 : 2; + flags->interrupt_info_struct.interrupt_permission |= APP_INT_ON_TIMER; + card->u.c.timer_int_enabled = TMR_INT_ENABLED_UPDATE; + + /* wait a maximum of 1 second for the statistics to be updated */ + timeout = jiffies; + for(;;) { + if(chdlc_priv_area->update_comms_stats == 0) + break; + if ((jiffies - timeout) > (1 * HZ)){ + chdlc_priv_area->update_comms_stats = 0; + card->u.c.timer_int_enabled &= + ~TMR_INT_ENABLED_UPDATE; + return -EAGAIN; + } + } +#else + spin_lock_irqsave(&card->wandev.lock, smp_flags); + update_comms_stats(card, chdlc_priv_area); + chdlc_priv_area->update_comms_stats=0; + spin_unlock_irqrestore(&card->wandev.lock, smp_flags); +#endif + return 0; +} + + +/*============================================================================ + * new_if - Create new logical channel. + * + * &wandev: Wanpipe device pointer + * &dev: Network device pointer + * &conf: User configuration options pointer + * + * This routine is called by the ROUTER_IFNEW ioctl, + * in wanmain.c. The ioctl passes us the user configuration + * options which we use to configure the driver and + * firmware. + * + * This functions main purpose is to allocate the + * private structure for CHDLC protocol and bind it + * to dev->priv pointer. + * + * Also the dev->init pointer should also be initialized + * to the if_init() function. + * + * Any allocation necessary for the private strucutre + * should be done here, as well as proc/ file initializetion + * for the network interface. + * + * o parse media- and hardware-specific configuration + * o make sure that a new channel can be created + * o allocate resources, if necessary + * o prepare network device structure for registaration. + * o add network interface to the /proc/net/wanrouter + * + * The opposite of this function is del_if() + * + * Return: 0 o.k. + * < 0 failure (channel will not be created) + */ +static int new_if (wan_device_t* wandev, netdevice_t* dev, wanif_conf_t* conf) +{ + sdla_t* card = wandev->private; + chdlc_private_area_t* chdlc_priv_area; + int err = 0; + + printk(KERN_INFO "%s: Configuring Interface: %s\n", + card->devname, conf->name); + + if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) { + printk(KERN_INFO "%s: Invalid interface name!\n", + card->devname); + return -EINVAL; + } + + /* allocate and initialize private data */ + chdlc_priv_area = kmalloc(sizeof(chdlc_private_area_t), GFP_KERNEL); + + if(chdlc_priv_area == NULL){ + WAN_MEM_ASSERT(card->devname); + return -ENOMEM; + } + + memset(chdlc_priv_area, 0, sizeof(chdlc_private_area_t)); + + chdlc_priv_area->card = card; + strcpy(chdlc_priv_area->if_name, conf->name); + + WAN_TASKLET_INIT((&chdlc_priv_area->common.bh_task),0,chdlc_bh,(unsigned long)chdlc_priv_area); + if (atomic_read(&card->wandev.if_cnt) > 0){ + err=-EEXIST; + goto new_if_error; + } + + chdlc_priv_area->TracingEnabled = 0; + chdlc_priv_area->route_status = NO_ROUTE; + chdlc_priv_area->route_removed = 0; + + card->u.c.async_mode = 1; //conf->async_mode; + + /* setup for asynchronous mode */ + if(card->u.c.async_mode) { + printk(KERN_INFO "%s: Configuring for asynchronous mode\n", + wandev->name); + + if(strcmp(conf->usedby, "WANPIPE") == 0) { + printk(KERN_INFO "%s: Running in WANIPE Async Mode\n", + wandev->name); + chdlc_priv_area->common.usedby = WANPIPE; + }else{ + printk(KERN_INFO "%s: Running in API Async Mode\n", + wandev->name); + chdlc_priv_area->common.usedby = API; + wan_reg_api(chdlc_priv_area, dev, card->devname); + } + + if(!card->wandev.clocking) { + printk(KERN_INFO + "%s: Asynch. clocking must be 'Internal'\n", + wandev->name); + + err=-EINVAL; + goto new_if_error; + } + + if((card->wandev.bps < MIN_ASY_BAUD_RATE) || + (card->wandev.bps > MAX_ASY_BAUD_RATE)) { + printk(KERN_INFO "%s: Selected baud rate is invalid.\n", + wandev->name); + printk(KERN_INFO "Must be between %u and %u bps.\n", + MIN_ASY_BAUD_RATE, MAX_ASY_BAUD_RATE); + + err=-EINVAL; + goto new_if_error; + } + + card->u.c.api_options = 0; + + card->u.c.protocol_options = conf->u.chdlc.protocol_options; + + DEBUG_EVENT("%s: Asy Prtocol Options: 0x%04X\n", + card->devname,card->u.c.protocol_options); + + card->u.c.tx_bits_per_char = conf->tx_bits_per_char; + card->u.c.rx_bits_per_char = conf->rx_bits_per_char; + card->u.c.stop_bits = conf->stop_bits; + card->u.c.parity = conf->parity; + card->u.c.break_timer = conf->break_timer; + card->u.c.inter_char_timer = conf->inter_char_timer; + card->u.c.rx_complete_length = conf->rx_complete_length; + card->u.c.xon_char = conf->xon_char; + + } + + /* Tells us that if this interface is a + * gateway or not */ + if ((chdlc_priv_area->gateway = conf->gateway) == WANOPT_YES){ + printk(KERN_INFO "%s: Interface %s is set as a gateway.\n", + card->devname,chdlc_priv_area->if_name); + } + + /* Get Multicast Information */ + chdlc_priv_area->mc = conf->mc; + + /* + * Create interface file in proc fs. + * Once the proc file system is created, the new_if() function + * should exit successfuly. + * + * DO NOT place code under this function that can return + * anything else but 0. + */ + err = wanrouter_proc_add_interface(wandev, + &chdlc_priv_area->dent, + chdlc_priv_area->if_name, + dev); + if (err){ + printk(KERN_INFO + "%s: can't create /proc/net/router/fr/%s entry!\n", + card->devname, chdlc_priv_area->if_name); + goto new_if_error; + } + + /* Only setup the dev pointer once the new_if function has + * finished successfully. DO NOT place any code below that + * can return an error */ + + dev->init = &if_init; + dev->priv = chdlc_priv_area; + + set_bit(0,&chdlc_priv_area->config_chdlc); + + atomic_inc(&card->wandev.if_cnt); + + printk(KERN_INFO "\n"); + + return 0; + +new_if_error: + + WAN_TASKLET_KILL(&chdlc_priv_area->common.bh_task); + wan_unreg_api(chdlc_priv_area, card->devname); + + kfree(chdlc_priv_area); + + dev->priv=NULL; + + return err; +} + +/*============================================================================ + * del_if - Delete logical channel. + * + * @wandev: Wanpipe private device pointer + * @dev: Netowrk interface pointer + * + * This function is called by ROUTER_DELIF ioctl call + * to deallocate the network interface. + * + * The network interface and the private structure are + * about to be deallocated by the upper layer. + * We have to clean and deallocate any allocated memory. + * + */ +static int del_if (wan_device_t* wandev, netdevice_t* dev) +{ + chdlc_private_area_t* chdlc_priv_area = dev->priv; + sdla_t* card = chdlc_priv_area->card; + + WAN_TASKLET_KILL(&chdlc_priv_area->common.bh_task); + wan_unreg_api(chdlc_priv_area, card->devname); + + /* Delete interface name from proc fs. */ + wanrouter_proc_delete_interface(wandev, chdlc_priv_area->if_name); + + atomic_dec(&card->wandev.if_cnt); + return 0; +} + +/****** Network Device Interface ********************************************/ + +/*============================================================================ + * if_init - Initialize Linux network interface. + * + * @dev: Network interface pointer + * + * During "ifconfig up" the upper layer calls this function + * to initialize dev access pointers. Such as transmit, + * stats and header. + * + * It is called only once for each interface, + * during Linux network interface registration. + * + * Returning anything but zero will fail interface + * registration. + */ +static int if_init (netdevice_t* dev) +{ + chdlc_private_area_t* chdlc_priv_area = dev->priv; + sdla_t* card = chdlc_priv_area->card; + wan_device_t* wandev = &card->wandev; + + /* Initialize device driver entry points */ + dev->open = &if_open; + dev->stop = &if_close; + dev->hard_header = NULL; + dev->rebuild_header = NULL; + dev->hard_start_xmit = &if_send; + dev->get_stats = &if_stats; +#if defined(LINUX_2_4)||defined(LINUX_2_6) + dev->tx_timeout = &if_tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; +#endif + dev->do_ioctl = if_do_ioctl; + + if (chdlc_priv_area->common.usedby == BRIDGE || + chdlc_priv_area->common.usedby == BRIDGE_NODE){ + + /* Setup the interface for Bridging */ + int hw_addr=0; + ether_setup(dev); + + /* Use a random number to generate the MAC address */ + memcpy(dev->dev_addr, "\xFE\xFC\x00\x00\x00\x00", 6); + get_random_bytes(&hw_addr, sizeof(hw_addr)); + *(int *)(dev->dev_addr + 2) += hw_addr; + + }else{ + /* Initialize media-specific parameters */ + dev->flags |= IFF_POINTOPOINT; + dev->flags |= IFF_NOARP; + + /* Enable Mulitcasting if user selected */ + if (chdlc_priv_area->mc == WANOPT_YES){ + dev->flags |= (IFF_MULTICAST|IFF_ALLMULTI); + } + + if (chdlc_priv_area->true_if_encoding){ + dev->type = ARPHRD_HDLC; /* This breaks the tcpdump */ + }else{ + dev->type = ARPHRD_PPP; + } + + dev->mtu = card->wandev.mtu; + /* for API usage, add the API header size to the requested MTU size */ + if(chdlc_priv_area->common.usedby == API) { + dev->mtu += sizeof(api_tx_hdr_t); + } + + dev->hard_header_len = 0; + } + + /* Initialize hardware parameters */ + dev->irq = wandev->irq; + dev->dma = wandev->dma; + dev->base_addr = wandev->ioport; + card->hw_iface.getcfg(card->hw, SDLA_MEMBASE, &dev->mem_start); + card->hw_iface.getcfg(card->hw, SDLA_MEMEND, &dev->mem_end); + + /* Set transmit buffer queue length + * If too low packets will not be retransmitted + * by stack. + */ + dev->tx_queue_len = 100; + + return 0; +} + +/*============================================================================ + * if_open - Open network interface. + * + * @dev: Network device pointer + * + * On ifconfig up, this function gets called in order + * to initialize and configure the private area. + * Driver should be configured to send and receive data. + * + * This functions starts a timer that will call + * chdlc_config() function. This function must be called + * because the IP addresses could have been changed + * for this interface. + * + * Return 0 if O.k. or errno. + */ +static int if_open (netdevice_t* dev) +{ + chdlc_private_area_t* chdlc_priv_area = dev->priv; + sdla_t* card = chdlc_priv_area->card; + struct timeval tv; + int err = 0; + + /* Only one open per interface is allowed */ + if (open_dev_check(dev)) + return -EBUSY; + + do_gettimeofday(&tv); + chdlc_priv_area->router_start_time = tv.tv_sec; + + netif_start_queue(dev); + + /* Increment the module usage count */ + wanpipe_open(card); + + chdlc_priv_area->config_chdlc_timeout=jiffies; + + if (wan_test_bit(0,&chdlc_priv_area->config_chdlc)){ + SHARED_MEMORY_INFO_STRUCT flags; + card->hw_iface.peek(card->hw, card->flags_off, &flags, sizeof(flags)); + + wan_clear_bit(0,&chdlc_priv_area->config_chdlc); + card->u.c.timer_int_enabled |= TMR_INT_ENABLED_CONFIG; + flags.interrupt_info_struct.interrupt_permission |= APP_INT_ON_TIMER; + card->hw_iface.poke(card->hw, card->flags_off, &flags, sizeof(flags)); + } + + return err; +} + +/*============================================================================ + * if_close - Close network interface. + * + * @dev: Network device pointer + * + * On ifconfig down, this function gets called in order + * to cleanup interace private area. + * + * IMPORTANT: + * + * No deallocation or unconfiguration should ever occur in this + * function, because the interface can come back up + * (via ifconfig up). + * + * Furthermore, in dynamic interfacace configuration mode, the + * interface will come up and down to reflect the protocol state. + * + * Any private deallocation and cleanup can occur in del_if() + * function. That function is called before the dev interface + * itself is deallocated. + * + * Thus, we should only stop the net queue and decrement + * the wanpipe usage counter via wanpipe_close() function. + */ + +static int if_close (netdevice_t* dev) +{ + chdlc_private_area_t* chdlc_priv_area = dev->priv; + sdla_t* card = chdlc_priv_area->card; + + stop_net_queue(dev); + +#if defined(LINUX_2_1) + dev->start=0; +#endif + wanpipe_close(card); + del_timer(&chdlc_priv_area->poll_delay_timer); + + if (chdlc_priv_area->common.usedby == API){ + unsigned long smp_flags; + spin_lock_irqsave(&card->wandev.lock,smp_flags); + wan_unbind_api_from_svc(chdlc_priv_area, + chdlc_priv_area->common.sk); + spin_unlock_irqrestore(&card->wandev.lock,smp_flags); + } + + return 0; +} + + +/*============================================================= + * disable_comm - Main shutdown function + * + * @card: Wanpipe device pointer + * + * The command 'wanrouter stop' has been called + * and the whole wanpipe device is going down. + * This is the last function called to disable + * all comunications and deallocate any memory + * that is still allocated. + * + * o Disable communications, turn off interrupts + * o Deallocate memory used + * o Unconfigure TE1 card + */ + +static void disable_comm (sdla_t *card) +{ + unsigned long smp_flags; + + wan_spin_lock_irq(&card->wandev.lock,&smp_flags); + if (card->u.c.comm_enabled){ + chdlc_disable_comm_shutdown (card); + }else{ + card->hw_iface.poke_byte(card->hw, card->intr_perm_off, 0x00); + } + wan_spin_unlock_irq(&card->wandev.lock,&smp_flags); + + /* TE1 - Unconfiging, only on shutdown */ + if (IS_TE1_CARD(card)) { + if (card->wandev.fe_iface.unconfig){ + card->wandev.fe_iface.unconfig(&card->fe); + } + } + + return; +} + + + +/*============================================================================ + * Handle transmit timeout event from netif watchdog + */ +static void if_tx_timeout (netdevice_t *dev) +{ + chdlc_private_area_t* chan = dev->priv; + sdla_t *card = chan->card; + + /* If our device stays busy for at least 5 seconds then we will + * kick start the device by making dev->tbusy = 0. We expect + * that our device never stays busy more than 5 seconds. So this + * is only used as a last resort. + */ + + ++card->wandev.stats.collisions; + + printk (KERN_INFO "%s: Transmit timed out on %s\n", card->devname,dev->name); + netif_wake_queue (dev); +} + + +/*============================================================================ + * if_send - Send a packet on a network interface. + * + * @dev: Network interface pointer + * @skb: Packet obtained from the stack or API + * that should be sent out the port. + * + * o set tbusy flag (marks start of the transmission) to + * block a timer-based transmit from overlapping. + * o check link state. If link is not up, then drop the packet. + * o execute adapter send command. + * o free socket buffer if the send is successful, otherwise + * return non zero value and push the packet back into + * the stack. Also set the tx interrupt to wake up the + * stack when the firmware is able to send. + * + * Return: 0 complete (socket buffer must be freed) + * non-0 packet may be re-transmitted (tbusy must be set) + * + * Notes: + * 1. This routine is called either by the protocol stack or by the "net + * bottom half" (with interrupts enabled). + * 2. Setting tbusy flag will inhibit further transmit requests from the + * protocol stack and can be used for flow control with protocol layer. + */ +static int if_send (struct sk_buff* skb, netdevice_t* dev) +{ + chdlc_private_area_t *chdlc_priv_area = dev->priv; + sdla_t *card = chdlc_priv_area->card; + int udp_type = 0; + unsigned long smp_flags; + int err=0; + unsigned char misc_Tx_bits = 0; + +#if defined(LINUX_2_4)||defined(LINUX_2_6) + netif_stop_queue(dev); +#endif + + if (skb == NULL){ + /* If we get here, some higher layer thinks we've missed an + * tx-done interrupt. + */ + printk(KERN_INFO "%s: interface %s got kicked!\n", + card->devname, dev->name); + + wake_net_dev(dev); + return 0; + } + +#if defined(LINUX_2_1) + if (dev->tbusy){ + ++card->wandev.stats.collisions; + if((jiffies - chdlc_priv_area->tick_counter) < (5 * HZ)) { + return 1; + } + + if_tx_timeout (dev); + } +#endif + + if (chdlc_priv_area->common.usedby != ANNEXG && + skb->protocol != htons(PVC_PROT)){ + + /* check the udp packet type */ + + udp_type = udp_pkt_type(skb, card); + + if (udp_type == UDP_CPIPE_TYPE){ + if(store_udp_mgmt_pkt(UDP_PKT_FRM_STACK, card, skb, dev, + chdlc_priv_area)){ + card->hw_iface.set_bit(card->hw, card->intr_perm_off, APP_INT_ON_TIMER); + } + start_net_queue(dev); + return 0; + } + + /* check to see if the source IP address is a broadcast or */ + /* multicast IP address */ + if(chdlc_priv_area->common.usedby == WANPIPE && chk_bcast_mcast_addr(card, dev, skb)){ + ++card->wandev.stats.tx_dropped; + wan_skb_free(skb); + start_net_queue(dev); + return 0; + } + } + + /* Lock the 508 Card: SMP is supported */ + if(card->type != SDLA_S514){ + s508_lock(card,&smp_flags); + } + + if(test_and_set_bit(SEND_CRIT, (void*)&card->wandev.critical)) { + + printk(KERN_INFO "%s: Critical in if_send: %lx\n", + card->wandev.name,card->wandev.critical); + ++card->wandev.stats.tx_dropped; + goto if_send_exit_crit; + } + + if(card->wandev.state != WAN_CONNECTED){ + ++card->wandev.stats.tx_dropped; + + }else if(!skb->protocol){ + ++card->wandev.stats.tx_errors; + + }else { + void* data = skb->data; + unsigned len = skb->len; + unsigned char attr; + + /* If it's an API packet pull off the API + * header. Also check that the packet size + * is larger than the API header + */ + if (chdlc_priv_area->common.usedby == API){ + api_tx_hdr_t* api_tx_hdr; + + /* discard the frame if we are configured for */ + /* 'receive only' mode or if there is no data */ + if (card->u.c.receive_only || + (len <= sizeof(api_tx_hdr_t))) { + + ++card->wandev.stats.tx_dropped; + goto if_send_exit_crit; + } + + api_tx_hdr = (api_tx_hdr_t *)data; + attr = api_tx_hdr->attr; + misc_Tx_bits = api_tx_hdr->misc_Tx_bits; + data += sizeof(api_tx_hdr_t); + len -= sizeof(api_tx_hdr_t); + } + + err=chdlc_send(card, data, len, misc_Tx_bits); + + if(err) { + err=-1; + }else{ + ++card->wandev.stats.tx_packets; + card->wandev.stats.tx_bytes += len; +#if defined(LINUX_2_4)||defined(LINUX_2_6) + dev->trans_start = jiffies; +#endif + } + } + +if_send_exit_crit: + + if (err==0){ + wan_skb_free(skb); + start_net_queue(dev); + }else{ + stop_net_queue(dev); + chdlc_priv_area->tick_counter = jiffies; + card->hw_iface.set_bit(card->hw, card->intr_perm_off, APP_INT_ON_TX); + } + + clear_bit(SEND_CRIT, (void*)&card->wandev.critical); + if(card->type != SDLA_S514){ + s508_unlock(card,&smp_flags); + } + + return err; +} + + +/*============================================================================ + * chk_bcast_mcast_addr - Check for source broadcast addresses + * + * Check to see if the packet to be transmitted contains a broadcast or + * multicast source IP address. + */ + +static int chk_bcast_mcast_addr(sdla_t *card, netdevice_t* dev, + struct sk_buff *skb) +{ + u32 src_ip_addr; + u32 broadcast_ip_addr = 0; + chdlc_private_area_t *chdlc_priv_area=dev->priv; + struct in_device *in_dev; + /* read the IP source address from the outgoing packet */ + src_ip_addr = *(u32 *)(skb->data + 12); + + if (chdlc_priv_area->common.usedby != WANPIPE){ + return 0; + } + + /* read the IP broadcast address for the device */ + in_dev = dev->ip_ptr; + if(in_dev != NULL) { + struct in_ifaddr *ifa= in_dev->ifa_list; + if(ifa != NULL) + broadcast_ip_addr = ifa->ifa_broadcast; + else + return 0; + } + + /* check if the IP Source Address is a Broadcast address */ + if((dev->flags & IFF_BROADCAST) && (src_ip_addr == broadcast_ip_addr)) { + printk(KERN_INFO "%s: Broadcast Source Address silently discarded\n", + card->devname); + return 1; + } + + /* check if the IP Source Address is a Multicast address */ + if((ntohl(src_ip_addr) >= 0xE0000001) && + (ntohl(src_ip_addr) <= 0xFFFFFFFE)) { + printk(KERN_INFO "%s: Multicast Source Address silently discarded\n", + card->devname); + return 1; + } + + return 0; +} + + +/*============================================================================ + * Reply to UDP Management system. + * Return length of reply. + */ +static int reply_udp( unsigned char *data, unsigned int mbox_len ) +{ + + unsigned short len, udp_length, temp, ip_length; + unsigned long ip_temp; + int even_bound = 0; + wan_udp_pkt_t *c_udp_pkt = (wan_udp_pkt_t *)data; + + /* Set length of packet */ + len = sizeof(struct iphdr)+ + sizeof(struct udphdr)+ + sizeof(wan_mgmt_t)+ + sizeof(wan_cmd_t)+ + sizeof(wan_trace_info_t)+ + mbox_len; + + /* fill in UDP reply */ + c_udp_pkt->wan_udp_request_reply = UDPMGMT_REPLY; + + /* fill in UDP length */ + udp_length = sizeof(struct udphdr)+ + sizeof(wan_mgmt_t)+ + sizeof(wan_cmd_t)+ + sizeof(wan_trace_info_t)+ + mbox_len; + + /* put it on an even boundary */ + if ( udp_length & 0x0001 ) { + udp_length += 1; + len += 1; + even_bound = 1; + } + + temp = (udp_length<<8)|(udp_length>>8); + c_udp_pkt->wan_udp_len = temp; + + /* swap UDP ports */ + temp = c_udp_pkt->wan_udp_sport; + c_udp_pkt->wan_udp_sport = + c_udp_pkt->wan_udp_dport; + c_udp_pkt->wan_udp_dport = temp; + + /* add UDP pseudo header */ + temp = 0x1100; + *((unsigned short *)(c_udp_pkt->wan_udp_data+mbox_len+even_bound)) = temp; + temp = (udp_length<<8)|(udp_length>>8); + *((unsigned short *)(c_udp_pkt->wan_udp_data+mbox_len+even_bound+2)) = temp; + + + /* calculate UDP checksum */ + c_udp_pkt->wan_udp_sum = 0; + c_udp_pkt->wan_udp_sum = calc_checksum(&data[UDP_OFFSET],udp_length+UDP_OFFSET); + + /* fill in IP length */ + ip_length = len; + temp = (ip_length<<8)|(ip_length>>8); + c_udp_pkt->wan_ip_len = temp; + + /* swap IP addresses */ + ip_temp = c_udp_pkt->wan_ip_src; + c_udp_pkt->wan_ip_src = c_udp_pkt->wan_ip_dst; + c_udp_pkt->wan_ip_dst = ip_temp; + + /* fill in IP checksum */ + c_udp_pkt->wan_ip_sum = 0; + c_udp_pkt->wan_ip_sum = calc_checksum(data,sizeof(struct iphdr)); + + return len; + +} /* reply_udp */ + +unsigned short calc_checksum (char *data, int len) +{ + unsigned short temp; + unsigned long sum=0; + int i; + + for( i = 0; i > 16 ) { + sum = (sum & 0xffffUL) + (sum >> 16); + } + + temp = (unsigned short)sum; + temp = ~temp; + + if( temp == 0 ) + temp = 0xffff; + + return temp; +} + + +/*============================================================================ + * Get ethernet-style interface statistics. + * Return a pointer to struct enet_statistics. + */ +static struct net_device_stats* if_stats (netdevice_t* dev) +{ + sdla_t *my_card; + chdlc_private_area_t* chdlc_priv_area; + + if ((chdlc_priv_area=dev->priv) == NULL) + return NULL; + + my_card = chdlc_priv_area->card; + return &my_card->wandev.stats; +} + +/****** Cisco HDLC Firmware Interface Functions *******************************/ + +/*============================================================================ + * Read firmware code version. + * Put code version as ASCII string in str. + */ +static int chdlc_read_version (sdla_t* card, char* str, int str_size) +{ + wan_mbox_t* mb = &card->wan_mbox; + int len; + char err; + + mb->wan_data_len = 0; + mb->wan_command = READ_ASY_CODE_VERSION; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + + if(err != COMMAND_OK) { + chdlc_error(card,err,mb); + }else if (str) { /* is not null */ + len = mb->wan_data_len; + if (len < str_size){ + memcpy(str, mb->wan_data, len); + str[len] = '\0'; + }else{ + DEBUG_EVENT("%s: Error: Version Length greater than max %i>%i!\n", + card->devname,len,str_size); + } + } + return (err); +} + +/*============================================================================ + * Set interrupt mode -- HDLC Version. + */ + +static int chdlc_set_intr_mode (sdla_t* card, unsigned mode) +{ + wan_mbox_t* mb = &card->wan_mbox; + ASY_INT_TRIGGERS_STRUCT* int_data = + (ASY_INT_TRIGGERS_STRUCT *)mb->wan_data; + int err; + + int_data->interrupt_triggers = mode; + int_data->IRQ = card->wandev.irq; + int_data->interrupt_timer = 1; + + mb->wan_data_len = sizeof(ASY_INT_TRIGGERS_STRUCT); + mb->wan_command = SET_ASY_INTERRUPT_TRIGGERS; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != COMMAND_OK) + chdlc_error (card, err, mb); + return err; +} + + +/*=========================================================== + * chdlc_disable_comm_shutdown + * + * Shutdown() disables the communications. We must + * have a sparate functions, because we must not + * call chdlc_error() hander since the private + * area has already been replaced */ + +static int chdlc_disable_comm_shutdown (sdla_t *card) +{ + wan_mbox_t* mb = &card->wan_mbox; + int err; + + ASY_INT_TRIGGERS_STRUCT* int_data = + (ASY_INT_TRIGGERS_STRUCT *)mb->wan_data; + + /* Disable Interrutps */ + int_data->interrupt_triggers = 0; + int_data->IRQ = card->wandev.irq; + int_data->interrupt_timer = 1; + + mb->wan_data_len = sizeof(ASY_INT_TRIGGERS_STRUCT); + mb->wan_command = SET_ASY_INTERRUPT_TRIGGERS; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + + /* Disable Communications */ + if (card->u.c.async_mode) { + mb->wan_command = DISABLE_ASY_COMMUNICATIONS; + }else{ + mb->wan_command = DISABLE_ASY_COMMUNICATIONS; + } + + mb->wan_data_len = 0; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + + card->u.c.comm_enabled = 0; + + /* TE1 - Unconfiging, only on shutdown */ + if (IS_TE1_CARD(card)) { + if (card->wandev.fe_iface.unconfig){ + card->wandev.fe_iface.unconfig(&card->fe); + } + } + + return 0; +} + +/*============================================================================ + * Enable communications. + */ + +static int chdlc_comm_enable (sdla_t* card) +{ + int err; + wan_mbox_t* mb = &card->wan_mbox; + + mb->wan_data_len = 0; + mb->wan_command = ENABLE_ASY_COMMUNICATIONS; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != COMMAND_OK) + chdlc_error(card, err, mb); + else + card->u.c.comm_enabled = 1; + + return err; +} + +/*============================================================================ + * Enable communications. + */ + +static int chdlc_comm_disable (sdla_t* card) +{ + int err; + wan_mbox_t* mb = &card->wan_mbox; + + mb->wan_data_len = 0; + mb->wan_command = DISABLE_ASY_COMMUNICATIONS; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != COMMAND_OK) + chdlc_error(card, err, mb); + else + card->u.c.comm_enabled = 0; + + return err; +} + + +/*============================================================================ + * Read communication error statistics. + */ +static int chdlc_read_comm_err_stats (sdla_t* card) +{ + int err; + wan_mbox_t* mb = &card->wan_mbox; + + mb->wan_data_len = 0; + mb->wan_command = READ_COMMS_ERROR_STATS; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != COMMAND_OK) + chdlc_error(card,err,mb); + return err; +} + + + +/*============================================================================ + * Update communications error and general packet statistics. + */ +static int update_comms_stats(sdla_t* card, + chdlc_private_area_t* chdlc_priv_area) +{ + wan_mbox_t* mb = &card->wan_mbox; + COMMS_ERROR_STATS_STRUCT* err_stats; + + /* 1. On the first timer interrupt, update T1/E1 alarms + * and PMON counters (only for T1/E1 card) (TE1) + */ + /* TE1 Update T1/E1 alarms */ + if (IS_TE1_CARD(card)) { + card->wandev.fe_iface.read_alarm(&card->fe, 0); + /* TE1 Update T1/E1 perfomance counters */ + card->wandev.fe_iface.read_pmon(&card->fe); + }else if (IS_56K_CARD(card)) { + /* 56K Update CSU/DSU alarms */ + card->wandev.fe_iface.read_alarm(&card->fe, 1); + } + + if(chdlc_read_comm_err_stats(card)) + return 1; + + err_stats = (COMMS_ERROR_STATS_STRUCT *)mb->wan_data; + card->wandev.stats.rx_over_errors = + err_stats->Rx_overrun_err_count; + card->wandev.stats.rx_crc_errors = + err_stats->Rx_parity_err_count; + card->wandev.stats.rx_frame_errors = + err_stats->Rx_framing_err_count; + + return 0; +} + +/*============================================================================ + * Send packet. + * Return: 0 - o.k. + * 1 - no transmit buffers available + */ +static int chdlc_send (sdla_t* card, void* data, unsigned len, unsigned char tx_bits) +{ + ASY_DATA_TX_STATUS_EL_STRUCT txbuf; + + card->hw_iface.peek(card->hw, card->u.c.txbuf_off, &txbuf, sizeof(txbuf)); + if (txbuf.opp_flag){ + return 1; + } + + card->hw_iface.poke(card->hw, txbuf.ptr_data_bfr, data, len); + + txbuf.data_length = len; + card->hw_iface.poke(card->hw, + card->u.c.txbuf_off, + &txbuf, + sizeof(txbuf)); + txbuf.opp_flag = 1; /* start transmission */ + card->hw_iface.poke_byte(card->hw, + card->u.c.txbuf_off+ + offsetof(ASY_DATA_TX_STATUS_EL_STRUCT, opp_flag), + txbuf.opp_flag); + + /* Update transmit buffer control fields */ + card->u.c.txbuf_off += sizeof(txbuf); + if (card->u.c.txbuf_off > card->u.c.txbuf_last_off){ + card->u.c.txbuf_off = card->u.c.txbuf_base_off; + } + + return 0; +} + +/*============================================================================ + * Read TE1/56K Front end registers + */ +static unsigned char read_front_end_reg (void* card1, unsigned short reg) +{ + sdla_t* card = (sdla_t*)card1; + wan_mbox_t* mb = &card->wan_mbox; + char* data = mb->wan_data; + int err; + + ((FRONT_END_REG_STRUCT *)data)->register_number = (unsigned short)reg; + mb->wan_data_len = sizeof(FRONT_END_REG_STRUCT); + mb->wan_command = READ_FRONT_END_REGISTER; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != COMMAND_OK){ + chdlc_error(card,err,mb); + } + + return(((FRONT_END_REG_STRUCT *)data)->register_value); +} + +/*============================================================================ + * Write to TE1/56K Front end registers + */ +static unsigned char write_front_end_reg (void* card1, unsigned short reg, unsigned char value) +{ + sdla_t* card = (sdla_t*)card1; + wan_mbox_t* mb = &card->wan_mbox; + char* data = mb->wan_data; + int err; + int retry=15; + + do { + ((FRONT_END_REG_STRUCT *)data)->register_number = (unsigned short)reg; + ((FRONT_END_REG_STRUCT *)data)->register_value = value; + mb->wan_data_len = sizeof(FRONT_END_REG_STRUCT); + mb->wan_command = WRITE_FRONT_END_REGISTER; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != COMMAND_OK){ + chdlc_error(card,err,mb); + } + }while(err && --retry); + + return err; +} + +/*============================================================================ + * Enable timer interrupt + */ +static void chdlc_enable_timer (void* card_id) +{ + sdla_t *card = (sdla_t*)card_id; + netdevice_t *dev; + + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + DEBUG_TEST("%s: Chdlc enabling timer %s\n",card->devname, + dev ? wan_netif_name(dev) : "No DEV"); + + card->u.c.timer_int_enabled |= TMR_INT_ENABLED_TE; + card->hw_iface.set_bit(card->hw, card->intr_perm_off, APP_INT_ON_TIMER); + return; +} + +/****** Firmware Error Handler **********************************************/ + +/*============================================================================ + * Firmware error handler. + * This routine is called whenever firmware command returns non-zero + * return code. + * + * Return zero if previous command has to be cancelled. + */ +static int chdlc_error (sdla_t *card, int err, wan_mbox_t *mb) +{ + unsigned cmd = mb->wan_command; + + switch (err) { + + case CMD_TIMEOUT: + printk(KERN_INFO "%s: command 0x%02X timed out!\n", + card->devname, cmd); + break; + + default: + printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n", + card->devname, cmd, err); + } + + return 0; +} + +/********** Bottom Half Handlers ********************************************/ + +/* NOTE: There is no API, BH support for Kernels lower than 2.2.X. + * DO NOT INSERT ANY CODE HERE, NOTICE THE + * PREPROCESSOR STATEMENT ABOVE, UNLESS YOU KNOW WHAT YOU ARE + * DOING */ + +static void chdlc_bh (unsigned long data) +{ + chdlc_private_area_t* chan = (chdlc_private_area_t*)data; + sdla_t *card = chan->card; + struct sk_buff *skb; + int len=0; + + while ((skb=wan_api_dequeue_skb(chan)) != NULL){ + + len=skb->len; + if (chan->common.usedby == API){ + if (wan_api_rx(chan,skb) == 0){ + card->wandev.stats.rx_packets++; + card->wandev.stats.rx_bytes += len; + }else{ + ++card->wandev.stats.rx_dropped; + wan_skb_free(skb); + } + }else{ + wan_skb_free(skb); + ++card->wandev.stats.rx_dropped; + } + } + + WAN_TASKLET_END((&chan->common.bh_task)); + + return; +} + +/* END OF API BH Support */ + + +/****** Interrupt Handlers **************************************************/ + +/*============================================================================ + * Cisco HDLC interrupt service routine. + */ +static void wpc_isr (sdla_t* card) +{ + netdevice_t* dev; + SHARED_MEMORY_INFO_STRUCT flags; + int i; + + /* Check for which port the interrupt has been generated + * Since Secondary Port is piggybacking on the Primary + * the check must be done here. + */ + + if (!card->hw){ + return; + } + + card->hw_iface.peek(card->hw, card->flags_off, + &flags, sizeof(flags)); + + /* Start card isr critical area */ + set_bit(0,&card->in_isr); + + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + + /* If we get an interrupt with no network device, stop the interrupts + * and issue an error */ + if (!card->tty_opt && !dev && + flags.interrupt_info_struct.interrupt_type != + COMMAND_COMPLETE_APP_INT_PEND){ + goto isr_done; + } + + /* if critical due to peripheral operations + * ie. update() or getstats() then reset the interrupt and + * wait for the board to retrigger. + */ + if(test_bit(PERI_CRIT, (void*)&card->wandev.critical)) { + printk(KERN_INFO "%s: Chdlc ISR: Critical with PERI_CRIT!\n", + card->devname); + goto isr_done; + } + + /* On a 508 Card, if critical due to if_send + * Major Error !!! */ + if(card->type != SDLA_S514) { + if(test_bit(SEND_CRIT, (void*)&card->wandev.critical)) { + printk(KERN_INFO "%s: Chdlc ISR: Critical with SEND_CRIT!\n", + card->devname); + card->in_isr = 0; + card->hw_iface.poke_byte(card->hw, card->intr_type_off, 0x00); + return; + } + } + + + + switch(flags.interrupt_info_struct.interrupt_type){ + + case RX_APP_INT_PEND: /* 0x01: receive interrupt */ + rx_intr(card); + break; + + case TX_APP_INT_PEND: /* 0x02: transmit interrupt */ + card->hw_iface.clear_bit(card->hw, card->intr_perm_off, APP_INT_ON_TX); + + if (dev && is_queue_stopped(dev)){ + chdlc_private_area_t* chdlc_priv_area=dev->priv; + + if (chdlc_priv_area->common.usedby == API){ + start_net_queue(dev); + wan_wakeup_api(chdlc_priv_area); + }else{ + wake_net_dev(dev); + } + } + break; + + case COMMAND_COMPLETE_APP_INT_PEND:/* 0x04: cmd cplt */ + ++ card->timer_int_enabled; + break; + + case GLOBAL_EXCEP_COND_APP_INT_PEND: + process_global_exception(card); + + /* Reset the 56k or T1/E1 front end exception condition */ + if(IS_56K_CARD(card) || IS_TE1_CARD(card)) { + FRONT_END_STATUS_STRUCT FE_status; + + card->hw_iface.peek(card->hw, + card->fe_status_off, + &FE_status, + sizeof(FE_status)); + FE_status.opp_flag = 0x01; + card->hw_iface.poke(card->hw, + card->fe_status_off, + &FE_status, + sizeof(FE_status)); + } + break; + + case TIMER_APP_INT_PEND: + timer_intr(card); + break; + + default: + + if (card->next){ + set_bit(0,&card->spurious); + }else{ + printk(KERN_INFO "%s: spurious interrupt 0x%02X!\n", + card->devname, + flags.interrupt_info_struct.interrupt_type); + printk(KERN_INFO "Code name: "); + for(i = 0; i < 4; i ++){ + printk("%c", + flags.global_info_struct.code_name[i]); + } + printk("\n"); + printk(KERN_INFO "Code version: "); + for(i = 0; i < 4; i ++){ + printk("%c", + flags.global_info_struct.code_version[i]); + } + printk("\n"); + } + break; + } + +isr_done: + + card->in_isr = 0; + card->hw_iface.poke_byte(card->hw, card->intr_type_off, 0x00); + return; +} + +/*============================================================================ + * Receive interrupt handler. + */ +static void rx_intr (sdla_t* card) +{ + netdevice_t *dev; + chdlc_private_area_t *chdlc_priv_area; + SHARED_MEMORY_INFO_STRUCT flags; + ASY_DATA_RX_STATUS_EL_STRUCT rxbuf; + struct sk_buff *skb; + unsigned addr; + unsigned len; + void *buf; + int i,udp_type; + + card->hw_iface.peek(card->hw, card->flags_off, &flags, sizeof(flags)); + card->hw_iface.peek(card->hw, card->u.c.rxmb_off, &rxbuf, sizeof(rxbuf)); + addr = rxbuf.ptr_data_bfr; + if (rxbuf.opp_flag != 0x01) { + printk(KERN_INFO + "%s: corrupted Rx buffer @ 0x%X, flag = 0x%02X!\n", + card->devname, (unsigned)card->u.c.rxmb_off, rxbuf.opp_flag); + printk(KERN_INFO "Code name: "); + for(i = 0; i < 4; i ++) + printk(KERN_INFO "%c", + flags.global_info_struct.code_name[i]); + printk(KERN_INFO "\n"); + printk(KERN_INFO "Code version: "); + for(i = 0; i < 4; i ++) + printk(KERN_INFO "%c", + flags.global_info_struct.code_version[i]); + printk(KERN_INFO "\n"); + + /* Bug Fix: Mar 6 2000 + * If we get a corrupted mailbox, it measn that driver + * is out of sync with the firmware. There is no recovery. + * If we don't turn off all interrupts for this card + * the machine will crash. + */ + printk(KERN_INFO "%s: Critical router failure ...!!!\n", card->devname); + printk(KERN_INFO "Please contact Sangoma Technologies !\n"); + chdlc_set_intr_mode(card,0); + return; + } + + len = rxbuf.data_length; + + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + if (!dev || !wan_netif_priv(dev)) + goto rx_exit; + + if (!is_dev_running(dev)) + goto rx_exit; + + chdlc_priv_area = wan_netif_priv(dev); + + if (chdlc_priv_area->common.usedby == ANNEXG){ + + /* Take off two CRC bytes */ + if (rxbuf.data_length <= 2 || rxbuf.data_length > 1506 ){ + printk(KERN_INFO "Bad Rx Frame Length %i\n", + rxbuf.data_length); + goto rx_exit; + } + len = rxbuf.data_length - CRC_LENGTH; + } + + /* Allocate socket buffer */ + skb = dev_alloc_skb(len+2); + + if (skb == NULL) { + printk(KERN_INFO "%s: no socket buffers available!\n", + card->devname); + ++card->wandev.stats.rx_dropped; + goto rx_exit; + } + + /* Align IP on 16 byte */ + skb_reserve(skb,2); + + /* Copy data to the socket buffer */ + if((addr + len) > card->u.c.rx_top_off + 1) { + unsigned tmp = card->u.c.rx_top_off - addr + 1; + buf = skb_put(skb, tmp); + card->hw_iface.peek(card->hw, addr, buf, tmp); + addr = card->u.c.rx_base_off; + len -= tmp; + } + + buf = skb_put(skb, len); + card->hw_iface.peek(card->hw, addr, buf, len); + + skb->protocol = htons(ETH_P_IP); + + udp_type = udp_pkt_type( skb, card ); + + if(udp_type == UDP_CPIPE_TYPE) { + if(store_udp_mgmt_pkt(UDP_PKT_FRM_NETWORK, + card, skb, dev, chdlc_priv_area)) { + card->hw_iface.set_bit(card->hw, card->intr_perm_off, APP_INT_ON_TIMER); + } + + } else if(chdlc_priv_area->common.usedby == API) { + + api_rx_hdr_t* api_rx_hdr; + skb_push(skb, sizeof(api_rx_hdr_t)); + api_rx_hdr = (api_rx_hdr_t*)&skb->data[0x00]; + api_rx_hdr->error_flag=0; + api_rx_hdr->time_stamp = rxbuf.time_stamp; + + skb->protocol = htons(WP_PVC_PROT); + skb->mac.raw = skb->data; + skb->dev = dev; + skb->pkt_type = WAN_PACKET_DATA; + + if (wan_api_enqueue_skb(chdlc_priv_area,skb) < 0){ + wan_skb_free(skb); + ++card->wandev.stats.rx_dropped; + goto rx_exit; + } + + WAN_TASKLET_SCHEDULE(&chdlc_priv_area->common.bh_task); + + } else if (chdlc_priv_area->common.usedby == ANNEXG){ + + if (chdlc_priv_area->annexg_dev){ + skb->protocol = htons(ETH_P_X25); + skb->dev = chdlc_priv_area->annexg_dev; + skb->mac.raw = skb->data; + + if (wan_api_enqueue_skb(chdlc_priv_area,skb) < 0){ + wan_skb_free(skb); + ++card->wandev.stats.rx_dropped; + goto rx_exit; + } + + WAN_TASKLET_SCHEDULE(&chdlc_priv_area->common.bh_task); + + }else{ + wan_skb_free(skb); + ++card->wandev.stats.rx_errors; + } + + }else if (chdlc_priv_area->common.usedby == BRIDGE || + chdlc_priv_area->common.usedby == BRIDGE_NODE){ + + /* Make sure it's an Ethernet frame, otherwise drop it */ + if (skb->len <= ETH_ALEN) { + wan_skb_free(skb); + ++card->wandev.stats.rx_errors; + goto rx_exit; + } + + card->wandev.stats.rx_packets ++; + card->wandev.stats.rx_bytes += skb->len; + + skb->dev = dev; + skb->protocol=eth_type_trans(skb,dev); + netif_rx(skb); + }else{ + /* FIXME: we should check to see if the received packet is a + multicast packet so that we can increment the multicast + statistic + ++ chdlc_priv_area->if_stats.multicast; + */ + /* Pass it up the protocol stack */ + + card->wandev.stats.rx_packets ++; + card->wandev.stats.rx_bytes += skb->len; + + skb->protocol = htons(ETH_P_IP); + skb->dev = dev; + skb->mac.raw = skb->data; + netif_rx(skb); + } + +rx_exit: + /* Release buffer element and calculate a pointer to the next one */ + rxbuf.opp_flag = 0x00; + card->hw_iface.poke_byte(card->hw, + card->u.c.rxmb_off+offsetof(ASY_DATA_RX_STATUS_EL_STRUCT, opp_flag), + rxbuf.opp_flag); + card->u.c.rxmb_off += sizeof(rxbuf); + if (card->u.c.rxmb_off > card->u.c.rxbuf_last_off){ + card->u.c.rxmb_off = card->u.c.rxbuf_base_off; + } +} + +/*============================================================================ + * Timer interrupt handler. + * The timer interrupt is used for two purposes: + * 1) Processing udp calls from 'cpipemon'. + * 2) Reading board-level statistics for updating the proc file system. + */ +void timer_intr(sdla_t *card) +{ + netdevice_t* dev=NULL; + chdlc_private_area_t* chdlc_priv_area = NULL; + /* TE timer interrupt */ + if (card->u.c.timer_int_enabled & TMR_INT_ENABLED_TE) { + card->wandev.fe_iface.polling(&card->fe); + card->u.c.timer_int_enabled &= ~TMR_INT_ENABLED_TE; + } + + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + if (!dev || !wan_netif_priv(dev)){ + goto timer_isr_exit; + } + + chdlc_priv_area = dev->priv; + + /* Configure hardware */ + if (card->u.c.timer_int_enabled & TMR_INT_ENABLED_CONFIG) { + config_chdlc(card, dev); + card->u.c.timer_int_enabled &= ~TMR_INT_ENABLED_CONFIG; + } + + /* process a udp call if pending */ + if(card->u.c.timer_int_enabled & TMR_INT_ENABLED_UDP) { + process_udp_mgmt_pkt(card, dev, + chdlc_priv_area,0); + card->u.c.timer_int_enabled &= ~TMR_INT_ENABLED_UDP; + } + + /* read the communications statistics if required */ + if(card->u.c.timer_int_enabled & TMR_INT_ENABLED_UPDATE) { + update_comms_stats(card, chdlc_priv_area); + if(!(-- chdlc_priv_area->update_comms_stats)) { + card->u.c.timer_int_enabled &= + ~TMR_INT_ENABLED_UPDATE; + } + } + +timer_isr_exit: + + /* only disable the timer interrupt if there are no udp or statistic */ + /* updates pending */ + if(!card->u.c.timer_int_enabled) { + card->hw_iface.clear_bit(card->hw, card->intr_perm_off, APP_INT_ON_TIMER); + } +} + + +/*----------------------------------------------------------------------------- + set_asy_config() used to set asynchronous configuration options on the board +------------------------------------------------------------------------------*/ + +static int set_asy_config(sdla_t* card) +{ + + ASY_CONFIGURATION_STRUCT cfg; + wan_mbox_t *mb = &card->wan_mbox; + int err; + + memset(&cfg, 0, sizeof(ASY_CONFIGURATION_STRUCT)); + + if(card->wandev.clocking) + cfg.baud_rate = card->wandev.bps; + + cfg.line_config_options = (card->wandev.interface == WANOPT_RS232) ? + INTERFACE_LEVEL_RS232 : INTERFACE_LEVEL_V35; + + cfg.modem_config_options = 0; + cfg.API_options = card->u.c.api_options; + cfg.protocol_options = card->u.c.protocol_options; + cfg.Tx_bits_per_char = card->u.c.tx_bits_per_char; + cfg.Rx_bits_per_char = card->u.c.rx_bits_per_char; + cfg.stop_bits = card->u.c.stop_bits; + cfg.parity = card->u.c.parity; + cfg.break_timer = card->u.c.break_timer; + cfg.Rx_inter_char_timer = card->u.c.inter_char_timer; + cfg.Rx_complete_length = card->u.c.rx_complete_length; + cfg.XON_char = card->u.c.xon_char; + cfg.XOFF_char = card->u.c.xoff_char; + cfg.statistics_options = 0x001F; + + mb->wan_data_len = sizeof(ASY_CONFIGURATION_STRUCT); + memcpy(mb->wan_data, &cfg, mb->wan_data_len); + mb->wan_command = SET_ASY_CONFIGURATION; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != COMMAND_OK) + chdlc_error (card, err, mb); + return err; +} + +/*============================================================================ + * Enable asynchronous communications. + */ + +static int asy_comm_enable (sdla_t* card) +{ + netdevice_t *dev; + int err; + wan_mbox_t *mb = &card->wan_mbox; + + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + if (dev == NULL){ + return -EINVAL; + } + mb->wan_data_len = 0; + mb->wan_command = ENABLE_ASY_COMMUNICATIONS; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != COMMAND_OK && dev) + chdlc_error(card, err, mb); + + if (!err) + card->u.c.comm_enabled = 1; + + return err; +} + +/*============================================================================ + * Process global exception condition + */ +static int process_global_exception(sdla_t *card) +{ + wan_mbox_t* mb = &card->wan_mbox; + int err; + + mb->wan_data_len = 0; + mb->wan_command = READ_GLOBAL_EXCEPTION_CONDITION; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + + if(err != CMD_TIMEOUT ){ + + switch(mb->wan_return_code) { + + case EXCEP_MODEM_STATUS_CHANGE: + + if (IS_56K_CARD(card)) { + + FRONT_END_STATUS_STRUCT FE_status; + + card->hw_iface.peek(card->hw, + card->fe_status_off, + &FE_status, + sizeof(FE_status)); + + card->fe.fe_param.k56_param.RR8_reg_56k = + FE_status.FE_U.stat_56k.RR8_56k; + card->fe.fe_param.k56_param.RRA_reg_56k = + FE_status.FE_U.stat_56k.RRA_56k; + card->fe.fe_param.k56_param.RRC_reg_56k = + FE_status.FE_U.stat_56k.RRC_56k; + card->wandev.fe_iface.read_alarm(&card->fe, 0); + + chdlc_handle_front_end_state(card); + break; + + } + + if (IS_TE1_CARD(card)) { + /* TE1 T1/E1 interrupt */ + card->wandev.fe_iface.isr(&card->fe); + chdlc_handle_front_end_state(card); + break; + } + + if ((mb->wan_data[0] & (DCD_HIGH | CTS_HIGH)) == (DCD_HIGH | CTS_HIGH)){ + card->fe.fe_status = FE_CONNECTED; + }else{ + card->fe.fe_status = FE_DISCONNECTED; + } + + printk(KERN_INFO "%s: Modem status change\n", + card->devname); + + switch(mb->wan_data[0] & (DCD_HIGH | CTS_HIGH)) { + + case ((DCD_HIGH | CTS_HIGH)): + printk(KERN_INFO "%s: DCD high, CTS high\n",card->devname); + break; + + case (DCD_HIGH): + printk(KERN_INFO "%s: DCD high, CTS low\n",card->devname); + break; + + case (CTS_HIGH): + printk(KERN_INFO "%s: DCD low, CTS high\n",card->devname); + break; + + default: + printk(KERN_INFO "%s: DCD low, CTS low\n",card->devname); + break; + } + + break; + + default: + printk(KERN_INFO "%s: Global exception %x\n", + card->devname, mb->wan_return_code); + break; + } + } + return 0; +} + + + +/** + * if_do_ioctl - Ioctl handler for fr + * @dev: Device subject to ioctl + * @ifr: Interface request block from the user + * @cmd: Command that is being issued + * + * This function handles the ioctls that may be issued by the user + * to control the settings of a FR. It does both busy + * and security checks. This function is intended to be wrapped by + * callers who wish to add additional ioctl calls of their own. + */ +/* SNMP */ +static int if_do_ioctl(netdevice_t *dev, struct ifreq *ifr, int cmd) +{ + chdlc_private_area_t* chan= (chdlc_private_area_t*)dev->priv; + unsigned long smp_flags; + sdla_t *card; + wan_udp_pkt_t *wan_udp_pkt; + int err=0; + + if (!chan){ + return -ENODEV; + } + card=chan->card; + + NET_ADMIN_CHECK(); + + switch(cmd) + { + + case SIOC_WANPIPE_BIND_SK: + if (!ifr){ + err= -EINVAL; + break; + } + + spin_lock_irqsave(&card->wandev.lock,smp_flags); + err=wan_bind_api_to_svc(chan,ifr->ifr_data); + spin_unlock_irqrestore(&card->wandev.lock,smp_flags); + break; + + case SIOC_WANPIPE_UNBIND_SK: + if (!ifr){ + err= -EINVAL; + break; + } + + spin_lock_irqsave(&card->wandev.lock,smp_flags); + err=wan_unbind_api_from_svc(chan,ifr->ifr_data); + spin_unlock_irqrestore(&card->wandev.lock,smp_flags); + break; + + case SIOC_WANPIPE_CHECK_TX: + case SIOC_ANNEXG_CHECK_TX: + err=0; + break; + + case SIOC_WANPIPE_DEV_STATE: + err = chan->common.state; + break; + + case SIOC_ANNEXG_KICK: + err=0; + break; + + case SIOC_ASYHDLC_RX_AVAIL_CMD: + { + SHARED_MEMORY_INFO_STRUCT flags; + card->hw_iface.peek(card->hw, card->flags_off, &flags, sizeof(flags)); + if (flags.async_info_struct.asy_rx_avail){ + err=HDLC_RX_IN_PROCESS; + }else{ + err=NO_HDLC_RX_IN_PROCESS; + } + } + break; + + case SIOC_WANPIPE_PIPEMON: + + if (atomic_read(&chan->udp_pkt_len) != 0){ + return -EBUSY; + } + + atomic_set(&chan->udp_pkt_len,MAX_LGTH_UDP_MGNT_PKT); + + /* For performance reasons test the critical + * here before spin lock */ + if (test_bit(0,&card->in_isr)){ + atomic_set(&chan->udp_pkt_len,0); + return -EBUSY; + } + + + wan_udp_pkt=(wan_udp_pkt_t*)chan->udp_pkt_data; + if (copy_from_user(&wan_udp_pkt->wan_udp_hdr,ifr->ifr_data,sizeof(wan_udp_hdr_t))){ + atomic_set(&chan->udp_pkt_len,0); + return -EFAULT; + } + + spin_lock_irqsave(&card->wandev.lock, smp_flags); + + /* We have to check here again because we don't know + * what happened during spin_lock */ + if (test_bit(0,&card->in_isr)) { + printk(KERN_INFO "%s:%s Pipemon command failed, Driver busy: try again.\n", + card->devname,dev->name); + atomic_set(&chan->udp_pkt_len,0); + spin_unlock_irqrestore(&card->wandev.lock, smp_flags); + return -EBUSY; + } + + process_udp_mgmt_pkt(card,dev,chan,1); + + spin_unlock_irqrestore(&card->wandev.lock, smp_flags); + + /* This area will still be critical to other + * PIPEMON commands due to udp_pkt_len + * thus we can release the irq */ + + if (atomic_read(&chan->udp_pkt_len) > sizeof(wan_udp_pkt_t)){ + printk(KERN_INFO "%s: Error: Pipemon buf too bit on the way up! %i\n", + card->devname,atomic_read(&chan->udp_pkt_len)); + atomic_set(&chan->udp_pkt_len,0); + return -EINVAL; + } + + if (copy_to_user(ifr->ifr_data,&wan_udp_pkt->wan_udp_hdr,sizeof(wan_udp_hdr_t))){ + atomic_set(&chan->udp_pkt_len,0); + return -EFAULT; + } + + atomic_set(&chan->udp_pkt_len,0); + return 0; + + + default: + return -EOPNOTSUPP; + } + return err; +} + + + +/*============================================================================= + * Store a UDP management packet for later processing. + */ + +static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, + struct sk_buff *skb, netdevice_t* dev, + chdlc_private_area_t* chdlc_priv_area ) +{ + int udp_pkt_stored = 0; + + if(!atomic_read(&chdlc_priv_area->udp_pkt_len) && + (skb->len <= MAX_LGTH_UDP_MGNT_PKT)) { + atomic_set(&chdlc_priv_area->udp_pkt_len, skb->len); + chdlc_priv_area->udp_pkt_src = udp_pkt_src; + memcpy(chdlc_priv_area->udp_pkt_data, skb->data, skb->len); + card->u.c.timer_int_enabled = TMR_INT_ENABLED_UDP; + udp_pkt_stored = 1; + } + + wan_skb_free(skb); + + return(udp_pkt_stored); +} + + +/*============================================================================= + * Process UDP management packet. + */ + +static int process_udp_mgmt_pkt(sdla_t* card, netdevice_t* dev, + chdlc_private_area_t* chdlc_priv_area, int local_dev ) +{ + unsigned char *buf; + unsigned int len; + struct sk_buff *new_skb; + int udp_mgmt_req_valid = 1; + SHARED_MEMORY_INFO_STRUCT flags; + wan_mbox_t *mb = &card->wan_mbox; + wan_udp_pkt_t *wan_udp_pkt; + struct timeval tv; + int err; + + wan_udp_pkt = (wan_udp_pkt_t *) chdlc_priv_area->udp_pkt_data; + + if (!local_dev){ + + if(chdlc_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK){ + + /* Only these commands are support for remote debugging. + * All others are not */ + switch(wan_udp_pkt->wan_udp_command) { + + case READ_GLOBAL_STATISTICS: + case READ_MODEM_STATUS: + case CPIPE_ROUTER_UP_TIME: + case READ_COMMS_ERROR_STATS: + case READ_ASY_OPERATIONAL_STATS: + /* These two commands are executed for + * each request */ + case READ_ASY_CONFIGURATION: + case READ_ASY_CODE_VERSION: + case WAN_GET_MEDIA_TYPE: + case WAN_FE_GET_CFG: + case WAN_FE_GET_STAT: + case WAN_GET_PROTOCOL: + case WAN_GET_PLATFORM: + udp_mgmt_req_valid = 1; + break; + default: + udp_mgmt_req_valid = 0; + break; + } + } + } + + if(!udp_mgmt_req_valid) { + + /* set length to 0 */ + wan_udp_pkt->wan_udp_data_len = 0; + + /* set return code */ + wan_udp_pkt->wan_udp_return_code = 0xCD; + + if (net_ratelimit()){ + printk(KERN_INFO + "%s: Warning, Illegal UDP command attempted from network: %x\n", + card->devname,wan_udp_pkt->wan_udp_command); + } + + } else { + wan_udp_pkt->wan_udp_opp_flag = 0; + + switch(wan_udp_pkt->wan_udp_command) { + + case CPIPE_FT1_READ_STATUS: + card->hw_iface.peek(card->hw, card->flags_off, &flags, sizeof(flags)); + ((unsigned char *)wan_udp_pkt->wan_udp_data )[0] = + flags.FT1_info_struct.parallel_port_A_input; + + ((unsigned char *)wan_udp_pkt->wan_udp_data )[1] = + flags.FT1_info_struct.parallel_port_B_input; + wan_udp_pkt->wan_udp_return_code = COMMAND_OK; + wan_udp_pkt->wan_udp_data_len = 2; + mb->wan_data_len = 2; + break; + + case CPIPE_ROUTER_UP_TIME: + do_gettimeofday( &tv ); + chdlc_priv_area->router_up_time = tv.tv_sec - + chdlc_priv_area->router_start_time; + *(unsigned long *)&wan_udp_pkt->wan_udp_data = + chdlc_priv_area->router_up_time; + mb->wan_data_len = sizeof(unsigned long); + wan_udp_pkt->wan_udp_data_len = sizeof(unsigned long); + wan_udp_pkt->wan_udp_return_code = COMMAND_OK; + break; + + case WAN_GET_MEDIA_TYPE: + case WAN_FE_GET_STAT: + case WAN_FE_SET_LB_MODE: + case WAN_FE_FLUSH_PMON: + case WAN_FE_GET_CFG: + if (IS_TE1_CARD(card)){ + card->wandev.fe_iface.process_udp( + &card->fe, + &wan_udp_pkt->wan_udp_cmd, + &wan_udp_pkt->wan_udp_data[0]); + }else if (IS_56K_CARD(card)){ + card->wandev.fe_iface.process_udp( + &card->fe, + &wan_udp_pkt->wan_udp_cmd, + &wan_udp_pkt->wan_udp_data[0]); + }else{ + if (wan_udp_pkt->wan_udp_command == WAN_GET_MEDIA_TYPE){ + wan_udp_pkt->wan_udp_data_len = sizeof(unsigned char); + wan_udp_pkt->wan_udp_return_code = CMD_OK; + }else{ + wan_udp_pkt->wan_udp_return_code = WAN_UDP_INVALID_CMD; + } + } + mb->wan_data_len = wan_udp_pkt->wan_udp_data_len; + break; + + case WAN_GET_PROTOCOL: + wan_udp_pkt->wan_udp_chdlc_num_frames = card->wandev.config_id; + wan_udp_pkt->wan_udp_return_code = CMD_OK; + mb->wan_data_len = wan_udp_pkt->wan_udp_data_len = 1; + break; + + case WAN_GET_PLATFORM: + wan_udp_pkt->wan_udp_data[0] = WAN_LINUX_PLATFORM; + wan_udp_pkt->wan_udp_return_code = CMD_OK; + mb->wan_data_len = wan_udp_pkt->wan_udp_data_len = 1; + break; + + default: + /* it's a board command */ + mb->wan_command = wan_udp_pkt->wan_udp_command; + mb->wan_data_len = wan_udp_pkt->wan_udp_data_len; + if (mb->wan_data_len) { + memcpy(&mb->wan_data, (unsigned char *) wan_udp_pkt-> + wan_udp_data, mb->wan_data_len); + } + + /* run the command on the board */ + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != COMMAND_OK) { + chdlc_error(card,err,mb); + wan_udp_pkt->wan_udp_return_code = mb->wan_return_code; + break; + } + + /* copy the result back to our buffer */ + memcpy(&wan_udp_pkt->wan_udp_hdr.wan_cmd, mb, sizeof(wan_cmd_t)); + + if (mb->wan_data_len) { + memcpy(&wan_udp_pkt->wan_udp_data, &mb->wan_data, + mb->wan_data_len); + } + + } /* end of switch */ + } /* end of else */ + + /* Fill UDP TTL */ + wan_udp_pkt->wan_ip_ttl= card->wandev.ttl; + + if (local_dev){ + wan_udp_pkt->wan_udp_request_reply = UDPMGMT_REPLY; + return 1; + } + + len = reply_udp(chdlc_priv_area->udp_pkt_data, mb->wan_data_len); + + if(chdlc_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK){ + + /* Must check if we interrupted if_send() routine. The + * tx buffers might be used. If so drop the packet */ + if (!test_bit(SEND_CRIT,&card->wandev.critical)) { + + if(!chdlc_send(card, chdlc_priv_area->udp_pkt_data, len, 0)) { + ++ card->wandev.stats.tx_packets; + card->wandev.stats.tx_bytes += len; + } + } + } else { + + /* Pass it up the stack + Allocate socket buffer */ + if ((new_skb = dev_alloc_skb(len)) != NULL) { + /* copy data into new_skb */ + + buf = skb_put(new_skb, len); + memcpy(buf, chdlc_priv_area->udp_pkt_data, len); + + /* Decapsulate pkt and pass it up the protocol stack */ + new_skb->protocol = htons(ETH_P_IP); + new_skb->dev = dev; + new_skb->mac.raw = new_skb->data; + + netif_rx(new_skb); + } else { + + printk(KERN_INFO "%s: no socket buffers available!\n", + card->devname); + } + } + + atomic_set(&chdlc_priv_area->udp_pkt_len,0); + + return 0; +} + +/*============================================================================ + * Initialize Receive and Transmit Buffers. + */ + +static void init_chdlc_tx_rx_buff( sdla_t* card) +{ + wan_mbox_t *mb = &card->wan_mbox; + unsigned long tx_config_off; + unsigned long rx_config_off; + ASY_TX_STATUS_EL_CFG_STRUCT tx_config; + ASY_RX_STATUS_EL_CFG_STRUCT rx_config; + char err; + + mb->wan_data_len = 0; + mb->wan_command = READ_ASY_CONFIGURATION; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + + if(err != COMMAND_OK) { + netdevice_t *dev; + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + if (dev){ + chdlc_error(card,err,mb); + } + return; + } + + /* ALEX: Apr 8 2004 SANGOMA ISA CARD */ + tx_config_off = + ((ASY_CONFIGURATION_STRUCT *)mb->wan_data)-> + ptr_asy_Tx_stat_el_cfg_struct; + rx_config_off = + ((ASY_CONFIGURATION_STRUCT *)mb->wan_data)-> + ptr_asy_Rx_stat_el_cfg_struct; + /* Setup Head and Tails for buffers */ + card->hw_iface.peek(card->hw, tx_config_off, &tx_config, sizeof(tx_config)); + card->u.c.txbuf_base_off = tx_config.base_addr_Tx_status_elements; + card->u.c.txbuf_last_off = + card->u.c.txbuf_base_off + + (tx_config.number_Tx_status_elements - 1) * + sizeof(ASY_DATA_TX_STATUS_EL_STRUCT); + card->hw_iface.peek(card->hw, rx_config_off, &rx_config, sizeof(rx_config)); + card->u.c.rxbuf_base_off = + rx_config.base_addr_Rx_status_elements; + card->u.c.rxbuf_last_off = + card->u.c.rxbuf_base_off + + (rx_config.number_Rx_status_elements - 1) * + sizeof(ASY_DATA_RX_STATUS_EL_STRUCT); + /* Set up next pointer to be used */ + card->u.c.txbuf_off = tx_config.next_Tx_status_element_to_use; + card->u.c.rxmb_off = + rx_config.next_Rx_status_element_to_use; + + /* Setup Actual Buffer Start and end addresses */ + card->u.c.rx_base_off = rx_config.base_addr_Rx_buffer; + card->u.c.rx_top_off = rx_config.end_addr_Rx_buffer; + +} + +/*============================================================================= + * Perform Interrupt Test by running READ_ASY_CODE_VERSION command MAX_INTR + * _TEST_COUNTER times. + */ +static int intr_test( sdla_t* card) +{ + wan_mbox_t* mb = &card->wan_mbox; + int err,i; + + card->timer_int_enabled = 0; + + err = chdlc_set_intr_mode(card, APP_INT_ON_COMMAND_COMPLETE); + + if (err == CMD_OK) { + for (i = 0; i < MAX_INTR_TEST_COUNTER; i ++) { + + mb->wan_data_len = 0; + mb->wan_command = READ_ASY_CODE_VERSION; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != CMD_OK) + chdlc_error(card, err, mb); + } + }else{ + return err; + } + +// udelay(2000); +// schedule(); +// udelay(2000); + + card->hw_iface.poke_byte(card->hw, card->intr_type_off, 0x00); + err = chdlc_set_intr_mode(card, 0); + + if (err != CMD_OK) + return err; + + return 0; +} + +/*============================================================================== + * Determine what type of UDP call it is. CPIPEAB ? + */ +static int udp_pkt_type(struct sk_buff *skb, sdla_t* card) +{ + wan_udp_pkt_t *wan_udp_pkt = (wan_udp_pkt_t *)skb->data; + + if (skb->len < sizeof(wan_udp_pkt_t)){ + return UDP_INVALID_TYPE; + } + +#ifdef _WAN_UDP_DEBUG + printk(KERN_INFO "SIG %s = %s\n\ + UPP %x = %x\n\ + PRT %x = %x\n\ + REQ %i = %i\n\ + 36 th = %x 37th = %x\n", + wan_udp_pkt->wan_udp_signature, + UDPMGMT_SIGNATURE, + wan_udp_pkt->wan_udp_dport, + ntohs(card->wandev.udp_port), + wan_udp_pkt->wan_ip_p, + UDPMGMT_UDP_PROTOCOL, + wan_udp_pkt->wan_udp_request_reply, + UDPMGMT_REQUEST, + skb->data[36], skb->data[37]); +#endif + + if ((wan_udp_pkt->wan_udp_dport == ntohs(card->wandev.udp_port)) && + (wan_udp_pkt->wan_ip_p == UDPMGMT_UDP_PROTOCOL) && + (wan_udp_pkt->wan_udp_request_reply == UDPMGMT_REQUEST)) { + if (!strncmp(wan_udp_pkt->wan_udp_signature,UDPMGMT_SIGNATURE,8)){ + return UDP_CPIPE_TYPE; + } + if (!strncmp(wan_udp_pkt->wan_udp_signature,GLOBAL_UDP_SIGNATURE,8)){ + return UDP_CPIPE_TYPE; + } + } + return UDP_INVALID_TYPE; +} + +/*============================================================================ + * Set PORT state. + */ +static void port_set_state (sdla_t *card, int state) +{ + netdevice_t *dev; + + if (card->wandev.state != state) + { + switch (state) + { + case WAN_CONNECTED: + printk (KERN_INFO "%s: Link connected!\n", + card->devname); + break; + + case WAN_CONNECTING: + printk (KERN_INFO "%s: Link connecting...\n", + card->devname); + break; + + case WAN_DISCONNECTED: + printk (KERN_INFO "%s: Link disconnected!\n", + card->devname); + break; + } + + card->wandev.state = state; + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + if (dev && wan_netif_priv(dev)){ + chdlc_private_area_t *chdlc_priv_area = wan_netif_priv(dev); + chdlc_priv_area->common.state = state; + if (chdlc_priv_area->common.usedby == API){ + wan_update_api_state(chdlc_priv_area); + } + } + } +} + +/*=========================================================================== + * config_chdlc + * + * Configure the chdlc protocol and enable communications. + * + * The if_open() function binds this function to the poll routine. + * Therefore, this function will run every time the chdlc interface + * is brought up. We cannot run this function from the if_open + * because if_open does not have access to the remote IP address. + * + * If the communications are not enabled, proceed to configure + * the card and enable communications. + * + * If the communications are enabled, it means that the interface + * was shutdown by ether the user or driver. In this case, we + * have to check that the IP addresses have not changed. If + * the IP addresses have changed, we have to reconfigure the firmware + * and update the changed IP addresses. Otherwise, just exit. + * + */ + +static int config_chdlc (sdla_t *card, netdevice_t *dev) +{ + if (card->u.c.comm_enabled){ + return 0; + } + + /* Setup the Board for asynchronous mode */ + if (set_asy_config(card)) { + printk (KERN_INFO "%s: Failed CHDLC Async configuration!\n", + card->devname); + return 0; + } + + card->hw_iface.poke_byte(card->hw, card->intr_type_off, 0x00); + card->hw_iface.poke_byte(card->hw, card->intr_perm_off, 0x00); + + if (IS_TE1_CARD(card)) { + int err = -EINVAL; + printk(KERN_INFO "%s: Configuring onboard %s CSU/DSU\n", + card->devname, + (IS_T1_CARD(card))?"T1":"E1"); + if (card->wandev.fe_iface.config){ + err = card->wandev.fe_iface.config(&card->fe); + } + if (err){ + printk(KERN_INFO "%s: Failed %s configuratoin!\n", + card->devname, + (IS_T1_CARD(card))?"T1":"E1"); + return -EINVAL; + } + } + + + if (IS_56K_CARD(card)) { + int err = -EINVAL; + printk(KERN_INFO "%s: Configuring 56K onboard CSU/DSU\n", + card->devname); + + if (card->wandev.fe_iface.config){ + err = card->wandev.fe_iface.config(&card->fe); + } + if (err){ + printk (KERN_INFO "%s: Failed 56K configuration!\n", + card->devname); + return -EINVAL; + } + } + + + /* Set interrupt mode and mask */ + if (chdlc_set_intr_mode(card, APP_INT_ON_RX_FRAME | + APP_INT_ON_GLOBAL_EXCEP_COND | + APP_INT_ON_TX | + APP_INT_ON_TIMER)){ + printk (KERN_INFO "%s: Failed to set interrupt triggers!\n", + card->devname); + return -EINVAL; + } + + /* Mask All interrupts */ + card->hw_iface.clear_bit(card->hw, card->intr_perm_off, + (APP_INT_ON_RX_FRAME | APP_INT_ON_TX | + APP_INT_ON_TIMER | APP_INT_ON_GLOBAL_EXCEP_COND)); + + + /* Enable communications */ + if (asy_comm_enable(card) != 0) { + printk(KERN_INFO "%s: Failed to enable async commnunication!\n", + card->devname); + card->hw_iface.poke_byte(card->hw, card->intr_perm_off, 0x00); + card->u.c.comm_enabled=0; + chdlc_set_intr_mode(card,0); + return -EINVAL; + } + + DEBUG_EVENT("%s: Communications enabled on startup\n", + card->devname); + + /* Initialize Rx/Tx buffer control fields */ + init_chdlc_tx_rx_buff(card); + port_set_state(card, WAN_CONNECTED); + + /* Manually poll the 56K CSU/DSU to get the status */ + if (IS_56K_CARD(card)) { + /* 56K Update CSU/DSU alarms */ + card->wandev.fe_iface.read_alarm(&card->fe, 1); + } + + /* Unmask all interrupts except the Transmit and Timer interrupts */ + card->hw_iface.set_bit(card->hw, card->intr_perm_off, + (APP_INT_ON_RX_FRAME | APP_INT_ON_GLOBAL_EXCEP_COND)); + card->hw_iface.poke_byte(card->hw, card->intr_type_off, 0x00); + return 0; +} + + +static int set_adapter_config (sdla_t* card) +{ +#if 0 + wan_mbox_t* mb = &card->wan_mbox; + ADAPTER_CONFIGURATION_STRUCT* cfg = (ADAPTER_CONFIGURATION_STRUCT*)mb->wan_data; + int err; + + card->hw_iface.getcfg(card->hw, SDLA_ADAPTERTYPE, &cfg->adapter_type); + cfg->adapter_config = 0x00; + cfg->operating_frequency = 00; + mb->wan_data_len = sizeof(ADAPTER_CONFIGURATION_STRUCT); + mb->wan_command = SET_ADAPTER_CONFIGURATION; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + + if(err != COMMAND_OK) { + chdlc_error(card,err,mb); + } + return (err); +#else + return 0; +#endif +} + + +void s508_lock (sdla_t *card, unsigned long *smp_flags) +{ + spin_lock_irqsave(&card->wandev.lock, *smp_flags); + if (card->next){ + spin_lock(&card->next->wandev.lock); + } +} + +void s508_unlock (sdla_t *card, unsigned long *smp_flags) +{ + if (card->next){ + spin_unlock(&card->next->wandev.lock); + } + spin_unlock_irqrestore(&card->wandev.lock, *smp_flags); +} + +/* + * ****************************************************************** + * Proc FS function + */ +#define PROC_CFG_FRM "%-15s| %-12s|\n" +#define PROC_STAT_FRM "%-15s| %-12s| %-14s|\n" +static char chdlc_config_hdr[] = + "Interface name | Device name |\n"; +static char chdlc_status_hdr[] = + "Interface name | Device name | Status |\n"; + +static int chdlc_get_config_info(void* priv, struct seq_file* m, int* stop_cnt) +{ + chdlc_private_area_t* chdlc_priv_area = priv; + sdla_t* card = NULL; + + if (chdlc_priv_area == NULL) + return m->count; + card = chdlc_priv_area->card; + + if ((m->from == 0 && m->count == 0) || (m->from && m->from == *stop_cnt)){ + PROC_ADD_LINE(m, + "%s", chdlc_config_hdr); + } + + PROC_ADD_LINE(m, + PROC_CFG_FRM, chdlc_priv_area->if_name, card->devname); + return m->count; +} + +static int chdlc_get_status_info(void* priv, struct seq_file* m, int* stop_cnt) +{ + chdlc_private_area_t* chdlc_priv_area = priv; + sdla_t* card = NULL; + + if (chdlc_priv_area == NULL) + return m->count; + card = chdlc_priv_area->card; + + if ((m->from == 0 && m->count == 0) || (m->from && m->from == *stop_cnt)){ + PROC_ADD_LINE(m, + "%s", chdlc_status_hdr); + } + + PROC_ADD_LINE(m, + PROC_STAT_FRM, + chdlc_priv_area->if_name, + card->devname, + STATE_DECODE(chdlc_priv_area->common.state)); + + return m->count; +} + +#define PROC_DEV_FR_S_FRM "%-20s| %-14s|\n" +#define PROC_DEV_FR_D_FRM "%-20s| %-14d|\n" +#define PROC_DEV_SEPARATE "=====================================\n" + + +static int chdlc_set_dev_config(struct file *file, + const char *buffer, + unsigned long count, + void *data) +{ + int cnt = 0; + wan_device_t* wandev = (void*)data; + sdla_t* card = NULL; + + if (wandev == NULL) + return cnt; + + card = (sdla_t*)wandev->private; + + printk(KERN_INFO "%s: New device config (%s)\n", + wandev->name, buffer); + /* Parse string */ + + return count; +} + + +#define PROC_IF_FR_S_FRM "%-30s\t%-14s\n" +#define PROC_IF_FR_D_FRM "%-30s\t%-14d\n" +#define PROC_IF_FR_L_FRM "%-30s\t%-14ld\n" +#define PROC_IF_SEPARATE "====================================================\n" + +static int chdlc_set_if_info(struct file *file, + const char *buffer, + unsigned long count, + void *data) +{ + netdevice_t* dev = (void*)data; + chdlc_private_area_t* chdlc_priv_area = NULL; + + if (dev == NULL || dev->priv == NULL) + return count; + + chdlc_priv_area = (chdlc_private_area_t*)dev->priv; + + + printk(KERN_INFO "%s: New interface config (%s)\n", + chdlc_priv_area->if_name, buffer); + /* Parse string */ + + return count; +} + +static void chdlc_handle_front_end_state(void* card_id) +{ + int rc; + sdla_t* card = (sdla_t*)card_id; + + if (card->wandev.ignore_front_end_status == WANOPT_YES){ + return; + } + + if (IS_TE1_CARD(card)){ + if (card->fe.fe_status == FE_CONNECTED) { + if(card->u.c.comm_enabled == 0) { + + rc=chdlc_comm_enable(card); + if (rc==0){ + init_chdlc_tx_rx_buff(card); + DEBUG_EVENT("%s: Communications enabled\n", + card->devname); + + port_set_state(card, WAN_CONNECTED); + }else{ + DEBUG_EVENT("%s: Critical Error: Failed to enable comms 0x%X\n", + card->devname,rc); + port_set_state(card, WAN_DISCONNECTED); + } + } + + }else{ + port_set_state(card, WAN_DISCONNECTED); + if (card->u.c.comm_enabled){ + printk(KERN_INFO "%s: Communications disabled\n", + card->devname); + chdlc_comm_disable (card); + } + } + + }else{ + if (card->fe.fe_status == FE_CONNECTED){ + if (card->u.c.state == WAN_CONNECTED){ + port_set_state(card,WAN_CONNECTED); + } + }else{ + port_set_state(card,WAN_DISCONNECTED); + } + } +} + + + +/****** End ****************************************************************/ diff -Nur linux.org/drivers/net/wan/sdla_atm.c linux-2.6.17/drivers/net/wan/sdla_atm.c --- linux.org/drivers/net/wan/sdla_atm.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/drivers/net/wan/sdla_atm.c 2006-08-30 10:07:16.000000000 +0000 @@ -0,0 +1,4134 @@ +/***************************************************************************** +* sdla_atm.c WANPIPE(tm) Multiprotocol WAN Link Driver. +* +* ATM ALL5 Driver +* +* Authors: Nenad Corbic +* +* Copyright: (c) 1995-2003 Sangoma Technologies Inc. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version +* 2 of the License, or (at your option) any later version. +* ============================================================================ +* Jul 13, 2004 David Rokhvarg Added Idle cell trace. +* Sep 12, 2003 Nenad Corbic Fixed the TE1 clock selection, the +* conf->interfaces must be hardcoded, before +* writting the value to the card structure. +* Jan 07, 2002 Nenad Corbic Initial version. +*****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include /* Socket Driver common area */ +#include + + +/****** Defines & Macros ****************************************************/ +#define MAX_TRACE_QUEUE 100 +#define MAX_TRACE_BUFFER (MAX_LGTH_UDP_MGNT_PKT - \ + sizeof(iphdr_t) - \ + sizeof(udphdr_t) - \ + sizeof(wan_mgmt_t) - \ + sizeof(wan_trace_info_t) - \ + sizeof(wan_cmd_t)) + +#define ATM_TIMER_TIMEOUT 1 +#define POLL_DELAY_TIMEOUT 1 + +/* Private critical flags */ +enum { + POLL_CRIT = PRIV_CRIT, + TX_INTR, + TASK_POLL +}; + +#define PORT(x) (x == 0 ? "PRIMARY" : "SECONDARY" ) +#define MAX_RX_BUF 50 + +/******Data Structures*****************************************************/ + +/* This structure is placed in the private data area of the device structure. + * The card structure used to occupy the private area but now the following + * structure will incorporate the card structure along with Protocol specific data + */ + +typedef struct private_area +{ + wanpipe_common_t common; + sdla_t *card; + + unsigned char encap_mode; + unsigned short vpi,vci; + netdevice_t *dev; + netskb_t *tx_cells_skb; + + int TracingEnabled; /* For enabling Tracing */ + + unsigned long router_start_time; + unsigned char route_status; + unsigned char route_removed; + unsigned long tick_counter; /* For 5s timeout counter */ + unsigned long router_up_time; + + unsigned char mc; /* Mulitcast support on/off */ + unsigned char udp_pkt_src; /* udp packet processing */ + unsigned short timer_int_enabled; + + unsigned long interface_down; + + /* Polling task queue. Each interface + * has its own task queue, which is used + * to defer events from the interrupt */ + wan_taskq_t poll_task; + + u8 gateway; + u8 true_if_encoding; + + //FIXME: add driver stats as per frame relay! + + /* Entry in proc fs per each interface */ + struct proc_dir_entry *dent; + + unsigned char udp_pkt_data[sizeof(wan_udp_pkt_t)+10]; + atomic_t udp_pkt_len; + + char if_name[WAN_IFNAME_SZ+1]; + struct net_device_stats if_stats; + + void *sar_pvc; + + wan_atm_conf_if_t cfg; + +}private_area_t; + +/* Route Status options */ +#define NO_ROUTE 0x00 +#define ADD_ROUTE 0x01 +#define ROUTE_ADDED 0x02 +#define REMOVE_ROUTE 0x03 + +/* keep the idle configuration */ +PHY_CONFIGURATION_STRUCT phy_idle_cfg; + +/* variable for keeping track of enabling/disabling FT1 monitor status */ +static int rCount; +static int Intr_test_counter; + +extern void disable_irq(unsigned int); +extern void enable_irq(unsigned int); + +/**SECTOIN************************************************** + * + * Function Prototypes + * + ***********************************************************/ + +/* WAN link driver entry points. These are called by the WAN router module. */ +static int update (wan_device_t* wandev); +static int new_if (wan_device_t* wandev, struct net_device* dev, wanif_conf_t* conf); +static int del_if(wan_device_t *wandev, struct net_device *dev); + +/* Network device interface */ +static int if_init (struct net_device* dev); +static int if_open (struct net_device* dev); +static int if_close (struct net_device* dev); +static int if_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); + +static struct net_device_stats* if_stats (struct net_device* dev); + +static int if_send (netskb_t* skb, struct net_device* dev); + +/* Firmware interface functions */ +static int frmw_configure (sdla_t* card, void* data); +static int frmw_comm_enable (sdla_t* card); +static int frmw_read_version (sdla_t* card, char* str); +static int frmw_set_intr_mode (sdla_t* card, unsigned mode); +static int set_adapter_config (sdla_t* card); +static int frmw_send (sdla_t* card, void* data, unsigned len, unsigned char tx_bits); +static int frmw_read_comm_err_stats (sdla_t* card); +static int frmw_read_op_stats (sdla_t* card); +static int frmw_error (sdla_t *card, int err, wan_mbox_t *mb); +static void enable_timer(void* card_id); +static int disable_comm_shutdown (sdla_t *card); +static int init_interrupt_status_ptrs(sdla_t *card); +static void if_tx_timeout (struct net_device *dev); + +/* Miscellaneous Functions */ +static int set_frmw_config (sdla_t* card); +static void init_tx_rx_buff( sdla_t* card); +static int process_exception(sdla_t *card); +static int process_global_exception(sdla_t *card); +static int update_comms_stats(sdla_t* card,private_area_t*); +static void port_set_state (sdla_t *card, int); + +static int config_frmw (sdla_t *card); +static void disable_comm (sdla_t *card); + +static void trigger_poll (struct net_device *); +static void frmw_poll (void *); + +/* Interrupt handlers */ +static void wpatm_isr (sdla_t* card); +static void rx_intr (sdla_t* card); +static void tx_intr (sdla_t* card); +static void timer_intr(sdla_t *); + +/* Bottom half handlers */ +static void wp_bh (unsigned long data); + +/* Miscellaneous functions */ +static int chk_bcast_mcast_addr(sdla_t* card, struct net_device* dev, + netskb_t *skb); +//static int reply_udp( unsigned char *data, unsigned int mbox_len ); +static int intr_test( sdla_t* card); +static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, + netskb_t *skb, struct net_device* dev, + private_area_t*); +static int process_udp_mgmt_pkt(sdla_t* card, struct net_device* dev, + private_area_t*, + int local_dev); + +static void s508_lock (sdla_t *card, unsigned long *smp_flags); +static void s508_unlock (sdla_t *card, unsigned long *smp_flags); + +static void wp_handle_rx_packets(netskb_t *skb); +static int wp_handle_tx_packets(sdla_t* card, netskb_t *skb); +static int wp_handle_out_of_sync_condition(sdla_t *card,unsigned char irq); + +static int +capture_atm_trace_packet(wan_trace_t *trace_info, void *data, int len, char direction); + +#ifdef WANPIPE_ENABLE_PROC_FILE_HOOKS +# warning "Enabling Proc File System Hooks" +static int get_config_info(void* priv, char* buf, int cnt, int, int, int*); +static int get_status_info(void* priv, char* buf, int cnt, int, int, int*); +#if defined(LINUX_2_4)||defined(LINUX_2_6) +static int get_dev_config_info(char* buf, char** start, off_t offs, int len); +static int get_if_info(char* buf, char** start, off_t offs, int len); +# else +static int get_dev_config_info(char* buf, char** start, off_t offs, int len, int dummy); +static int get_if_info(char* buf, char** start, off_t offs, int len, int dummy); +# endif +static int set_dev_config(struct file*, const char*, unsigned long, void *); +static int set_if_info(struct file*, const char*, unsigned long, void *); +#endif + +static void atm_timer_poll(unsigned long data); + +static netdevice_t* move_dev_to_next (sdla_t *card, netdevice_t *dev); + +/* Procfs functions */ +static int wan_atm_get_info(void* pcard, struct seq_file* m, int* stop_cnt); + +/* TE1 Control registers */ +static WRITE_FRONT_END_REG_T write_front_end_reg; +static READ_FRONT_END_REG_T read_front_end_reg; +static void handle_front_end_state(void* card_id); + + +/**SECTION********************************************************* + * + * Public Functions + * + ******************************************************************/ + + +/*============================================================================ + * wpatm_init - Cisco HDLC protocol initialization routine. + * + * @card: Wanpipe card pointer + * @conf: User hardware/firmware/general protocol configuration + * pointer. + * + * This routine is called by the main WANPIPE module + * during setup: ROUTER_SETUP ioctl(). + * + * At this point adapter is completely initialized + * and firmware is running. + * o read firmware version (to make sure it's alive) + * o configure adapter + * o initialize protocol-specific fields of the adapter data space. + * + * Return: 0 o.k. + * < 0 failure. + */ + +int wp_atm_init (sdla_t* card, wandev_conf_t* conf) +{ + int err,i; + + union{ + char str[80]; + } u; + volatile wan_mbox_t* mb; + unsigned long timeout; + netskb_t *skb; + + /* Initialize the disable_comm function + * because we don't want upper layers to + * call dislabe_comm incase we fail + * initializetion */ + + card->disable_comm = NULL; + + /* Verify configuration ID */ + if (conf->config_id != WANCONFIG_ATM) { + DEBUG_EVENT( "%s: invalid configuration ID %u!\n", + card->devname, conf->config_id); + return -EINVAL; + } + + /* Initialize the card mailbox and obtain the mailbox pointer */ + /* Set a pointer to the actual mailbox in the allocated virtual + * memory area */ + /* Alex Apr 8 2004 Sangom ISA card */ + card->mbox_off = PRI_BASE_ADDR_MB_STRUCT; + mb = &card->wan_mbox; + + if (!card->configured){ + unsigned char return_code = 0x00; + + /* The board will place an 'I' in the return + * code to indicate that it is ready to accept + * commands. We expect this to be completed + * in less than 1 second. */ + + timeout = jiffies; + do { + return_code = 0x00; + card->hw_iface.peek(card->hw, + card->mbox_off+offsetof(wan_mbox_t, wan_return_code), + &return_code, + sizeof(unsigned char)); + if ((jiffies - timeout) > 1*HZ) break; + }while(return_code != 'I'); + if (return_code != 'I') { + DEBUG_EVENT( + "%s: Initialization not completed by adapter\n", + card->devname); + DEBUG_EVENT( "Please contact Sangoma representative.\n"); + return -EIO; + } + } + + + memcpy(&card->u.atm.atm_cfg,&conf->u.atm,sizeof(wan_atm_conf_t)); + + wan_atomic_set(&card->wandev.if_cnt,0); + + err = (card->hw_iface.check_mismatch) ? + card->hw_iface.check_mismatch(card->hw,conf->fe_cfg.media) : -EINVAL; + if (err){ + return err; + } + + /* TE1 Make special hardware initialization for T1/E1 board */ + if (IS_TE1_MEDIA(&conf->fe_cfg)){ + + memcpy(&card->fe.fe_cfg, &conf->fe_cfg, sizeof(sdla_fe_cfg_t)); + sdla_te_iface_init(&card->wandev.fe_iface); + card->fe.name = card->devname; + card->fe.card = card; + card->fe.write_fe_reg = write_front_end_reg; + card->fe.read_fe_reg = read_front_end_reg; + + card->wandev.fe_enable_timer = enable_timer; + card->wandev.te_link_state = handle_front_end_state; + conf->interface = + (IS_T1_CARD(card)) ? WANOPT_V35 : WANOPT_RS232; + + if (card->wandev.comm_port == WANOPT_PRI){ + conf->clocking = WANOPT_EXTERNAL; + } + + }else if (IS_56K_MEDIA(&conf->fe_cfg)){ + + memcpy(&card->fe.fe_cfg, &conf->fe_cfg, sizeof(sdla_fe_cfg_t)); + sdla_56k_iface_init(&card->wandev.fe_iface); + card->fe.name = card->devname; + card->fe.card = card; + card->fe.write_fe_reg = write_front_end_reg; + card->fe.read_fe_reg = read_front_end_reg; + + if (card->wandev.comm_port == WANOPT_PRI){ + conf->clocking = WANOPT_EXTERNAL; + } + + }else{ + card->fe.fe_status = FE_CONNECTED; + } + + if (card->wandev.ignore_front_end_status == WANOPT_NO){ + DEBUG_EVENT( + "%s: Enabling front end link monitor\n", + card->devname); + }else{ + DEBUG_EVENT( + "%s: Disabling front end link monitor\n", + card->devname); + } + + + /* Obtain hardware configuration parameters */ + card->wandev.clocking = conf->clocking; + card->wandev.ignore_front_end_status = conf->ignore_front_end_status; + card->wandev.ttl = conf->ttl; + card->wandev.interface = conf->interface; + card->wandev.comm_port = conf->comm_port; + card->wandev.udp_port = conf->udp_port; + card->wandev.new_if_cnt = 0; + + + /* Read firmware version. Note that when adapter initializes, it + * clears the mailbox, so it may appear that the first command was + * executed successfully when in fact it was merely erased. To work + * around this, we execute the first command twice. + */ + + if (frmw_read_version(card, u.str)) + return -EIO; + + + DEBUG_EVENT( "%s: Running ATM firmware v%s\n", + card->devname, u.str); + + if (set_adapter_config(card)) { + return -EIO; + } + + card->isr = &wpatm_isr; + card->wandev.update = &update; + card->wandev.new_if = &new_if; + card->wandev.del_if = &del_if; + +#ifdef WANPIPE_ENABLE_PROC_FILE_HOOKS + /* Proc fs functions hooks */ + card->wandev.get_config_info = &get_config_info; + card->wandev.get_status_info = &get_status_info; + card->wandev.get_dev_config_info= &get_dev_config_info; + card->wandev.get_if_info = &get_if_info; + card->wandev.set_dev_config = &set_dev_config; + card->wandev.set_if_info = &set_if_info; +#endif + card->wandev.get_info = &wan_atm_get_info; + + + /* Setup Port Bps */ + if(card->wandev.clocking) { + + if(card->type == SDLA_S514){ + card->wandev.bps = wp_min(conf->bps,PHY_MAX_BAUD_RATE_S514); + }else{ + card->wandev.bps = wp_min(conf->bps,PHY_MAX_BAUD_RATE_S508); + } + + DEBUG_EVENT ("%s: Configuring Baud rate to %i bps\n", + card->devname,card->wandev.bps); + }else{ + card->wandev.bps = 0; + } + + + /* Setup the Port MTU */ + if((card->wandev.comm_port == WANOPT_PRI)) { + /* For Primary Port 0 */ + if (conf->mtu < MIN_WP_PRI_MTU){ + DEBUG_EVENT("%s: Warning: Limiting MTU to Min=%i\n", + card->devname,MIN_WP_PRI_MTU); + conf->mtu=MIN_WP_PRI_MTU; + }else if (conf->mtu > MAX_WP_PRI_MTU){ + DEBUG_EVENT("%s: Warning: Limiting MTU to Max=%i\n", + card->devname,MIN_WP_PRI_MTU); + conf->mtu=MAX_WP_PRI_MTU; + }else{ + DEBUG_EVENT("%s: Warning: Limiting MTU to Max=%i\n", + card->devname,MIN_WP_PRI_MTU); + } + card->wandev.mtu = conf->mtu; + } + + if ((err=init_interrupt_status_ptrs(card)) != COMMAND_OK){ + return err; + } + + card->intr_type_off = + card->flags_off + + offsetof(SHARED_MEMORY_INFO_STRUCT, interrupt_info_struct) + + offsetof(INTERRUPT_INFORMATION_STRUCT, interrupt_type); + card->intr_perm_off = + card->flags_off + + offsetof(SHARED_MEMORY_INFO_STRUCT, interrupt_info_struct) + + offsetof(INTERRUPT_INFORMATION_STRUCT, interrupt_permission); + card->fe_status_off = + card->flags_off + + offsetof(SHARED_MEMORY_INFO_STRUCT, FE_info_struct) + + offsetof(FE_INFORMATION_STRUCT, parallel_port_A_input); + card->wandev.state = WAN_DISCONNECTED; + + if (!card->wandev.piggyback){ + int err; + + /* Perform interrupt testing */ + err = intr_test(card); + + if(err || (Intr_test_counter < MAX_INTR_TEST_COUNTER)) { + DEBUG_EVENT( "%s: Interrupt test failed (%i)\n", + card->devname, Intr_test_counter); + DEBUG_EVENT( "%s: Please choose another interrupt\n", + card->devname); + + card->wandev.state = WAN_UNCONFIGURED; + return -EIO; + } + + DEBUG_EVENT( "%s: Interrupt test passed (%i)\n", + card->devname, Intr_test_counter); + card->configured = 1; + } + + if (frmw_set_intr_mode(card, APP_INT_ON_TIMER)){ + DEBUG_EVENT( "%s: Failed to set interrupt triggers!\n", + card->devname); + card->wandev.state = WAN_UNCONFIGURED; + return -EIO; + } + + card->u.atm.trace_info = wan_malloc(sizeof(wan_trace_t)); + if (!card->u.atm.trace_info){ + card->wandev.state = WAN_UNCONFIGURED; + return -ENOMEM; + } + + wan_trace_info_init(card->u.atm.trace_info,MAX_TRACE_QUEUE); + + skb_queue_head_init(&card->u.atm.wp_rx_free_list); + skb_queue_head_init(&card->u.atm.wp_rx_used_list); + skb_queue_head_init(&card->u.atm.wp_rx_data_list); + skb_queue_head_init(&card->u.atm.wp_tx_prot_list); + + err=wp_sar_register_device(card, + card->devname, + &card->u.atm.atm_device, + &card->u.atm.wp_rx_data_list, + &card->u.atm.wp_tx_prot_list, + card->u.atm.trace_info); + if (err){ + wan_free(card->u.atm.trace_info); + card->wandev.state = WAN_UNCONFIGURED; + return -EINVAL; + } + + /* Initialize the receive bh handler, that + * will be used to run the ATM SAR for rx packets */ + WAN_TASKLET_INIT(((wan_tasklet_t*)&card->u.atm.wanpipe_rx_task), + 0, wp_bh, (unsigned long)card); + + wan_init_timer(&card->u.atm.atm_timer,atm_timer_poll,(unsigned long)card); + + for (i=0;iu.atm.wp_rx_free_list)) != NULL){ + wan_skb_free(skb); + } + + wp_sar_unregister_device(card->u.atm.atm_device); + card->u.atm.atm_device=NULL; + wan_free(card->u.atm.trace_info); + card->u.atm.trace_info=NULL; + card->wandev.state = WAN_UNCONFIGURED; + return -ENOMEM; + } + wan_skb_queue_tail(&card->u.atm.wp_rx_free_list,skb); + } + + /* Mask the Timer interrupt */ + card->hw_iface.clear_bit(card->hw, card->intr_perm_off, APP_INT_ON_TIMER); + + /* If we are using backup mode, this flag will + * indicate not to look for IP addresses in config_frmw()*/ + card->backup = conf->backup; + + + /* Set protocol link state to disconnected, + * After seting the state to DISCONNECTED this + * function must return 0 i.e. success */ + card->u.atm.state = WAN_DISCONNECTED; + + /* Now it is save to call disable_comm, because + * all structures have been initialized */ + card->disable_comm = &disable_comm; + + DEBUG_EVENT( "\n"); + return 0; +} + +static void atm_timer_poll(unsigned long data) +{ + struct wan_dev_le *devle; + sdla_t *card = (sdla_t *)data; + netdevice_t *dev; + private_area_t *chan; + int err; + + if (wan_test_bit(PERI_CRIT,&card->wandev.critical)){ + DEBUG_EVENT ("%s: ATM Poll Timer exiting due to PERI CRIT\n", + card->devname); + return; + } + + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + if (!wan_atomic_read(&card->wandev.if_cnt) || !dev){ + DEBUG_EVENT ("%s: ATM Poll Timer exiting due to no if\n", + card->devname); + return; + } + + if (card->wandev.state != WAN_CONNECTED){ + goto atm_timer_poll_exit; + } + + WAN_LIST_FOREACH(devle, &card->wandev.dev_head, dev_link){ + dev = WAN_DEVLE2DEV(devle); + if (!dev || !wan_netif_priv(dev)) continue; + + if (!wan_netif_up(dev)){ + continue; + } + + chan = wan_netif_priv(dev); + if (!(chan->sar_pvc)){ + continue; + } + + err=wanpipe_sar_poll(chan->sar_pvc, ATM_TIMER_TIMEOUT); + if (!err){ + card->hw_iface.set_bit(card->hw, card->intr_perm_off, APP_INT_ON_TX_FRAME); + } + } + +atm_timer_poll_exit: + wan_add_timer(&card->u.atm.atm_timer, ATM_TIMER_TIMEOUT*HZ); + return; +} + + +/**SECTION************************************************************** + * + * WANPIPE Device Driver Entry Points + * + * *********************************************************************/ + + + +/*============================================================================ + * update - Update wanpipe device status & statistics + * + * @wandev: Wanpipe device pointer + * + * This procedure is called when updating the PROC file system. + * It returns various communications statistics. + * + * cat /proc/net/wanrouter/wanpipe# (where #=1,2,3...) + * + * These statistics are accumulated from 3 + * different locations: + * 1) The 'if_stats' recorded for the device. + * 2) Communication error statistics on the adapter. + * 3) Operational statistics on the adapter. + * + * The board level statistics are read during a timer interrupt. + * Note that we read the error and operational statistics + * during consecitive timer ticks so as to minimize the time + * that we are inside the interrupt handler. + * + */ +static int update (wan_device_t* wandev) +{ + sdla_t* card = wandev->private; + struct net_device* dev; + volatile private_area_t* priv_area; + unsigned long timeout; + + /* sanity checks */ + if((wandev == NULL) || (wandev->private == NULL)) + return -EFAULT; + + if(wandev->state == WAN_UNCONFIGURED) + return -ENODEV; + + /* more sanity checks */ + if(!card->flags_off) + return -ENODEV; + + if(wan_test_bit(PERI_CRIT, (void*)&card->wandev.critical)) + return -EAGAIN; + + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + if(dev == NULL) + return -ENODEV; + + if((priv_area=dev->priv) == NULL) + return -ENODEV; + + + if(card->update_comms_stats){ + return -EAGAIN; + } + + /* TE1 Change the update_comms_stats variable to 3, + * only for T1/E1 card, otherwise 2 for regular + * S514/S508 card. + * Each timer interrupt will update only one type + * of statistics. + */ + card->update_comms_stats = (IS_TE1_CARD(card) || IS_56K_CARD(card)) ? 3 : 2; + card->hw_iface.set_bit(card->hw, card->intr_perm_off, APP_INT_ON_TIMER); + card->timer_int_enabled = TMR_INT_ENABLED_UPDATE; + + /* wait a maximum of 1 second for the statistics to be updated */ + timeout = jiffies; + for(;;) { + if(card->update_comms_stats == 0) + break; + + if ((jiffies - timeout) > (1 * HZ)){ + card->update_comms_stats = 0; + card->timer_int_enabled &= + ~TMR_INT_ENABLED_UPDATE; + return -EAGAIN; + } + } + + return 0; +} + + +/*============================================================================ + * new_if - Create new logical channel. + * + * &wandev: Wanpipe device pointer + * &dev: Network device pointer + * &conf: User configuration options pointer + * + * This routine is called by the ROUTER_IFNEW ioctl, + * in wanmain.c. The ioctl passes us the user configuration + * options which we use to configure the driver and + * firmware. + * + * This functions main purpose is to allocate the + * private structure for protocol and bind it + * to dev->priv pointer. + * + * Also the dev->init pointer should also be initialized + * to the if_init() function. + * + * Any allocation necessary for the private strucutre + * should be done here, as well as proc/ file initializetion + * for the network interface. + * + * o parse media- and hardware-specific configuration + * o make sure that a new channel can be created + * o allocate resources, if necessary + * o prepare network device structure for registaration. + * o add network interface to the /proc/net/wanrouter + * + * The opposite of this function is del_if() + * + * Return: 0 o.k. + * < 0 failure (channel will not be created) + */ +static int new_if (wan_device_t* wandev, struct net_device* dev, wanif_conf_t* conf) +{ + sdla_t* card = wandev->private; + private_area_t* priv_area; + int err = 0; + + if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) { + DEBUG_EVENT( "%s: Error: Invalid interface name!\n", + card->devname); + return -EINVAL; + } + + DEBUG_EVENT( "%s: Configuring Interface: %s\n", + card->devname, conf->name); + + + /* allocate and initialize private data */ + priv_area = wan_malloc(sizeof(private_area_t)); + if(priv_area == NULL){ + WAN_MEM_ASSERT(card->devname); + return -ENOMEM; + } + memset(priv_area, 0, sizeof(private_area_t)); + + strncpy(priv_area->if_name, conf->name, WAN_IFNAME_SZ); + + memcpy(&priv_area->cfg, &conf->u.atm, sizeof(wan_atm_conf_if_t)); + + priv_area->card = card; + priv_area->dev = dev; + + /* Initialize the socket binding information + * These hooks are used by the API sockets to + * bind into the network interface */ + priv_area->common.sk = NULL; + priv_area->common.state = WAN_CONNECTING; + + priv_area->TracingEnabled = 0; + priv_area->route_status = NO_ROUTE; + priv_area->route_removed = 0; + + /* Setup interface as: + * WANPIPE = IP over Protocol (Firmware) + * API = Raw Socket access to Protocol (Firmware) + * BRIDGE = Ethernet over Protocol, no ip info + * BRIDGE_NODE = Ethernet over Protocol, with ip info + */ + if(strcmp(conf->usedby, "WANPIPE") == 0) { + + DEBUG_EVENT( "%s:%s: Running in WANPIPE mode!\n", + wandev->name,conf->name); + priv_area->common.usedby = WANPIPE; + + /* Option to bring down the interface when + * the link goes down */ + if (conf->if_down){ + wan_set_bit(DYN_OPT_ON,&priv_area->interface_down); + DEBUG_EVENT( + "%s:%s: Dynamic interface configuration enabled\n", + card->devname,priv_area->if_name); + } + + }else if( strcmp(conf->usedby, "API") == 0) { + priv_area->common.usedby = API; + DEBUG_EVENT( "%s:%s: Running in API mode !\n", + wandev->name,priv_area->if_name); + + }else if (strcmp(conf->usedby, "BRIDGE") == 0) { + priv_area->common.usedby = BRIDGE; + DEBUG_EVENT( "%s:%s: Running in WANPIPE (BRIDGE) mode.\n", + card->devname,priv_area->if_name); + + }else if (strcmp(conf->usedby, "BRIDGE_N") == 0) { + priv_area->common.usedby = BRIDGE_NODE; + DEBUG_EVENT( "%s:%s: Running in WANPIPE (BRIDGE_NODE) mode.\n", + card->devname,priv_area->if_name); + + }else{ + DEBUG_EVENT( "%s:%s: Error: Invalid operation mode [WANPIPE|API|BRIDGE|BRIDGE_NODE]\n", + card->devname,priv_area->if_name); + err=-EINVAL; + goto new_if_error; + } + + + DEBUG_EVENT("%s:%s: Configuring ATM Encap=%d, Vpi=%d, Vci=%d\n", + card->devname,priv_area->if_name, + priv_area->cfg.encap_mode, + priv_area->cfg.vpi, + priv_area->cfg.vci); + + err=wp_sar_register_pvc(card->u.atm.atm_device, + &priv_area->sar_pvc, + (void **)&priv_area->tx_cells_skb, + priv_area, + priv_area->if_name, + dev, + &priv_area->cfg, + card->wandev.mtu); + if (err){ + err=-EBUSY; + goto new_if_error; + } + + /* If gateway option is set, then this interface is the + * default gateway on this system. We must know that information + * in case DYNAMIC interface configuration is enabled. + * + * I.E. If the interface is brought down by the driver, the + * default route will also be removed. Once the interface + * is brought back up, we must know to re-astablish the + * default route. + */ + if ((priv_area->gateway = conf->gateway) == WANOPT_YES){ + DEBUG_EVENT( "%s:%s: Interface is set as a gateway.\n", + card->devname,priv_area->if_name); + } + + /* Get Multicast Information from the user + * FIXME: This option is not clearly defined + */ + priv_area->mc = conf->mc; + + + /* The network interface "dev" has been passed as + * an argument from the above layer. We must initialize + * it so it can be registered into the kernel. + * + * The "dev" structure is the link between the kernel + * stack and the wanpipe driver. It contains all + * access hooks that kernel uses to communicate to + * the our driver. + * + * For now, just set the "dev" name to the user + * defined name and initialize: + * dev->if_init : function that will be called + * to further initialize + * dev structure on "ifconfig up" + * + * dev->priv : private structure allocated above + * + */ + + /* Initialize the polling task routine + * used to defer tasks from interrupt context. + * Also it is used to implement dynamic + * interface configuration i.e. bringing interfaces + * up and down. + */ + + WAN_TASKQ_INIT((&priv_area->poll_task),0,frmw_poll,dev); + +#if 0 + /* Create interface file in proc fs. + * Once the proc file system is created, the new_if() function + * should exit successfuly. + * + * DO NOT place code under this function that can return + * anything else but 0. + */ + err = wanrouter_proc_add_interface(wandev, + &priv_area->dent, + priv_area->if_name, + dev); + if (err){ + DEBUG_EVENT( + "%s: Failed to create /proc/net/router/frmw/%s entry!\n", + card->devname, priv_area->if_name); + goto new_if_error; + } +#endif + + /* Only setup the dev pointer once the new_if function has + * finished successfully. DO NOT place any code below that + * can return an error */ + dev->init = &if_init; + dev->priv = priv_area; + + /* Increment the number of network interfaces + * configured on this card. + */ + wan_atomic_inc(&card->wandev.if_cnt); + + return 0; + +new_if_error: + + if (priv_area->sar_pvc){ + wp_sar_unregister_pvc(card->u.atm.atm_device, + priv_area->sar_pvc, + priv_area->tx_cells_skb); + priv_area->sar_pvc=NULL; + priv_area->tx_cells_skb=NULL; + } + + wan_free(priv_area); + + dev->priv=NULL; + + return err; +} + +/*============================================================================ + * del_if - Delete logical channel. + * + * @wandev: Wanpipe private device pointer + * @dev: Netowrk interface pointer + * + * This function is called by ROUTER_DELIF ioctl call + * to deallocate the network interface. + * + * The network interface and the private structure are + * about to be deallocated by the upper layer. + * We have to clean and deallocate any allocated memory. + * + * NOTE: DO NOT deallocate dev->priv here! It will be + * done by the upper layer. + * + */ +static int del_if (wan_device_t* wandev, struct net_device* dev) +{ + private_area_t* priv_area = dev->priv; + sdla_t* card = wandev->private; + unsigned long flags; + + wan_atomic_dec(&card->wandev.if_cnt); + + wan_spin_lock_irq(&card->wandev.lock,&flags); + + card->u.atm.tx_dev=NULL; + + if (priv_area->sar_pvc){ + wp_sar_unregister_pvc(card->u.atm.atm_device, + priv_area->sar_pvc, + priv_area->tx_cells_skb); + + priv_area->sar_pvc=NULL; + priv_area->tx_cells_skb=NULL; + } + wan_spin_unlock_irq(&card->wandev.lock,&flags); + +#if 0 + /* Delete interface name from proc fs. */ + wanrouter_proc_delete_interface(wandev, priv_area->if_name); +#endif + + /* Decrement the number of network interfaces + * configured on this card. + */ + if (wan_atomic_read(&card->wandev.if_cnt) <= 0){ + wan_del_timer(&card->u.atm.atm_timer); + } + + DEBUG_SUB_MEM(sizeof(private_area_t)); + return 0; +} + + +/**SECTION*********************************************************** + * + * KERNEL Device Entry Interfaces + * + ********************************************************************/ + + + +/*============================================================================ + * if_init - Initialize Linux network interface. + * + * @dev: Network interface pointer + * + * During "ifconfig up" the upper layer calls this function + * to initialize dev access pointers. Such as transmit, + * stats and header. + * + * It is called only once for each interface, + * during Linux network interface registration. + * + * Returning anything but zero will fail interface + * registration. + */ +static int if_init (struct net_device* dev) +{ + private_area_t* priv_area = dev->priv; + sdla_t* card = priv_area->card; + wan_device_t* wandev = &card->wandev; + + /* Initialize device driver entry points */ + dev->open = &if_open; + dev->stop = &if_close; + dev->hard_header = NULL; + dev->rebuild_header = NULL; + dev->hard_start_xmit = &if_send; + dev->get_stats = &if_stats; +#if defined(LINUX_2_4)||defined(LINUX_2_6) + dev->tx_timeout = &if_tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; +#endif + dev->do_ioctl = if_do_ioctl; + + if (priv_area->cfg.encap_mode == RFC_MODE_BRIDGED_ETH_LLC || + priv_area->cfg.encap_mode == RFC_MODE_BRIDGED_ETH_VC){ + + /* Setup the interface for Bridging */ + int hw_addr=0; + ether_setup(dev); + + /* Use a random number to generate the MAC address */ + memcpy(dev->dev_addr, "\xFE\xFC\x00\x00\x00\x00", 6); + get_random_bytes(&hw_addr, sizeof(hw_addr)); + *(int *)(dev->dev_addr + 2) += hw_addr; + + }else{ + /* Initialize media-specific parameters */ + dev->flags |= IFF_POINTOPOINT; + dev->flags |= IFF_NOARP; + + /* Enable Mulitcasting if user selected */ + if (priv_area->mc == WANOPT_YES){ + dev->flags |= IFF_MULTICAST; + } + + if (priv_area->true_if_encoding){ + dev->type = ARPHRD_HDLC; /* This breaks the tcpdump */ + }else{ + dev->type = ARPHRD_PPP; + } + + dev->mtu = card->wandev.mtu; + + dev->hard_header_len = 0; + dev->tx_queue_len = 100; + } + + /* Initialize hardware parameters */ + dev->irq = wandev->irq; + dev->dma = wandev->dma; + dev->base_addr = wandev->ioport; + card->hw_iface.getcfg(card->hw, SDLA_MEMBASE, &dev->mem_start); + card->hw_iface.getcfg(card->hw, SDLA_MEMEND, &dev->mem_end); + + return 0; +} + +/*============================================================================ + * if_open - Open network interface. + * + * @dev: Network device pointer + * + * On ifconfig up, this function gets called in order + * to initialize and configure the private area. + * Driver should be configured to send and receive data. + * + * This functions starts a timer that will call + * frmw_config() function. This function must be called + * because the IP addresses could have been changed + * for this interface. + * + * Return 0 if O.k. or errno. + */ +static int if_open (struct net_device* dev) +{ + private_area_t* priv_area = dev->priv; + sdla_t* card = priv_area->card; + struct timeval tv; + int err = 0; + + /* Only one open per interface is allowed */ + if (open_dev_check(dev)) + return -EBUSY; + + /* Initialize the router start time. + * Used by wanpipemon debugger to indicate + * how long has the interface been up */ + do_gettimeofday(&tv); + priv_area->router_start_time = tv.tv_sec; + + netif_start_queue(dev); + + /* Increment the module usage count */ + wanpipe_open(card); + + priv_area->common.state=WAN_CONNECTED; + + if (card->open_cnt == 1){ + wan_add_timer(&card->u.atm.atm_timer,ATM_TIMER_TIMEOUT*HZ); + } + + if (!card->comm_enabled){ + card->timer_int_enabled |= TMR_INT_ENABLED_CONFIG; + card->hw_iface.set_bit(card->hw, card->intr_perm_off, APP_INT_ON_TIMER); + } + + return err; +} + +/*============================================================================ + * if_close - Close network interface. + * + * @dev: Network device pointer + * + * On ifconfig down, this function gets called in order + * to cleanup interace private area. + * + * IMPORTANT: + * + * No deallocation or unconfiguration should ever occur in this + * function, because the interface can come back up + * (via ifconfig up). + * + * Furthermore, in dynamic interfacace configuration mode, the + * interface will come up and down to reflect the protocol state. + * + * Any deallocation and cleanup can occur in del_if() + * function. That function is called before the dev interface + * itself is deallocated. + * + * Thus, we should only stop the net queue and decrement + * the wanpipe usage counter via wanpipe_close() function. + */ + +static int if_close (struct net_device* dev) +{ + private_area_t* priv_area = dev->priv; + sdla_t* card = priv_area->card; + + stop_net_queue(dev); + +#if defined(LINUX_2_1) + dev->start=0; +#endif + wanpipe_close(card); + + + return 0; +} + + +/*============================================================= + * disable_comm - Main shutdown function + * + * @card: Wanpipe device pointer + * + * The command 'wanrouter stop' has been called + * and the whole wanpipe device is going down. + * This is the last function called to disable + * all comunications and deallocate any memory + * that is still allocated. + * + * o Disable communications, turn off interrupts + * o Deallocate memory used, if any + * o Unconfigure TE1 card + */ + +static void disable_comm (sdla_t *card) +{ + unsigned long smp_flags; + netskb_t *skb; + + wan_spin_lock_irq(&card->wandev.lock,&smp_flags); + if (card->comm_enabled){ + disable_comm_shutdown (card); + }else{ + card->hw_iface.poke_byte(card->hw, card->intr_perm_off, 0x00); + } + wan_spin_unlock_irq(&card->wandev.lock,&smp_flags); + + /* Stop the ATM bh handler. We must do this + * outside the critical area because the kill + * function can sleep! */ + + WAN_TASKLET_KILL(((wan_tasklet_t*)&card->u.atm.wanpipe_rx_task)); + + wan_del_timer(&card->u.atm.atm_timer); + + wan_spin_lock_irq(&card->wandev.lock,&smp_flags); + + /* Free up ATM receive buffers */ + while ((skb=wan_skb_dequeue(&card->u.atm.wp_rx_free_list)) != NULL){ + wan_skb_free(skb); + } + while ((skb=wan_skb_dequeue(&card->u.atm.wp_rx_used_list)) != NULL){ + wan_skb_free(skb); + } + while ((skb=wan_skb_dequeue(&card->u.atm.wp_rx_data_list)) != NULL){ + wan_skb_free(skb); + } + while ((skb=wan_skb_dequeue(&card->u.atm.wp_tx_prot_list)) != NULL){ + wan_skb_free(skb); + } + + if (card->u.atm.atm_device){ + wp_sar_unregister_device(card->u.atm.atm_device); + card->u.atm.atm_device=NULL; + } + + if (card->u.atm.trace_info){ + wan_trace_purge(card->u.atm.trace_info); + wan_free(card->u.atm.trace_info); + card->u.atm.trace_info=NULL; + } + + wan_spin_unlock_irq(&card->wandev.lock,&smp_flags); + + /* TE1 - Unconfiging, only on shutdown */ + if (IS_TE1_CARD(card)) { + if (card->wandev.fe_iface.unconfig){ + card->wandev.fe_iface.unconfig(&card->fe); + } + } + return; +} + + + +/*============================================================================ + * if_tx_timeout + * + * Kernel networking stack calls this function in case + * the interface has been stopped for TX_TIMEOUT seconds. + * + * This would occur if we lost TX interrupts or the + * card has stopped working for some reason. + * + * Handle transmit timeout event from netif watchdog + */ +static void if_tx_timeout (struct net_device *dev) +{ + private_area_t* chan = dev->priv; + sdla_t *card = chan->card; + + /* If our device stays busy for at least 5 seconds then we will + * kick start the device by making dev->tbusy = 0. We expect + * that our device never stays busy more than 5 seconds. So this + * is only used as a last resort. + */ + + ++chan->if_stats.collisions; + + DEBUG_EVENT( "%s: Transmit timed out on %s\n", card->devname,dev->name); + netif_wake_queue (dev); +} + + +/*============================================================================ + * if_send - Send a packet on a network interface. + * + * @dev: Network interface pointer + * @skb: Packet obtained from the stack or API + * that should be sent out the port. + * + * o Mark interface as stopped + * (marks start of the transmission) to indicate + * to the stack that the interface is busy. + * + * o Check link state. + * If link is not up, then drop the packet. + * + * o Copy the tx packet into the protocol tx buffers on + * the adapter. + * + * o If tx successful: + * Free the skb buffer and mark interface as running + * and return 0. + * + * o If tx failed, busy: + * Keep interface marked as busy + * Do not free skb buffer + * Enable Tx interrupt (which will tell the stack + * that interace is not busy) + * Return a non-zero value to tell the stack + * that the tx should be retried. + * + * Return: 0 complete (socket buffer must be freed) + * non-0 packet may be re-transmitted + * + */ +static int if_send (netskb_t* skb, struct net_device* dev) +{ + private_area_t *chan = dev->priv; + sdla_t *card = chan->card; + unsigned long smp_flags; + int err=0; + + /* Mark interface as busy. The kernel will not + * attempt to send any more packets until we clear + * this condition */ +#if defined(LINUX_2_4)||defined(LINUX_2_6) + netif_stop_queue(dev); +#endif + + if (skb == NULL){ + /* This should never happen. Just a sanity check. + */ + DEBUG_EVENT( "%s: interface %s got kicked!\n", + card->devname, dev->name); + + WAN_NETIF_WAKE_QUEUE(dev); + return 0; + } + + /* Non 2.4 kernels used to call if_send() + * after TX_TIMEOUT seconds have passed of interface + * being busy. Same as if_tx_timeout() in 2.4 kernels */ +#if defined(LINUX_2_1) + if (dev->tbusy){ + + /* If our device stays busy for at least 5 seconds then we will + * kick start the device by making dev->tbusy = 0. We expect + * that our device never stays busy more than 5 seconds. So this + * is only used as a last resort. + */ + if((jiffies - chan->tick_counter) < (5 * HZ)) { + return 1; + } + + if_tx_timeout(dev); + } +#endif + + /* PVC_PROT protocol is used by the API sockets + * to indicate to the driver that this packet + * is a custom RAW packet and no protocol checks + * should be done on it */ + if (ntohs(skb->protocol) != htons(PVC_PROT)){ + + /* check the udp packet type */ + if (wan_udp_pkt_type(card,wan_skb_data(skb)) == 0){ + if(store_udp_mgmt_pkt(UDP_PKT_FRM_STACK, card, skb, dev, + chan)){ + card->hw_iface.set_bit(card->hw, card->intr_perm_off, APP_INT_ON_TIMER); + } + start_net_queue(dev); + return 0; + } + + /* check to see if the source IP address is a broadcast or */ + /* multicast IP address */ + if(chan->common.usedby == WANPIPE && chk_bcast_mcast_addr(card, dev, skb)){ + ++chan->if_stats.tx_dropped; + wan_skb_free(skb); + start_net_queue(dev); + return 0; + } + } + + if(card->type != SDLA_S514){ + s508_lock(card,&smp_flags); + } + + if(card->wandev.state != WAN_CONNECTED){ + ++chan->if_stats.tx_dropped; + start_net_queue(dev); + + }else if(!skb->protocol){ + /* Skb buffer without protocol should never + * occur in normal operation */ + ++chan->if_stats.tx_errors; + start_net_queue(dev); + + }else { + + err=wanpipe_sar_tx(chan->sar_pvc, skb, (void*)chan->tx_cells_skb); + err=0; + if (err != 0){ + ++chan->if_stats.tx_errors; + start_net_queue(dev); + goto if_send_exit_crit; + } + + DEBUG_TX("IF_SEND Orig SKB=%d Tx Cells=%d Tx Cell Erro=%i \n", + wan_skb_len(skb),wan_skb_len(chan->tx_cells_skb), + wan_skb_len(chan->tx_cells_skb)%53); + + err=wp_handle_tx_packets(card,chan->tx_cells_skb); + if (err) { + /* Failed to send, mark queue as busy + * and let the stack retry */ + stop_net_queue(dev); + }else{ + + /* Send successful, update stats + * and mark queue as ready */ + ++chan->if_stats.tx_packets; + chan->if_stats.tx_bytes += wan_skb_len(skb); + start_net_queue(dev); + + wan_netif_set_ticks(dev, SYSTEM_TICKS); + } + + } + +if_send_exit_crit: + + /* If the queue is still stopped here, then we + * have failed to send! Turn on interrutps and + * return the skb buffer to the stack by + * exiting with non-zero value. + * + * Otherwise, free the skb buffer and return 0 + */ + if (!(err=WAN_NETIF_QUEUE_STOPPED(dev))) { + wan_skb_free(skb); + }else{ + chan->tick_counter = jiffies; + card->hw_iface.set_bit(card->hw, card->intr_perm_off, APP_INT_ON_TX_FRAME); + } + + /* End of critical area for re-entry and for S508 card */ + if(card->type != SDLA_S514){ + s508_unlock(card,&smp_flags); + } + + return err; +} + + +/*============================================================================ + * chk_bcast_mcast_addr - Check for source broadcast addresses + * + * Check to see if the packet to be transmitted contains a broadcast or + * multicast source IP address. + */ + +static int chk_bcast_mcast_addr(sdla_t *card, struct net_device* dev, + netskb_t *skb) +{ + u32 src_ip_addr; + u32 broadcast_ip_addr = 0; + private_area_t *priv_area=dev->priv; + struct in_device *in_dev; + /* read the IP source address from the outgoing packet */ + src_ip_addr = *(u32 *)(wan_skb_data(skb) + 12); + + if (priv_area->common.usedby != WANPIPE){ + return 0; + } + + /* read the IP broadcast address for the device */ + in_dev = dev->ip_ptr; + if(in_dev != NULL) { + struct in_ifaddr *ifa= in_dev->ifa_list; + if(ifa != NULL) + broadcast_ip_addr = ifa->ifa_broadcast; + else + return 0; + } + + /* check if the IP Source Address is a Broadcast address */ + if((dev->flags & IFF_BROADCAST) && (src_ip_addr == broadcast_ip_addr)) { + DEBUG_EVENT( "%s: Broadcast Source Address silently discarded\n", + card->devname); + return 1; + } + + /* check if the IP Source Address is a Multicast address */ + if((ntohl(src_ip_addr) >= 0xE0000001) && + (ntohl(src_ip_addr) <= 0xFFFFFFFE)) { + DEBUG_EVENT( "%s: Multicast Source Address silently discarded\n", + card->devname); + return 1; + } + + return 0; +} + +/*============================================================================ + * if_stats + * + * Used by /proc/net/dev and ifconfig to obtain interface + * statistics. + * + * Return a pointer to struct net_device_stats. + */ +static struct net_device_stats* if_stats (struct net_device* dev) +{ + private_area_t* priv_area; + + if ((priv_area=dev->priv) == NULL) + return NULL; + + return &priv_area->if_stats; +} + + + + +/*======================================================================== + * + * if_do_ioctl - Ioctl handler for fr + * + * @dev: Device subject to ioctl + * @ifr: Interface request block from the user + * @cmd: Command that is being issued + * + * This function handles the ioctls that may be issued by the user + * to control or debug the protocol or hardware . + * + * It does both busy and security checks. + * This function is intended to be wrapped by callers who wish to + * add additional ioctl calls of their own. + * + * Used by: SNMP Mibs + * wanpipemon debugger + * + */ +static int if_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + private_area_t* chan= (private_area_t*)dev->priv; + unsigned long smp_flags; + wan_udp_pkt_t *wan_udp_pkt; + sdla_t *card; + + if (!chan){ + return -ENODEV; + } + card=chan->card; + + NET_ADMIN_CHECK(); + + switch(cmd) + { + case SIOC_WANPIPE_PIPEMON: + + if (wan_atomic_read(&chan->udp_pkt_len) != 0){ + return -EBUSY; + } + + wan_atomic_set(&chan->udp_pkt_len,MAX_LGTH_UDP_MGNT_PKT); + + wan_udp_pkt=(wan_udp_pkt_t*)chan->udp_pkt_data; + if (copy_from_user(&wan_udp_pkt->wan_udp_hdr,ifr->ifr_data,sizeof(wan_udp_hdr_t))){ + wan_atomic_set(&chan->udp_pkt_len,0); + return -EFAULT; + } + + wan_spin_lock_irq(&card->wandev.lock, &smp_flags); + + /* We have to check here again because we don't know + * what happened during spin_lock */ + if (wan_test_bit(0,&card->in_isr)) { + DEBUG_EVENT( "%s:%s Pipemon command failed, Driver busy: try again.\n", + card->devname,dev->name); + wan_atomic_set(&chan->udp_pkt_len,0); + wan_spin_unlock_irq(&card->wandev.lock, &smp_flags); + return -EBUSY; + } + + process_udp_mgmt_pkt(card,dev,chan,1); + + wan_spin_unlock_irq(&card->wandev.lock, &smp_flags); + + /* This area will still be critical to other + * PIPEMON commands due to udp_pkt_len + * thus we can release the irq */ + + if (wan_atomic_read(&chan->udp_pkt_len) > sizeof(wan_udp_pkt_t)){ + DEBUG_EVENT( "%s: Error: Pipemon buf too bit on the way up! %i\n", + card->devname,wan_atomic_read(&chan->udp_pkt_len)); + wan_atomic_set(&chan->udp_pkt_len,0); + return -EINVAL; + } + + if (copy_to_user(ifr->ifr_data,&wan_udp_pkt->wan_udp_hdr,sizeof(wan_udp_hdr_t))){ + wan_atomic_set(&chan->udp_pkt_len,0); + return -EFAULT; + } + + wan_atomic_set(&chan->udp_pkt_len,0); + return 0; + + + default: + return -EOPNOTSUPP; + } + return 0; +} + + + + + +/**SECTION********************************************************** + * + * FIRMWARE Specific Interface Functions + * + *******************************************************************/ + +static int init_interrupt_status_ptrs(sdla_t *card) +{ + wan_mbox_t *mb1=&card->wan_mbox; + int err; + + /* Set up the interrupt status area */ + /* Read the Configuration and obtain: + * Ptr to shared memory infor struct + * Use this pointer to calculate the value of get_card_flags(card) ! + */ + mb1->wan_data_len = 0; + mb1->wan_command = READ_CONFIGURATION; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb1); + if(err != COMMAND_OK) { + frmw_error(card, err, mb1); + return -EIO; + } + + /* Alex Apr 8 2004 Sangom ISA card */ + card->flags_off = ((PHY_CONFIGURATION_STRUCT *)mb1->wan_data)-> + ptr_shared_mem_info_struct; + return 0; +} + + + +/*============================================================ + * set_adapter_config + * + * Set adapter config configures the firmware for + * the specific front end hardware. + * Front end hardware: T1/E1/56K/V32/RS232 + * + */ + +static int set_adapter_config (sdla_t* card) +{ + wan_mbox_t* mb = &card->wan_mbox; + ADAPTER_CONFIGURATION_STRUCT* cfg = (ADAPTER_CONFIGURATION_STRUCT*)mb->wan_data; + int err; + + card->hw_iface.getcfg(card->hw, SDLA_ADAPTERTYPE, &cfg->adapter_type); + cfg->adapter_config = 0x00; + cfg->operating_frequency = 00; + mb->wan_data_len = sizeof(ADAPTER_CONFIGURATION_STRUCT); + mb->wan_command = SET_ADAPTER_CONFIGURATION; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + + if(err != COMMAND_OK) { + frmw_error(card,err,mb); + } + return (err); +} + + +/*============================================================================ + * frmw_read_version + * + * Read firmware code version. + * Put code version as ASCII string in str. + */ +static int frmw_read_version (sdla_t* card, char* str) +{ + wan_mbox_t* mb = &card->wan_mbox; + int len; + char err; + mb->wan_data_len = 0; + mb->wan_command = READ_CODE_VERSION; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + + if(err != COMMAND_OK) { + frmw_error(card,err,mb); + } + else if (str) { /* is not null */ + len = mb->wan_data_len; + memcpy(str, mb->wan_data, len); + str[len] = '\0'; + } + return (err); +} + +/*----------------------------------------------------------------------------- + * Configure firmware. + */ +static int frmw_configure (sdla_t* card, void* data) +{ + int err; + wan_mbox_t *mb = &card->wan_mbox; + int data_length = sizeof(PHY_CONFIGURATION_STRUCT); + + mb->wan_data_len = data_length; + memcpy(mb->wan_data, data, data_length); + mb->wan_command = SET_CONFIGURATION; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + + if (err != COMMAND_OK) frmw_error (card, err, mb); + + return err; +} + + +/*============================================================================ + * Set interrupt mode -- HDLC Version. + */ + +static int frmw_set_intr_mode (sdla_t* card, unsigned mode) +{ + wan_mbox_t* mb = &card->wan_mbox; + INT_TRIGGERS_STRUCT* int_data = + (INT_TRIGGERS_STRUCT *)mb->wan_data; + int err; + + int_data->interrupt_triggers = mode; + card->hw_iface.getcfg(card->hw, SDLA_IRQ, &int_data->IRQ); + int_data->interrupt_timer = 1; + + mb->wan_data_len = sizeof(INT_TRIGGERS_STRUCT); + mb->wan_command = SET_INTERRUPT_TRIGGERS; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != COMMAND_OK) + frmw_error (card, err, mb); + return err; +} + + +/*=========================================================== + * disable_comm_shutdown + * + * Shutdown() disables the communications. We must + * have a sparate functions, because we must not + * call frmw_error() hander since the private + * area has already been replaced */ + +static int disable_comm_shutdown (sdla_t *card) +{ + wan_mbox_t* mb = &card->wan_mbox; + INT_TRIGGERS_STRUCT* int_data = + (INT_TRIGGERS_STRUCT *)mb->wan_data; + int err; + + /* Disable Interrutps */ + int_data->interrupt_triggers = 0; + card->hw_iface.getcfg(card->hw, SDLA_IRQ, &int_data->IRQ); + int_data->interrupt_timer = 1; + + mb->wan_data_len = sizeof(INT_TRIGGERS_STRUCT); + mb->wan_command = SET_INTERRUPT_TRIGGERS; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + + /* Disable Communications */ + + mb->wan_command = DISABLE_COMMUNICATIONS; + + mb->wan_data_len = 0; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + + card->comm_enabled = 0; + + return 0; +} + +/*============================================================================ + * Enable communications. + */ + +static int frmw_comm_enable (sdla_t* card) +{ + int err; + wan_mbox_t* mb = &card->wan_mbox; + + mb->wan_data_len = 0; + mb->wan_command = ENABLE_COMMUNICATIONS; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != COMMAND_OK) + frmw_error(card, err, mb); + else + card->comm_enabled = 1; + + return err; +} + +/*============================================================================ + * Read communication error statistics. + */ +static int frmw_read_comm_err_stats (sdla_t* card) +{ + int err; + wan_mbox_t* mb = &card->wan_mbox; + + mb->wan_data_len = 0; + mb->wan_command = READ_COMMS_ERROR_STATS; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != COMMAND_OK) + frmw_error(card,err,mb); + return err; +} + + +/*============================================================================ + * Read operational statistics. + */ +static int frmw_read_op_stats (sdla_t* card) +{ + int err; + wan_mbox_t* mb = &card->wan_mbox; + + mb->wan_data_len = 0; + mb->wan_command = READ_OPERATIONAL_STATS; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != COMMAND_OK) + frmw_error(card,err,mb); + return err; +} + + +/*============================================================================ + * Update communications error and general packet statistics. + */ +static int update_comms_stats(sdla_t* card, private_area_t* priv_area) +{ + wan_mbox_t* mb = &card->wan_mbox; + COMMS_ERROR_STATS_STRUCT* err_stats; + OPERATIONAL_STATS_STRUCT* op_stats; + + if(card->update_comms_stats == 3) { + /* 1. On the first timer interrupt, update T1/E1 alarms + * and PMON counters (only for T1/E1 card) (TE1) + */ + /* TE1 Update T1/E1 alarms */ + if (IS_TE1_CARD(card)) { + card->wandev.fe_iface.read_alarm(&card->fe, 0); + /* TE1 Update T1/E1 perfomance counters */ + card->wandev.fe_iface.read_pmon(&card->fe, 0); + + }else if (IS_56K_CARD(card)) { + /* 56K Update CSU/DSU alarms */ + card->wandev.fe_iface.read_alarm(&card->fe, 0); + } + } else { + /* 2. On the second timer interrupt, read the comms error + * statistics + */ + if(card->update_comms_stats == 2) { + if(frmw_read_comm_err_stats(card)) + return 1; + + err_stats = (COMMS_ERROR_STATS_STRUCT *)mb->wan_data; + card->wandev.stats.rx_over_errors = + err_stats->Rx_overrun_err_count; + + } else { + + /* on the third timer interrupt, read the operational + * statistics + */ + if(frmw_read_op_stats(card)) + return 1; + op_stats = (OPERATIONAL_STATS_STRUCT *)mb->wan_data; + card->wandev.stats.rx_length_errors = + op_stats->Rx_blocks_discard_count; + + card->wandev.stats.rx_crc_errors = + op_stats->Rx_bad_HEC_count; + + card->wandev.stats.rx_frame_errors = + op_stats->Rx_sync_failure_count; + + card->wandev.stats.rx_fifo_errors = + op_stats->Rx_hunt_timeout_count; + + card->wandev.stats.rx_missed_errors = + op_stats->Rx_resync_reception_loss_count; + + card->wandev.stats.tx_aborted_errors = + op_stats->Tx_underrun_cell_count+ + op_stats->Tx_length_error_count; + + + } + } + + return 0; +} + +/*============================================================================ + * Send packet. + * Return: 0 - o.k. + * 1 - no transmit buffers available + */ +static int frmw_send (sdla_t* card, void* data, unsigned len, unsigned char tx_bits) +{ + DATA_TX_STATUS_EL_STRUCT txbuf; + card->hw_iface.peek(card->hw, card->u.atm.txbuf_off, &txbuf, sizeof(txbuf)); + if (txbuf.opp_flag){ + return 1; + } + + card->hw_iface.poke(card->hw, txbuf.ptr_data_bfr, data, len); + + txbuf.block_length = len; + txbuf.misc_Tx_bits = tx_bits; + txbuf.opp_flag = 1; /* start transmission */ + card->hw_iface.poke(card->hw, card->u.atm.txbuf_off, &txbuf, sizeof(txbuf)); + + /* Update transmit buffer control fields */ + card->u.atm.txbuf_off += sizeof(DATA_TX_STATUS_EL_STRUCT); + if (card->u.atm.txbuf_off > card->u.atm.txbuf_last_off){ + card->u.atm.txbuf_off = card->u.atm.txbuf_base_off; + } + + return 0; +} + +/*============================================================================ + * Read TE1/56K Front end registers + */ +static unsigned char read_front_end_reg (void* card1, ...) +{ + va_list args; + sdla_t* card = (sdla_t*)card1; + wan_mbox_t* mb = &card->wan_mbox; + u16 reg; + char* data = mb->wan_data; + int err; + + va_start(args, card1); + reg = (u16)va_arg(args, int); + va_end(args); + + ((FRONT_END_REG_STRUCT *)data)->register_number = (unsigned short)reg; + mb->wan_data_len = sizeof(FRONT_END_REG_STRUCT); + mb->wan_command = READ_FRONT_END_REGISTER; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != COMMAND_OK) + frmw_error(card,err,mb); + + return(((FRONT_END_REG_STRUCT *)data)->register_value); +} + +/*============================================================================ + * Write to TE1/56K Front end registers + */ +static int write_front_end_reg (void* card1, ...) +{ + va_list args; + sdla_t* card = (sdla_t*)card1; + wan_mbox_t* mb = &card->wan_mbox; + u16 reg; + u8 value; + char* data = mb->wan_data; + int err; + int retry=15; + + va_start(args, card1); + reg = (u16)va_arg(args, int); + value = (u8)va_arg(args, int); + va_end(args); + + do { + ((FRONT_END_REG_STRUCT *)data)->register_number = (unsigned short)reg; + ((FRONT_END_REG_STRUCT *)data)->register_value = value; + mb->wan_data_len = sizeof(FRONT_END_REG_STRUCT); + mb->wan_command = WRITE_FRONT_END_REGISTER; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != COMMAND_OK) + frmw_error(card,err,mb); + }while(err && --retry); + + return err; +} + +/*============================================================================ + * Enable timer interrupt + */ +static void enable_timer (void* card_id) +{ + sdla_t *card = (sdla_t*)card_id; + netdevice_t *dev; + + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + DEBUG_EVENT( "%s: enabling timer %s\n",card->devname, + dev ? dev->name:"No DEV"); + + card->timer_int_enabled |= TMR_INT_ENABLED_TE; + card->hw_iface.set_bit(card->hw, card->intr_perm_off, APP_INT_ON_TIMER); + return; +} + +/*============================================================================ + * Firmware error handler. + * This routine is called whenever firmware command returns non-zero + * return code. + * + * Return zero if previous command has to be cancelled. + * + * WARNING: This function might be called in critical region. + * Thus no waiting should be performed here + */ +static int frmw_error (sdla_t *card, int err, wan_mbox_t *mb) +{ + unsigned cmd = mb->wan_command; + + switch (err) { + + default: + DEBUG_EVENT( "%s: command 0x%02X returned 0x%02X!\n", + card->devname, cmd, err); + } + + return 0; +} + + +/*=============================================================== + * set_frmw_config() + * + * used to set configuration options on the board + * + */ + +static int set_frmw_config(sdla_t* card) +{ + PHY_CONFIGURATION_STRUCT cfg; + + memset(&cfg, 0, sizeof(PHY_CONFIGURATION_STRUCT)); + + if(card->wandev.clocking){ + cfg.baud_rate = card->wandev.bps; + } + + cfg.line_config_options = (card->wandev.interface == WANOPT_RS232) ? + INTERFACE_LEVEL_RS232 : INTERFACE_LEVEL_V35; + + /* Automatic DTR/RTS and notify modem status changes */ + cfg.modem_config_options = 0; + + cfg.modem_status_timer = 10; + + /* Cells are passed transparently between the firmware + * and driver. This allows the transfer of multiple cells + * in a single block */ + cfg.API_options = PHY_TRANSPARENT_TX_RX_CELLS | PHY_APP_REVERSES_BIT_ORDER; + + cfg.protocol_options = PHY_UNI; + + cfg.HEC_options = PHY_DISABLE_RX_HEC_CHECK; + + cfg.custom_Rx_COSET = 0; + cfg.custom_Tx_COSET = 0; + + cfg.buffer_options = 0; + + /* Maximum number of cells that may be transmitted + * by the application in a single block */ + cfg.max_cells_in_Tx_block = PHY_MAX_CELLS_IN_TX_BLOCK; + + cfg.Tx_underrun_cell_GFC = card->u.atm.atm_cfg.atm_cell_cfg; + cfg.Tx_underrun_cell_PT = card->u.atm.atm_cfg.atm_cell_pt; + cfg.Tx_underrun_cell_CLP = card->u.atm.atm_cfg.atm_cell_clp; + cfg.Tx_underrun_cell_payload = card->u.atm.atm_cfg.atm_cell_payload; + + DEBUG_EVENT("%s: Configuring ATM Cells: GFC=0x%X PT=0x%X CLP=0x%X Payload=0x%X\n", + card->devname, + cfg.Tx_underrun_cell_GFC, + cfg.Tx_underrun_cell_PT, + cfg.Tx_underrun_cell_CLP, + cfg.Tx_underrun_cell_payload); + + memcpy(&phy_idle_cfg, &cfg, sizeof(PHY_CONFIGURATION_STRUCT)); + + cfg.number_cells_Tx_underrun = PHY_MAX_CELLS_TX_UNDERRUN; + + cfg.Rx_hunt_timer = 100; + cfg.Rx_hunt_timer = card->u.atm.atm_cfg.atm_hunt_timer; + + cfg.Rx_sync_bytes = 0x0152; + cfg.Rx_sync_offset = 0x03; + + if (card->u.atm.atm_cfg.atm_sync_mode){ + cfg.protocol_options |= PHY_MANUAL_RX_SYNC; + } + + cfg.Rx_sync_bytes = card->u.atm.atm_cfg.atm_sync_data; + cfg.Rx_sync_offset = card->u.atm.atm_cfg.atm_sync_offset; + + + DEBUG_EVENT("%s: Configuring ATM Sync: %s bytes=0x%04X offset=%i hunt=%i\n", + card->devname, + card->u.atm.atm_cfg.atm_sync_mode?"Manual":"Auto", + cfg.Rx_sync_bytes, + cfg.Rx_sync_offset, + cfg.Rx_hunt_timer); + + cfg.max_cells_in_Rx_block = PHY_MAX_CELLS_IN_RX_BLOCK; + cfg.cell_Rx_sync_loss_timer = 500; + cfg.Rx_HEC_check_timer = 100; + cfg.Rx_bad_HEC_timer = 100; + cfg.Rx_max_bad_HEC_count = 10; + cfg.number_cells_Rx_discard = PHY_MAX_CELLS_RX_DISCARD; + + cfg.statistics_options = (PHY_TX_BYTE_COUNT_STAT | + PHY_RX_BYTE_COUNT_STAT | + PHY_TX_THROUGHPUT_STAT | + PHY_RX_THROUGHPUT_STAT | + PHY_INCL_UNDERRUN_TX_THRUPUT | + PHY_INCL_DISC_RX_THRUPUT) ; + + return frmw_configure(card, &cfg); +} + +/*============================================================================ + * init_tx_rx_buff + * + * Initialize hardware Receive and Transmit Buffers. + * + */ + +static void init_tx_rx_buff( sdla_t* card) +{ + netdevice_t *dev; + wan_mbox_t* mb = &card->wan_mbox; + unsigned long tx_config_off; + unsigned long rx_config_off; + TX_STATUS_EL_CFG_STRUCT tx_config; + RX_STATUS_EL_CFG_STRUCT rx_config; + char err; + + mb->wan_data_len = 0; + mb->wan_command = READ_CONFIGURATION; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + + if(err != COMMAND_OK) { + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + if (dev){ + frmw_error(card,err,mb); + } + return; + } + + /* Alex Apr 8 2004 Sangom ISA card */ + tx_config_off = ((PHY_CONFIGURATION_STRUCT *)mb->wan_data)-> + ptr_Tx_stat_el_cfg_struct; + card->hw_iface.peek(card->hw, tx_config_off, &tx_config, sizeof(tx_config)); + rx_config_off = ((PHY_CONFIGURATION_STRUCT *)mb->wan_data)-> + ptr_Rx_stat_el_cfg_struct; + card->hw_iface.peek(card->hw, rx_config_off, &rx_config, sizeof(rx_config)); + + /* Setup Head and Tails for buffers */ + card->u.atm.txbuf_base_off = tx_config.base_addr_Tx_status_els; + card->u.atm.txbuf_last_off = + card->u.atm.txbuf_base_off + + (tx_config.number_Tx_status_els - 1) * sizeof(DATA_TX_STATUS_EL_STRUCT); + + card->u.atm.rxbuf_base_off = rx_config.base_addr_Rx_status_els; + card->u.atm.rxbuf_last_off = + card->u.atm.rxbuf_base_off + + (rx_config.number_Rx_status_els - 1) * sizeof(DATA_RX_STATUS_EL_STRUCT); + + /* Set up next pointer to be used */ + card->u.atm.txbuf_off = tx_config.next_Tx_status_el_to_use; + card->u.atm.rxmb_off = rx_config.next_Rx_status_el_to_use; + return; +} + +/*============================================================================= + * intr_test + * + * Perform Interrupt Test by running READ_CODE_VERSION command MAX_INTR + * _TEST_COUNTER times. + * + */ +static int intr_test( sdla_t* card) +{ + wan_mbox_t* mb = &card->wan_mbox; + int err,i; + + Intr_test_counter = 0; + + err = frmw_set_intr_mode(card, APP_INT_ON_COMMAND_COMPLETE); + + if (err == CMD_OK) { + for (i = 0; i < MAX_INTR_TEST_COUNTER; i ++) { + mb->wan_data_len = 0; + mb->wan_command = READ_CODE_VERSION; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != CMD_OK) + frmw_error(card, err, mb); + } + } + else { + return err; + } + card->hw_iface.poke_byte(card->hw, card->intr_type_off, 0x00); + err = frmw_set_intr_mode(card, 0); + + if (err != CMD_OK) + return err; + + return 0; +} + + + + + +/**SECTION************************************************** + * + * Bottom Half Handlers + * + **********************************************************/ + +static void wp_bh (unsigned long data) +{ + netdevice_t *dev; + sdla_t *card = (sdla_t*)data; + netskb_t *skb; + int err=0; + + if (wan_test_bit(PERI_CRIT, (void*)&card->wandev.critical)){ + DEBUG_EVENT("%s: WpBH PERI Critical\n", + card->devname); + WAN_TASKLET_END(((wan_tasklet_t*)&card->u.atm.wanpipe_rx_task)); + return; + } + + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + if (!card->u.atm.atm_device || !dev){ + DEBUG_EVENT("%s: WpBH Dev done\n", + card->devname); + WAN_TASKLET_END(((wan_tasklet_t*)&card->u.atm.wanpipe_rx_task)); + return; + } + + while ((skb=wan_skb_dequeue(&card->u.atm.wp_rx_used_list))){ + + err=wanpipe_sar_rx(card->u.atm.atm_device,skb); + + wan_skb_init(skb,16); + skb->len=1; + wan_skb_trim(skb,0); + + wan_skb_queue_tail(&card->u.atm.wp_rx_free_list,skb); + + if (err < 0 && card->wandev.state==WAN_CONNECTED){ + /* We are out of sync */ + wp_handle_out_of_sync_condition(card,0); + goto wp_bh_exit; + } + } + + while((skb=wan_skb_dequeue(&card->u.atm.wp_rx_data_list))){ + wp_handle_rx_packets(skb); + } + + while((skb=wan_skb_dequeue(&card->u.atm.wp_tx_prot_list))){ + err=wp_handle_tx_packets(card,skb); + if (err){ + + wan_skb_queue_head(&card->u.atm.wp_tx_prot_list,skb); + card->hw_iface.set_bit(card->hw, card->intr_perm_off, APP_INT_ON_TX_FRAME); + break; + } + wan_skb_free(skb); + } + +wp_bh_exit: + WAN_TASKLET_END(((wan_tasklet_t*)&card->u.atm.wanpipe_rx_task)); + return; +} + +static int wp_handle_out_of_sync_condition(sdla_t *card, unsigned char irq) +{ + wan_mbox_t* mb = &card->wan_mbox; + int err; + netskb_t* skb; + unsigned long flags=0; + + /* We should only try to re-sync if we are in + * CONNECTED state, otherwise we are probably + * in re-sync state already */ + if (card->u.atm.state != WAN_CONNECTED){ + return 0; + } + + DEBUG_EVENT("%s: ATM PHY out of sync, re-syncing!\n", + card->devname); + + if (!irq){ + wan_spin_lock_irq(&card->wandev.lock,&flags); + } + + mb->wan_data_len = 0; + mb->wan_command = PHY_RESYNCHRONIZE_RECEIVER; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != CMD_OK){ + frmw_error(card, err, mb); + DEBUG_EVENT("%s: Error: Failed to re-syncing adapter !\n", + card->devname); + + /* We failed to resync for some reason, get out + * and let the rx sar trigger the re-sync again */ + if (!irq){ + wan_spin_unlock_irq(&card->wandev.lock,&flags); + } + return -1; + } + port_set_state(card, WAN_DISCONNECTED); + + + while ((skb=wan_skb_dequeue(&card->u.atm.wp_rx_used_list))){ + wan_skb_init(skb,16); + skb->len=1; + wan_skb_trim(skb,0); + wan_skb_queue_tail(&card->u.atm.wp_rx_free_list,skb); + } + + wan_skb_queue_purge(&card->u.atm.wp_rx_data_list); + wan_skb_queue_purge(&card->u.atm.wp_tx_prot_list); + + if (!irq){ + wan_spin_unlock_irq(&card->wandev.lock,&flags); + } + + return 0; +} + +static int wp_handle_tx_packets(sdla_t* card, netskb_t *skb) +{ + void *data = wan_skb_data(skb); + unsigned long len = wan_skb_len(skb); + int err; + unsigned long flags; + + wan_spin_lock_irq(&card->wandev.lock,&flags); + err=frmw_send(card, data, len, 0); + wan_spin_unlock_irq(&card->wandev.lock,&flags); + + return err; +} + +static void wp_handle_rx_packets(netskb_t *skb) +{ + private_area_t *chan = (private_area_t *)skb->dev; + sdla_t *card; + + if (!chan){ + DEBUG_EVENT("%s:%d Error, Rx packet has no dev pointer (skb->dev==NULL)\n", + __FUNCTION__,__LINE__); + wan_skb_free(skb); + return; + } + + card=chan->card; + skb->dev=chan->dev; + + switch (chan->cfg.encap_mode){ + case RFC_MODE_BRIDGED_ETH_LLC: + case RFC_MODE_BRIDGED_ETH_VC: + skb->protocol = eth_type_trans(skb, skb->dev); + break; + case RFC_MODE_ROUTED_IP_LLC: + case RFC_MODE_ROUTED_IP_VC: + skb->protocol = htons(ETH_P_IP); + skb->mac.raw = skb->data; + break; + } + + ++chan->if_stats.rx_packets; + chan->if_stats.rx_bytes += skb->len; + + netif_rx(skb); +} + + +/**SECTION*************************************************************** + * + * HARDWARE Interrupt Handlers + * + ***********************************************************************/ + + +/*============================================================================ + * wpfw_isr + * + * Main interrupt service routine. + * Determin the interrupt received and handle it. + * + */ +static void wpatm_isr (sdla_t* card) +{ + SHARED_MEMORY_INFO_STRUCT flags; + int i; + + if (!card->hw){ + return; + } + + wan_set_bit(0,&card->in_isr); + + /* if critical due to peripheral operations + * ie. update() or getstats() then reset the interrupt and + * wait for the board to retrigger. + */ + if(wan_test_bit(PERI_CRIT, (void*)&card->wandev.critical)) { + DEBUG_EVENT( "%s: ISR: Critical with PERI_CRIT!\n", + card->devname); + goto isr_done; + } + + card->hw_iface.peek(card->hw, card->flags_off, &flags, sizeof(flags)); + switch(flags.interrupt_info_struct.interrupt_type) { + + case RX_APP_INT_PEND: /* 0x01: receive interrupt */ + rx_intr(card); + break; + + case TX_APP_INT_PEND: /* 0x02: transmit interrupt */ + tx_intr(card); + break; + + case COMMAND_COMPLETE_APP_INT_PEND:/* 0x04: cmd complete */ + ++ Intr_test_counter; + break; + + case EXCEP_COND_APP_INT_PEND: /* 0x20: Exception */ + process_exception(card); + break; + + case GLOBAL_EXCEP_COND_APP_INT_PEND: + process_global_exception(card); + + /* Reset the 56k or T1/E1 front end exception condition */ + if(IS_56K_CARD(card) || IS_TE1_CARD(card)) { + card->hw_iface.poke_byte(card->hw, card->fe_status_off, 0x01); + } + break; + + case TIMER_APP_INT_PEND: /* Timer interrupt */ + timer_intr(card); + break; + + default: + DEBUG_EVENT( "%s: spurious interrupt 0x%02X!\n", + card->devname, + flags.interrupt_info_struct.interrupt_type); + DEBUG_EVENT( "Code name: "); + for(i = 0; i < 4; i ++){ + printk("%c", + flags.global_info_struct.code_name[i]); + } + printk("\n"); + DEBUG_EVENT( "Code version: "); + for(i = 0; i < 4; i ++){ + printk("%c", + flags.global_info_struct.code_version[i]); + } + printk("\n"); + break; + } + +isr_done: + + wan_clear_bit(0,&card->in_isr); + card->hw_iface.poke_byte(card->hw, card->intr_type_off, 0x00); + return; +} + + +/*=============================================================== + * tx_intr + * + * Transmit interrupt handler. + * For each dev, check that there is something to send. + * If data available, transmit. + * + *===============================================================*/ + +static void tx_intr (sdla_t* card) +{ + netdevice_t *dev; + private_area_t *chan=NULL; + unsigned char dev_kicked=0, more_to_tx=0; + int i=0; + + card->hw_iface.clear_bit(card->hw, card->intr_perm_off, APP_INT_ON_TX_FRAME); + + if (card->u.atm.tx_dev == NULL){ + card->u.atm.tx_dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + } + + dev = card->u.atm.tx_dev; + + for (;;){ + + if (!WAN_NETIF_UP(dev)){ + goto tx_intr_dev_skip; + } + + chan = dev->priv; + if (WAN_NETIF_QUEUE_STOPPED(dev)){ + + if (dev_kicked){ + more_to_tx=1; + break; + } + + if (chan->common.usedby == API){ + WAN_NETIF_START_QUEUE(dev); + wan_wakeup_api(chan); + }else{ + WAN_NETIF_WAKE_QUEUE(dev); + } + + dev_kicked=1; + } + +tx_intr_dev_skip: + dev = move_dev_to_next(card,dev); + if (++i >= wan_atomic_read(&card->wandev.if_cnt)){ + break; + } + + }//End of FOR + + card->u.atm.tx_dev = dev; + + if (more_to_tx){ + card->hw_iface.set_bit(card->hw, card->intr_perm_off, APP_INT_ON_TX_FRAME); + } + + if (wan_skb_queue_len(&card->u.atm.wp_tx_prot_list)){ + WAN_TASKLET_SCHEDULE(((wan_tasklet_t*)&card->u.atm.wanpipe_rx_task)); + } + + return; +} + +/*=============================================================== + * move_dev_to_next + * + * + *===============================================================*/ + + +static netdevice_t * move_dev_to_next (sdla_t *card, netdevice_t *dev) +{ + struct wan_dev_le *devle; + if (wan_atomic_read(&card->wandev.if_cnt) == 1){ + return dev; + } + + WAN_LIST_FOREACH(devle, &card->wandev.dev_head, dev_link){ + if (devle->dev == dev){ + dev = WAN_DEVLE2DEV(WAN_LIST_NEXT(devle, dev_link)); + if (!dev){ + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + } + return dev; + } + } + return dev; +} + + + +/*============================================================================ + * rx_intr + * + * Receive interrupt handler. + */ +static void rx_intr (sdla_t* card) +{ + SHARED_MEMORY_INFO_STRUCT flags; + DATA_RX_STATUS_EL_STRUCT rxbuf; + unsigned long addr; + netskb_t *skb; + unsigned len; + void *buf; + int i; + + card->hw_iface.peek(card->hw, card->flags_off, &flags, sizeof(flags)); + card->hw_iface.peek(card->hw, card->u.atm.rxmb_off, &rxbuf, sizeof(rxbuf)); + addr = rxbuf.ptr_data_bfr; + if (rxbuf.opp_flag != 0x01) { + DEBUG_EVENT( + "%s: corrupted Rx buffer @ 0x%lX, flag = 0x%02X!\n", + card->devname, card->u.atm.rxmb_off, rxbuf.opp_flag); + DEBUG_EVENT( "Code name: "); + for(i = 0; i < 4; i ++) + DEBUG_EVENT( "%c", + flags.global_info_struct.code_name[i]); + DEBUG_EVENT( "\n"); + DEBUG_EVENT( "Code version: "); + for(i = 0; i < 4; i ++) + DEBUG_EVENT( "%c", + flags.global_info_struct.code_version[i]); + DEBUG_EVENT( "\n"); + + + /* Bug Fix: Mar 6 2000 + * If we get a corrupted mailbox, it measn that driver + * is out of sync with the firmware. There is no recovery. + * If we don't turn off all interrupts for this card + * the machine will crash. + */ + DEBUG_EVENT( "%s: Critical router failure ...!!!\n", card->devname); + DEBUG_EVENT( "Please contact Sangoma Technologies !\n"); + frmw_set_intr_mode(card,0); + return; + } + + if (card->wandev.state != WAN_CONNECTED){ + ++card->wandev.stats.rx_dropped; + goto rx_exit; + } + + len = rxbuf.block_length; + + /* Get a free/unused socket buffer from the ATM + * rx pool. */ + skb = wan_skb_dequeue(&card->u.atm.wp_rx_free_list); + if (skb == NULL) { + DEBUG_EVENT( "%s: No ATM rx buffers available!\n", + card->devname); + ++card->wandev.stats.rx_dropped; + goto rx_exit; + } + + buf = wan_skb_put(skb, len); + card->hw_iface.peek(card->hw, addr, buf, len); + + wan_skb_queue_tail(&card->u.atm.wp_rx_used_list,skb); + + WAN_TASKLET_SCHEDULE(((wan_tasklet_t*)&card->u.atm.wanpipe_rx_task)); + +rx_exit: + /* Release buffer element and calculate a pointer to the next one */ + rxbuf.opp_flag = 0x00; + card->hw_iface.poke(card->hw, card->u.atm.rxmb_off, &rxbuf, sizeof(rxbuf)); + card->u.atm.rxmb_off += sizeof(rxbuf); + if(card->u.atm.rxmb_off > card->u.atm.rxbuf_last_off){ + card->u.atm.rxmb_off = card->u.atm.rxbuf_base_off; + } +} + +/*============================================================================ + * Timer interrupt handler. + * The timer interrupt is used for two purposes: + * 1) Processing udp calls from 'cpipemon'. + * 2) Reading board-level statistics for updating the proc file system. + */ +void timer_intr(sdla_t *card) +{ + struct net_device* dev=NULL; + private_area_t* priv_area = NULL; + /* TE timer interrupt */ + if (card->timer_int_enabled & TMR_INT_ENABLED_TE) { + card->wandev.fe_iface.polling(&card->fe); + card->timer_int_enabled &= ~TMR_INT_ENABLED_TE; + } + + /* Configure hardware */ + if (card->timer_int_enabled & TMR_INT_ENABLED_CONFIG) { + config_frmw(card); + card->timer_int_enabled &= ~TMR_INT_ENABLED_CONFIG; + } + + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + if (dev == NULL){ + card->timer_int_enabled=0; + goto timer_isr_exit; + } + + priv_area = dev->priv; + + /* process a udp call if pending */ + if(card->timer_int_enabled & TMR_INT_ENABLED_UDP) { + process_udp_mgmt_pkt(card, dev, + priv_area,0); + card->timer_int_enabled &= ~TMR_INT_ENABLED_UDP; + } + + /* read the communications statistics if required */ + if(card->timer_int_enabled & TMR_INT_ENABLED_UPDATE) { + update_comms_stats(card, priv_area); + if(!(-- card->update_comms_stats)) { + card->timer_int_enabled &= + ~TMR_INT_ENABLED_UPDATE; + } + } + +timer_isr_exit: + + /* only disable the timer interrupt if there are no udp or statistic */ + /* updates pending */ + if(!card->timer_int_enabled) { + card->hw_iface.clear_bit(card->hw, card->intr_perm_off, APP_INT_ON_TIMER); + } +} + +/*============================================================================ + * Process global exception condition + */ +static int process_global_exception(sdla_t *card) +{ + wan_mbox_t* mb = &card->wan_mbox; + int err; + + mb->wan_data_len = 0; + mb->wan_command = READ_GLOBAL_EXCEPTION_CONDITION; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + + if(err != CMD_TIMEOUT ){ + + switch(mb->wan_return_code) { + + case EXCEP_MODEM_STATUS_CHANGE: + + if (IS_56K_CARD(card)) { + + FRONT_END_STATUS_STRUCT FE_status; + + card->hw_iface.peek(card->hw, + card->fe_status_off, + &FE_status, + sizeof(FE_status)); + card->fe.fe_param.k56_param.RR8_reg_56k = + FE_status.FE_U.stat_56k.RR8_56k; + card->fe.fe_param.k56_param.RRA_reg_56k = + FE_status.FE_U.stat_56k.RRA_56k; + card->fe.fe_param.k56_param.RRC_reg_56k = + FE_status.FE_U.stat_56k.RRC_56k; + card->wandev.fe_iface.read_alarm(&card->fe, 0); + + handle_front_end_state(card); + break; + + } + + if (IS_TE1_CARD(card)) { + /* TE1 T1/E1 interrupt */ + card->wandev.fe_iface.isr(&card->fe); + handle_front_end_state(card); + break; + } + + if ((mb->wan_data[0] & (DCD_HIGH | CTS_HIGH)) == (DCD_HIGH | CTS_HIGH)){ + card->fe.fe_status = FE_CONNECTED; + }else{ + card->fe.fe_status = FE_DISCONNECTED; + } + + DEBUG_EVENT( "%s: Modem status change\n", + card->devname); + + switch(mb->wan_data[0] & (DCD_HIGH | CTS_HIGH)) { + + case ((DCD_HIGH | CTS_HIGH)): + DEBUG_EVENT( "%s: DCD high, CTS high\n",card->devname); + break; + + case (DCD_HIGH): + DEBUG_EVENT( "%s: DCD high, CTS low\n",card->devname); + break; + + case (CTS_HIGH): + DEBUG_EVENT( "%s: DCD low, CTS high\n",card->devname); + break; + + default: + DEBUG_EVENT( "%s: DCD low, CTS low\n",card->devname); + break; + } + + handle_front_end_state(card); + break; + + case EXCEP_IRQ_TIMEOUT: + DEBUG_EVENT( "%s: IRQ timeout occurred\n", + card->devname); + break; + + default: + DEBUG_EVENT( "%s: Global exception %x\n", + card->devname, mb->wan_return_code); + break; + } + } + return 0; +} + +static void phy_sync_state_change(sdla_t *card, PHY_RX_SYNC_EXCEP_STRUCT *rx_sync) +{ + switch (rx_sync->Rx_sync_status){ + + case PHY_RX_SYNC_LOST: + DEBUG_EVENT("%s: Phy state change: Rx sync lost \n",card->devname); + goto state_ch_disconnected; + + case PHY_RX_HUNT: + DEBUG_EVENT("%s: Phy state change: Rx hunt \n",card->devname); + goto state_ch_disconnected; + + case PHY_RX_PRESYNC: + DEBUG_EVENT("%s: Phy state change: Rx presync \n",card->devname); + goto state_ch_disconnected; + + case PHY_RX_SYNCHRONIZED: + DEBUG_EVENT("%s: Phy state change: Rx sync successful \n",card->devname); + card->u.atm.state=WAN_CONNECTED; + if (card->fe.fe_status == FE_CONNECTED){ + port_set_state(card, WAN_CONNECTED); + } + break; + + default: + DEBUG_EVENT("%s: Unknown phy state change 0x%x\n", + card->devname, rx_sync->Rx_sync_status); + goto state_ch_disconnected; + } + + return; + +state_ch_disconnected: + card->u.atm.state=WAN_DISCONNECTED; + port_set_state(card, WAN_DISCONNECTED); + return; +} + + +/*============================================================================ + * Process exception condition + */ +static int process_exception(sdla_t *card) +{ + wan_mbox_t* mb = &card->wan_mbox; + int err; + + mb->wan_data_len = 0; + mb->wan_command = READ_EXCEPTION_CONDITION; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + + if(err == CMD_TIMEOUT) { + return 0; + } + + switch (err) { + + case PHY_EXCEP_RX_SYNC_STATE_CHANGE: + /* the PHY receiver has changed state */ + phy_sync_state_change(card,(PHY_RX_SYNC_EXCEP_STRUCT *)mb->wan_data); + break; + + case PHY_EXCEP_INVALID_HEC: + /* the Rx consecutive incorrect HEC counter has expired */ + DEBUG_EVENT("%s: PHY Exception: Rx consecutive invalid HEC\n", + card->devname); + break; + case PHY_EXCEP_RECEP_LOSS: + /* the cell reception sync loss timer has expired */ + DEBUG_EVENT("%s: PHY Exception: Cell rx sync loss timer expired\n", + card->devname); + break; + case PHY_EXCEP_RX_DISCARD: + /* incoming cells were discarded */ + DEBUG_EVENT("%s: PHY Exception: Incoming cells were discarded\n", + card->devname); + break; + case PHY_EXCEP_TX_LENGTH_ERROR: + /* a transmit buffer of invalid length was detected */ + DEBUG_EVENT("%s: PHY Exception: Tx buffer of invalid length detected\n", + card->devname); + break; + + + default: + DEBUG_EVENT("%s: PHY Exception: Unknown 0x%x\n", + card->devname, err); + + break; + } + return 0; +} + + + + +/**SECTION*********************************************************** + * + * WANPIPE Debugging Interfaces + * + ********************************************************************/ + + + +/*============================================================================= + * store_udp_mgmt_pkt + * + * Store a UDP management packet for later processing. + * + * When isr or tx task receives a UDP debug packet from + * wanpipemon utility, or from the remote network, the + * debug process must be defered to a kernel task + * which will execute the debug command at a later time. + * + */ + +static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, + netskb_t *skb, struct net_device* dev, + private_area_t* priv_area ) +{ + int udp_pkt_stored = 0; + + if(!wan_atomic_read(&priv_area->udp_pkt_len) && + (skb->len <= MAX_LGTH_UDP_MGNT_PKT)) { + wan_atomic_set(&priv_area->udp_pkt_len, skb->len); + priv_area->udp_pkt_src = udp_pkt_src; + memcpy(priv_area->udp_pkt_data, skb->data, skb->len); + card->timer_int_enabled = TMR_INT_ENABLED_UDP; + udp_pkt_stored = 1; + } + + wan_skb_free(skb); + + return(udp_pkt_stored); +} + +#define ATM_HEADER_SZ 5 +#define ATM_PAYLOAD_SZ 48 +typedef struct wp_atm_cell +{ + unsigned char hdr[ATM_HEADER_SZ]; /* ATM header */ + unsigned char info[ATM_PAYLOAD_SZ]; /* ATM payload */ +} wp_atm_cell_t; + + +/*============================================================================= + * process_udp_mgmt_pkt + * + * Process all "wanpipemon" debugger commands. This function + * performs all debugging tasks: + * + * Line Tracing + * Line/Hardware Statistics + * Protocol Statistics + * + * "wanpipemon" utility is a user-space program that + * is used to debug the WANPIPE product. + * + */ + +static int process_udp_mgmt_pkt(sdla_t* card, struct net_device* dev, + private_area_t* priv_area, int local_dev ) +{ + unsigned short buffer_length; + int udp_mgmt_req_valid = 1; + wan_mbox_t *mb = &card->wan_mbox; + SHARED_MEMORY_INFO_STRUCT flags; + wan_udp_pkt_t *wan_udp_pkt; + struct timeval tv; + int err; + netskb_t* skb; + wp_atm_cell_t tx_idle_data; + + wan_udp_pkt = (wan_udp_pkt_t *) priv_area->udp_pkt_data; + + //DEBUG_EVENT("%s: process_udp_mgmt_pkt(): command 0x%x\n", + // card->devname,wan_udp_pkt->wan_udp_command); + + card->hw_iface.peek(card->hw, card->flags_off, &flags, sizeof(flags)); + if (!local_dev){ + + if(priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK){ + + /* Only these commands are support for remote debugging. + * All others are not */ + switch(wan_udp_pkt->wan_udp_command) { + + case READ_GLOBAL_STATISTICS: + case READ_MODEM_STATUS: + case ROUTER_UP_TIME: + case READ_COMMS_ERROR_STATS: + case READ_OPERATIONAL_STATS: + /* These two commands are executed for + * each request */ + case READ_CONFIGURATION: + case READ_CODE_VERSION: + case WAN_GET_MEDIA_TYPE: + case WAN_FE_GET_STAT: + udp_mgmt_req_valid = 1; + break; + default: + udp_mgmt_req_valid = 0; + break; + } + } + } + + if(!udp_mgmt_req_valid) { + + /* set length to 0 */ + wan_udp_pkt->wan_udp_data_len = 0; + + /* set return code */ + wan_udp_pkt->wan_udp_return_code = 0xCD; + + if (net_ratelimit()){ + DEBUG_EVENT( + "%s: Warning, Illegal UDP command attempted from network: %x\n", + card->devname,wan_udp_pkt->wan_udp_command); + } + + }else{ + wan_udp_hdr_t* udp_hdr = &wan_udp_pkt->wan_udp_hdr; + wan_trace_t *trace_info = card->u.atm.trace_info; + + if (!trace_info){ + DEBUG_EVENT( + "%s: Critical error, no trace info ptr in udp dbg\n", + card->devname); + + wan_udp_pkt->wan_udp_data_len = 0; + wan_udp_pkt->wan_udp_return_code = 0xCD; + goto process_udp_cmd_exit; + } + + wan_udp_pkt->wan_udp_opp_flag = 0; + + switch(wan_udp_pkt->wan_udp_command) { + + case ENABLE_TRACING: + + udp_hdr->wan_udphdr_return_code = WAN_CMD_OK; + udp_hdr->wan_udphdr_data_len = 0; + + if (!wan_test_bit(0,&trace_info->tracing_enabled)){ + + trace_info->trace_timeout = SYSTEM_TICKS; + + wan_trace_purge(trace_info); + + //DEBUG_EVENT("%s: ATM ENABLE_TRACING : mode %d\n", card->devname, + // udp_hdr->wan_udphdr_data[0]); + + switch(udp_hdr->wan_udphdr_data[0]) + { + case 0: + wan_clear_bit(1,&trace_info->tracing_enabled); + DEBUG_UDP("%s: ADSL L3 trace enabled!\n", + card->devname); + break; + case 1: + wan_clear_bit(2,&trace_info->tracing_enabled); + wan_set_bit(1,&trace_info->tracing_enabled); + DEBUG_UDP("%s: ADSL L2 trace enabled!\n", + card->devname); + break; + case 3: + wan_clear_bit(1,&trace_info->tracing_enabled); + //user wants to see all cells, including idle + wan_set_bit(2,&trace_info->tracing_enabled); + wan_set_bit(3,&trace_info->tracing_enabled); + DEBUG_UDP("%s: ATM 'All Cells' trace enabled!\n", + card->devname); + break; + default: + wan_clear_bit(1,&trace_info->tracing_enabled); + wan_set_bit(2,&trace_info->tracing_enabled); + DEBUG_UDP("%s: ADSL L1 trace enabled!\n", + card->devname); + } + wan_set_bit (0,&trace_info->tracing_enabled); + + }else{ + DEBUG_EVENT("%s: Error: ATM trace running!\n", + card->devname); + udp_hdr->wan_udphdr_return_code = 2; + } + + break; + + case DISABLE_TRACING: + + udp_hdr->wan_udphdr_return_code = WAN_CMD_OK; + + if(wan_test_bit(0,&trace_info->tracing_enabled)) { + + wan_clear_bit(0,&trace_info->tracing_enabled); + wan_clear_bit(1,&trace_info->tracing_enabled); + wan_clear_bit(2,&trace_info->tracing_enabled); + wan_clear_bit(3,&trace_info->tracing_enabled); + + wan_trace_purge(trace_info); + + DEBUG_UDP("%s: Disabling ADSL trace\n", + card->devname); + + }else{ + /* set return code to line trace already + disabled */ + udp_hdr->wan_udphdr_return_code = 1; + } + + break; + + case GET_TRACE_INFO: + + if(wan_test_bit(0,&trace_info->tracing_enabled)){ + trace_info->trace_timeout = SYSTEM_TICKS; + }else{ + DEBUG_EVENT("%s: Error ATM trace not enabled\n", + card->devname); + /* set return code */ + udp_hdr->wan_udphdr_return_code = 1; + break; + } + + buffer_length = 0; + udp_hdr->wan_udphdr_atm_num_frames = 0; + udp_hdr->wan_udphdr_atm_ismoredata = 0; + +#if defined(__FreeBSD__) || defined(__OpenBSD__) + while (wan_trace_queue_len(trace_info)){ + WAN_IFQ_POLL(&trace_info->trace_queue, skb); + if (skb == NULL){ + DEBUG_EVENT("%s: No more trace packets in trace queue!\n", + card->devname); + break; + } + if ((WAN_MAX_DATA_SIZE - buffer_length) < skb->m_pkthdr.len){ + /* indicate there are more frames on board & exit */ + udp_hdr->wan_udphdr_atm_ismoredata = 0x01; + break; + } + + m_copydata(skb, + 0, + skb->m_pkthdr.len, + &udp_hdr->wan_udphdr_data[buffer_length]); + buffer_length += skb->m_pkthdr.len; + WAN_IFQ_DEQUEUE(&trace_info->trace_queue, skb); + if (skb){ + wan_skb_fee(skb); + } + udp_hdr->wan_udphdr_atm_num_frames++; + } +#elif defined(__LINUX__) + + if( (wan_test_bit(3,&trace_info->tracing_enabled)) ){ + + memset(&tx_idle_data, 0x00, sizeof(wp_atm_cell_t)); + + //set CLP + tx_idle_data.hdr[3] = phy_idle_cfg.Tx_underrun_cell_CLP; + //set HEC + tx_idle_data.hdr[4] = calculate_hec_crc(tx_idle_data.hdr); + + //set the payload + memset(tx_idle_data.info, phy_idle_cfg.Tx_underrun_cell_payload, ATM_PAYLOAD_SZ); + + if(wpabs_get_last_trace_direction(trace_info) == TRC_INCOMING_FRM ){ + + capture_atm_trace_packet(trace_info, + &tx_idle_data, + sizeof(wp_atm_cell_t), TRC_OUTGOING_FRM); + + wpabs_set_last_trace_direction(trace_info, TRC_OUTGOING_FRM); + }else{ + + trace_info->missed_idle_rx_counter++; + if(trace_info->missed_idle_rx_counter > 10){ + + //This condition is possible if no idle cells received + //for a long period of time. It usualy means line is disconnected. + //Despite that the tx idle cells may still be transmitted. + + capture_atm_trace_packet(trace_info, + &tx_idle_data, + sizeof(wp_atm_cell_t), TRC_OUTGOING_FRM); + + wpabs_set_last_trace_direction(trace_info, TRC_OUTGOING_FRM); + trace_info->missed_idle_rx_counter = 0; + } + } + } + + + while ((skb=skb_dequeue(&trace_info->trace_queue)) != NULL){ + + if((MAX_TRACE_BUFFER - buffer_length) < wan_skb_len(skb)){ + /* indicate there are more frames on board & exit */ + udp_hdr->wan_udphdr_atm_ismoredata = 0x01; + if (buffer_length != 0){ + wan_skb_queue_head(&trace_info->trace_queue, skb); + }else{ + /* If rx buffer length is greater than the + * whole udp buffer copy only the trace + * header and drop the trace packet */ + + memcpy(&udp_hdr->wan_udphdr_atm_data[buffer_length], + wan_skb_data(skb), + sizeof(wan_trace_pkt_t)); + + buffer_length = sizeof(wan_trace_pkt_t); + udp_hdr->wan_udphdr_atm_num_frames++; + wan_skb_free(skb); + } + break; + } + + memcpy(&udp_hdr->wan_udphdr_atm_data[buffer_length], + wan_skb_data(skb), + wan_skb_len(skb)); + + buffer_length += wan_skb_len(skb); + wan_skb_free(skb); + udp_hdr->wan_udphdr_atm_num_frames++; + } +#endif + /* set the data length and return code */ + udp_hdr->wan_udphdr_data_len = buffer_length; + udp_hdr->wan_udphdr_return_code = WAN_CMD_OK; + break; + + case FT1_READ_STATUS: + + ((unsigned char *)wan_udp_pkt->wan_udp_data )[0] = + flags.FE_info_struct.parallel_port_A_input; + + ((unsigned char *)wan_udp_pkt->wan_udp_data )[1] = + flags.FE_info_struct.parallel_port_B_input; + wan_udp_pkt->wan_udp_return_code = COMMAND_OK; + wan_udp_pkt->wan_udp_data_len = 2; + mb->wan_data_len = 2; + break; + + case ROUTER_UP_TIME: + do_gettimeofday( &tv ); + priv_area->router_up_time = tv.tv_sec - + priv_area->router_start_time; + *(unsigned long *)&wan_udp_pkt->wan_udp_data = + priv_area->router_up_time; + mb->wan_data_len = sizeof(unsigned long); + wan_udp_pkt->wan_udp_data_len = sizeof(unsigned long); + wan_udp_pkt->wan_udp_return_code = COMMAND_OK; + break; + + case ATM_LINK_STATUS: + + wan_udp_pkt->wan_udp_data[0] = (card->wandev.state==WAN_CONNECTED)?1:0; + wan_udp_pkt->wan_udp_data[1] = wanpipe_get_atm_state(priv_area->sar_pvc); + wan_udp_pkt->wan_udp_data_len = 2; + wan_udp_pkt->wan_udp_return_code = COMMAND_OK; + break; + + case FT1_MONITOR_STATUS_CTRL: + /* Enable FT1 MONITOR STATUS */ + if ((wan_udp_pkt->wan_udp_data[0] & ENABLE_READ_FT1_STATUS) || + (wan_udp_pkt->wan_udp_data[0] & ENABLE_READ_FT1_OP_STATS)) { + + if( rCount++ != 0 ) { + wan_udp_pkt->wan_udp_return_code = COMMAND_OK; + mb->wan_data_len = 1; + break; + } + } + + /* Disable FT1 MONITOR STATUS */ + if( wan_udp_pkt->wan_udp_data[0] == 0) { + + if( --rCount != 0) { + wan_udp_pkt->wan_udp_return_code = COMMAND_OK; + mb->wan_data_len = 1; + break; + } + } + goto dflt_1; + + case WAN_GET_MEDIA_TYPE: + case WAN_FE_GET_STAT: + case WAN_FE_SET_LB_MODE: + case WAN_FE_FLUSH_PMON: + case WAN_FE_GET_CFG: + if (IS_TE1_CARD(card)){ + card->wandev.fe_iface.process_udp( + &card->fe, + &wan_udp_pkt->wan_udp_cmd, + &wan_udp_pkt->wan_udp_data[0]); + }else if (IS_56K_CARD(card)){ + card->wandev.fe_iface.process_udp( + &card->fe, + &wan_udp_pkt->wan_udp_cmd, + &wan_udp_pkt->wan_udp_data[0]); + }else{ + if (wan_udp_pkt->wan_udp_command == WAN_GET_MEDIA_TYPE){ + wan_udp_pkt->wan_udp_data_len = sizeof(unsigned char); + wan_udp_pkt->wan_udp_return_code = CMD_OK; + }else{ + wan_udp_pkt->wan_udp_return_code = WAN_UDP_INVALID_CMD; + } + } + mb->wan_data_len = wan_udp_pkt->wan_udp_data_len; + break; + + case WAN_GET_PROTOCOL: + wan_udp_pkt->wan_udp_atm_num_frames = card->wandev.config_id; + wan_udp_pkt->wan_udp_return_code = CMD_OK; + mb->wan_data_len = wan_udp_pkt->wan_udp_data_len = 1; + break; + + case WAN_GET_PLATFORM: + wan_udp_pkt->wan_udp_data[0] = WAN_LINUX_PLATFORM; + wan_udp_pkt->wan_udp_return_code = CMD_OK; + mb->wan_data_len = wan_udp_pkt->wan_udp_data_len = 1; + break; + + default: +dflt_1: + DEBUG_EVENT("%s: onboard command: 0x%X\n", + card->devname, wan_udp_pkt->wan_udp_command); + + /* it's a board command */ + mb->wan_command = wan_udp_pkt->wan_udp_command; + mb->wan_data_len = wan_udp_pkt->wan_udp_data_len; + if (mb->wan_data_len) { + memcpy(&mb->wan_data, (unsigned char *) wan_udp_pkt-> + wan_udp_data, mb->wan_data_len); + } + + /* run the command on the board */ + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != COMMAND_OK) { + frmw_error(card,err,mb); + wan_udp_pkt->wan_udp_return_code = mb->wan_return_code; + break; + } + + /* copy the result back to our buffer */ + memcpy(&wan_udp_pkt->wan_udp_hdr.wan_cmd, mb, sizeof(wan_cmd_t)); + if (mb->wan_data_len) { + memcpy(&wan_udp_pkt->wan_udp_data, &mb->wan_data, + mb->wan_data_len); + } + + } /* end of switch */ + } /* end of else */ + +process_udp_cmd_exit: + + /* Fill UDP TTL */ + wan_udp_pkt->wan_ip_ttl= card->wandev.ttl; + + if (local_dev){ + wan_udp_pkt->wan_udp_request_reply = UDPMGMT_REPLY; + return 1; + } + +/* FIXME ?????????????????????? */ +#if 0 + len = reply_udp(priv_area->udp_pkt_data, mb->wan_data_len); + + if(priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK){ + + /* Must check if we interrupted if_send() routine. The + * tx buffers might be used. If so drop the packet */ + if (!wan_test_bit(SEND_CRIT,&card->wandev.critical)) { + + if(!frmw_send(card, priv_area->udp_pkt_data, len, 0)) { + ++ chan->if_stats.tx_packets; + chan->if_stats.tx_bytes += len; + } + } + } else { + + /* Pass it up the stack + Allocate socket buffer */ + if ((new_skb = wan_skb_alloc(len) != NULL) { + /* copy data into new_skb */ + + buf = wan_skb_put(new_skb, len); + memcpy(buf, priv_area->udp_pkt_data, len); + + /* Decapsulate pkt and pass it up the protocol stack */ + new_skb->protocol = htons(ETH_P_IP); + new_skb->dev = dev; + new_skb->mac.raw = new_skb->data; + + netif_rx(new_skb); + } else { + + DEBUG_EVENT( "%s: no socket buffers available!\n", + card->devname); + } + } +#endif + wan_atomic_set(&priv_area->udp_pkt_len,0); + + return 0; +} + +static int +capture_atm_trace_packet( + wan_trace_t *trace_info, + void *data, + int len, + char direction) +{ + int atm_packets=1; + int i; + wan_trace_pkt_t trc_el; + volatile wp_atm_cell_t *atm_cell_ptr=(wp_atm_cell_t*)data; + void *new_skb=NULL; + + atm_packets = len/sizeof(wp_atm_cell_t); + + if (atm_packets <= 0){ + return -1; + } + + if(wpabs_tracing_enabled(trace_info) != 3){ + return -1; + } + + for (i=0;iwandev.state != state) + { + switch (state) + { + case WAN_CONNECTED: + DEBUG_EVENT( "%s: Link connected!\n", + card->devname); + break; + + case WAN_CONNECTING: + DEBUG_EVENT( "%s: Link connecting...\n", + card->devname); + break; + + case WAN_DISCONNECTED: + DEBUG_EVENT( "%s: Link disconnected!\n", + card->devname); + break; + } + + card->wandev.state = state; + WAN_LIST_FOREACH(devle, &card->wandev.dev_head, dev_link){ + private_area_t *priv_area; + + dev = WAN_DEVLE2DEV(devle); + if (!dev || !wan_netif_priv(dev)) + continue; + priv_area = wan_netif_priv(dev); + priv_area->common.state = state; + + if (priv_area->sar_pvc){ + if (state == WAN_CONNECTED){ + wanpipe_set_atm_state(priv_area->sar_pvc,ATM_CONNECTED); + }else{ + wanpipe_set_atm_state(priv_area->sar_pvc,ATM_DISCONNECTED); + } + } + + netif_wake_queue(dev); + + if (priv_area->common.usedby == API){ + wan_wakeup_api(priv_area); + } + } + } +} + +/*=========================================================================== + * config_frmw + * + * Configure the protocol and enable communications. + * + * The if_open() function binds this function to the poll routine. + * Therefore, this function will run every time the interface + * is brought up. We cannot run this function from the if_open + * because if_open does not have access to the remote IP address. + * + * If the communications are not enabled, proceed to configure + * the card and enable communications. + * + * If the communications are enabled, it means that the interface + * was shutdown by either the user or driver. In this case, we + * have to check that the IP addresses have not changed. If + * the IP addresses have changed, we have to reconfigure the firmware + * and update the changed IP addresses. Otherwise, just exit. + * + */ + +static int config_frmw (sdla_t *card) +{ + + DEBUG_EVENT("%s: Configuring ATM Protocol\n", + card->devname); + + /* Setup the Board for */ + if (set_frmw_config(card)) { + DEBUG_EVENT( "%s: Failed configuration!\n", + card->devname); + return 0; + } + + card->hw_iface.poke_byte(card->hw, card->intr_type_off, 0x00); + card->hw_iface.poke_byte(card->hw, card->intr_perm_off, 0x00); + if (IS_TE1_CARD(card)) { + int err = -EINVAL; + DEBUG_EVENT( "%s: Configuring onboard %s CSU/DSU\n", + card->devname, + (IS_T1_CARD(card))?"T1":"E1"); + if (card->wandev.fe_iface.config){ + err = card->wandev.fe_iface.config(&card->fe); + } + if (err){ + DEBUG_EVENT( "%s: Failed %s configuratoin!\n", + card->devname, + (IS_T1_CARD(card))?"T1":"E1"); + return -EINVAL; + } + } + + + if (IS_56K_CARD(card)) { + int err = -EINVAL; + DEBUG_EVENT( "%s: Configuring 56K onboard CSU/DSU\n", + card->devname); + + if (card->wandev.fe_iface.config){ + err = card->wandev.fe_iface.config(&card->fe); + } + if (err){ + DEBUG_EVENT( "%s: Failed 56K configuration!\n", + card->devname); + return -EINVAL; + } + } + + + /* Set interrupt mode and mask */ + if (frmw_set_intr_mode(card, APP_INT_ON_RX_FRAME | + APP_INT_ON_GLOBAL_EXCEP_COND | + APP_INT_ON_TX_FRAME | + APP_INT_ON_EXCEP_COND | APP_INT_ON_TIMER)){ + DEBUG_EVENT( "%s: Failed to set interrupt triggers!\n", + card->devname); + return -EINVAL; + } + + /* Mask All interrupts */ + card->hw_iface.clear_bit(card->hw, card->intr_perm_off, + (APP_INT_ON_RX_FRAME | APP_INT_ON_TX_FRAME | + APP_INT_ON_TIMER | APP_INT_ON_GLOBAL_EXCEP_COND | + APP_INT_ON_EXCEP_COND)); + + if (frmw_comm_enable(card) != 0) { + DEBUG_EVENT( "%s: Failed to enable communications!\n", + card->devname); + card->hw_iface.poke_byte(card->hw, card->intr_perm_off, 0x00); + card->comm_enabled=0; + frmw_set_intr_mode(card,0); + return -EINVAL; + } + + /* Initialize Rx/Tx buffer control fields */ + init_tx_rx_buff(card); + card->u.atm.state = WAN_CONNECTING; + port_set_state(card, WAN_CONNECTING); + + /* Manually poll the 56K CSU/DSU to get the status */ + if (IS_56K_CARD(card)) { + /* 56K Update CSU/DSU alarms */ + card->wandev.fe_iface.read_alarm(&card->fe, 1); + } + + /* Unmask all interrupts except the Transmit and Timer interrupts */ + card->hw_iface.set_bit(card->hw, card->intr_perm_off, + (APP_INT_ON_RX_FRAME | APP_INT_ON_GLOBAL_EXCEP_COND | + APP_INT_ON_EXCEP_COND)); + card->hw_iface.poke_byte(card->hw, card->intr_type_off, 0x00); + return 0; +} + + +/*============================================================ + * frmw_poll + * + * Rationale: + * We cannot manipulate the routing tables, or + * ip addresses withing the interrupt. Therefore + * we must perform such actons outside an interrupt + * at a later time. + * + * Description: + * polling routine, responsible for + * shutting down interfaces upon disconnect + * and adding/removing routes. + * + * Usage: + * This function is executed for each + * interface through a tq_schedule bottom half. + * + * trigger_poll() function is used to kick + * the chldc_poll routine. + * + * if_open() calls the timer delay function which + * in turn calls the trigger_poll() to kick + * this task. + */ + +static void frmw_poll (void *dev_ptr) +{ + netdevice_t *dev=dev_ptr; + private_area_t *priv_area; + sdla_t *card; + u8 check_gateway=0; + + if (!dev || (priv_area=dev->priv) == NULL){ + return; + } + + card = priv_area->card; + + /* (Re)Configuraiton is in progress, stop what you are + * doing and get out */ + if (wan_test_bit(PERI_CRIT,&card->wandev.critical)){ + wan_clear_bit(POLL_CRIT,&card->wandev.critical); + return; + } + + switch (card->wandev.state){ + + case WAN_DISCONNECTED: + + /* If the dynamic interface configuration is on, and interface + * is up, then bring down the network interface */ + + if (wan_test_bit(DYN_OPT_ON,&priv_area->interface_down) && + !wan_test_bit(DEV_DOWN, &priv_area->interface_down) && + dev->flags & IFF_UP){ + + DEBUG_EVENT( "%s: Interface %s down.\n", + card->devname,dev->name); + change_dev_flags(dev,(dev->flags&~IFF_UP)); + set_bit(DEV_DOWN,&priv_area->interface_down); + priv_area->route_status = NO_ROUTE; + + } + + break; + + case WAN_CONNECTED: + + /* In SMP machine this code can execute before the interface + * comes up. In this case, we must make sure that we do not + * try to bring up the interface before dev_open() is finished */ + + + /* DEV_DOWN will be set only when we bring down the interface + * for the very first time. This way we know that it was us + * that brought the interface down */ + + if (wan_test_bit(DYN_OPT_ON,&priv_area->interface_down) && + wan_test_bit(DEV_DOWN, &priv_area->interface_down) && + !(dev->flags & IFF_UP)){ + + DEBUG_EVENT( "%s: Interface %s up.\n", + card->devname,dev->name); + change_dev_flags(dev,(dev->flags|IFF_UP)); + wan_clear_bit(DEV_DOWN,&priv_area->interface_down); + check_gateway=1; + } + + if (priv_area->gateway && check_gateway) + add_gateway(card,dev); + + break; + } + + wan_clear_bit(POLL_CRIT,&card->wandev.critical); +} + +/*============================================================ + * trigger_poll + * + * Description: + * Add a frmw_poll() task into a tq_scheduler bh handler + * for a specific interface. This will kick + * the fr_poll() routine at a later time. + * + * Usage: + * Interrupts use this to defer a taks to + * a polling routine. + * + * To execute tasks out of interrupt context. + * + */ +static void trigger_poll (struct net_device *dev) +{ + private_area_t *priv_area; + sdla_t *card; + + /* FIXME Poll routine is not used */ + return; + + if (!dev) + return; + + if ((priv_area = dev->priv)==NULL) + return; + + card = priv_area->card; + + if (wan_test_and_set_bit(POLL_CRIT,&card->wandev.critical)){ + return; + } + if (wan_test_bit(PERI_CRIT,&card->wandev.critical)){ + return; + } + + + WAN_TASKQ_SCHEDULE((&priv_area->poll_task)); + return; +} + + +/*============================================================ + * handle_front_end_state + * + * Front end state indicates the physical medium that + * the Z80 backend connects to. + * + * S514-1/2/3: V32/RS232/FT1 Front End + * Front end state is determined via + * Modem/Status. + * S514-4/5/7/8: 56K/T1/E1 Front End + * Front end state is determined via + * link status interrupt received + * from the front end hardware. + * + * If the front end state handler is enabed by the + * user. The interface state will follow the + * front end state. I.E. If the front end goes down + * the protocol and interface will be declared down. + * + * If the front end state is UP, then the interface + * and protocol will be up ONLY if the protocol is + * also UP. + * + * Therefore, we must have three state variables + * 1. Front End State (card->wandev.front_end_status) + * 2. Protocol State (card->wandev.state) + * 3. Interface State (dev->flags & IFF_UP) + * + */ + +static void handle_front_end_state(void* card_id) +{ + sdla_t* card = (sdla_t*)card_id; + netdevice_t *dev; + + /* FIXME: The is a bug fix to gideons firmware + * If we ever loose the front end, put + * the card into re-sync mode */ + if (card->fe.fe_status != FE_CONNECTED){ + wp_handle_out_of_sync_condition(card,1); + } + + if (card->wandev.ignore_front_end_status == WANOPT_YES){ + return; + } + + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + if (card->fe.fe_status == FE_CONNECTED){ + if (card->u.atm.state == WAN_CONNECTED){ + port_set_state(card,WAN_CONNECTED); + trigger_poll(dev); + } + }else{ + port_set_state(card,WAN_DISCONNECTED); + trigger_poll(dev); + } +} + +/*============================================================ + * s508_lock and s508_unlock + * + * Used to lock and unlock critical code areas. By + * default only Interrupt is allowed to execute + * board commands. If the non-interrupt process + * tries to execute a command these locks must + * be used to turn off the interrupts. + * + * Otherwise race conditions can occur between + * the interrupt and non-interrupt kernel + * processes. + * + */ + +void s508_lock (sdla_t *card, unsigned long *smp_flags) +{ + wan_spin_lock_irq(&card->wandev.lock, smp_flags); + if (card->next){ + wan_spin_lock(&card->next->wandev.lock); + } +} + +void s508_unlock (sdla_t *card, unsigned long *smp_flags) +{ + if (card->next){ + wan_spin_unlock(&card->next->wandev.lock); + } + wan_spin_unlock_irq(&card->wandev.lock, smp_flags); +} + + + + +/**SECTION********************************************************** + * + * PROC FILE SYSTEM SUPPORT + * + *******************************************************************/ + + + +#ifdef WANPIPE_ENABLE_PROC_FILE_HOOKS +#warning "Enabling Proc File System Hooks" + + +#define PROC_CFG_FRM "%-15s| %-12s|\n" +#define PROC_STAT_FRM "%-15s| %-12s| %-14s|\n" +static char config_hdr[] = + "Interface name | Device name |\n"; +static char status_hdr[] = + "Interface name | Device name | Status |\n"; + +static int get_config_info(void* priv, char* buf, int cnt, int len, int offs, int* stop_cnt) +{ + private_area_t* priv_area = priv; + sdla_t* card = NULL; + int size = 0; + + if (priv_area == NULL) + return cnt; + card = priv_area->card; + + if ((offs == 0 && cnt == 0) || (offs && offs == *stop_cnt)){ + PROC_ADD_LINE(cnt, (buf, &cnt, len, offs, stop_cnt, &size, "%s", config_hdr)); + } + + PROC_ADD_LINE(cnt, (buf, &cnt, len, offs, stop_cnt, &size, + PROC_CFG_FRM, priv_area->if_name, card->devname)); + return cnt; +} + +static int get_status_info(void* priv, char* buf, int cnt, int len, int offs, int* stop_cnt) +{ + private_area_t* priv_area = priv; + sdla_t* card = NULL; + int size = 0; + + if (priv_area == NULL) + return cnt; + card = priv_area->card; + + if ((offs == 0 && cnt == 0) || (offs && offs == *stop_cnt)){ + PROC_ADD_LINE(cnt, (buf, &cnt, len, offs, stop_cnt, &size, "%s", status_hdr)); + } + + PROC_ADD_LINE(cnt, (buf, &cnt, len, offs, stop_cnt, &size, PROC_STAT_FRM, + priv_area->if_name, card->devname, STATE_DECODE(priv_area->common.state))); + + return cnt; +} + +#define PROC_DEV_FR_S_FRM "%-20s| %-14s|\n" +#define PROC_DEV_FR_D_FRM "%-20s| %-14d|\n" +#define PROC_DEV_SEPARATE "=====================================\n" + +#if defined(LINUX_2_4)||defined(LINUX_2_6) +static int get_dev_config_info(char* buf, char** start, off_t offs, int len) +#else +static int get_dev_config_info(char* buf, char** start, off_t offs, int len, int dummy) +#endif +{ + int cnt = 0; + wan_device_t* wandev = (void*)start; + sdla_t* card = NULL; + int size = 0; + PROC_ADD_DECL(stop_cnt); + + if (wandev == NULL) + return cnt; + + PROC_ADD_INIT(offs, stop_cnt); + card = (sdla_t*)wandev->private; + + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_DEV_SEPARATE)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, "Configuration for %s device\n", + wandev->name)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_DEV_SEPARATE)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_DEV_FR_S_FRM, + "Comm Port", COMPORT_DECODE(card->wandev.comm_port))); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_DEV_FR_S_FRM, + "Interface", INT_DECODE(wandev->interface))); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_DEV_FR_S_FRM, + "Clocking", CLK_DECODE(wandev->clocking))); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_DEV_FR_D_FRM, + "BaudRate",wandev->bps)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_DEV_FR_D_FRM, + "MTU", wandev->mtu)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_DEV_FR_D_FRM, + "UDP Port", wandev->udp_port)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_DEV_FR_D_FRM, + "TTL", wandev->ttl)); + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, PROC_DEV_SEPARATE)); + + PROC_ADD_RET(cnt, offs, stop_cnt); +} + +static int set_dev_config(struct file *file, + const char *buffer, + unsigned long count, + void *data) +{ + int cnt = 0; + wan_device_t* wandev = (void*)data; + sdla_t* card = NULL; + + if (wandev == NULL) + return cnt; + + card = (sdla_t*)wandev->private; + + DEBUG_EVENT( "%s: New device config (%s)\n", + wandev->name, buffer); + /* Parse string */ + + return count; +} + + +#define PROC_IF_FR_S_FRM "%-30s\t%-14s\n" +#define PROC_IF_FR_D_FRM "%-30s\t%-14d\n" +#define PROC_IF_FR_L_FRM "%-30s\t%-14ld\n" +#define PROC_IF_SEPARATE "====================================================\n" + +#if defined(LINUX_2_4)||defined(LINUX_2_6) +static int get_if_info(char* buf, char** start, off_t offs, int len) +#else +static int get_if_info(char* buf, char** start, off_t offs, int len, int dummy) +#endif +{ + int cnt = 0; + struct net_device* dev = (void*)start; + private_area_t* priv_area = dev->priv; + sdla_t* card = priv_area->card; + int size = 0; + PROC_ADD_DECL(stop_cnt); + + goto get_if_info_end; + PROC_ADD_INIT(offs, stop_cnt); + /* Update device statistics */ + if (!offs && card->wandev.update) { + int rslt = 0; + rslt = card->wandev.update(&card->wandev); + if(rslt) { + switch (rslt) { + case -EAGAIN: + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, + "Device is busy!\n")); + break; + + default: + PROC_ADD_LINE(cnt, + (buf, &cnt, len, offs, &stop_cnt, &size, + "Device is not configured!\n")); + break; + } + goto get_if_info_end; + } + } + +get_if_info_end: + PROC_ADD_RET(cnt, offs, stop_cnt); +} + +static int set_if_info(struct file *file, + const char *buffer, + unsigned long count, + void *data) +{ + struct net_device* dev = (void*)data; + private_area_t* priv_area = NULL; + + if (dev == NULL || dev->priv == NULL) + return count; + + priv_area = (private_area_t*)dev->priv; + + + DEBUG_EVENT( "%s: New interface config (%s)\n", + priv_area->if_name, buffer); + /* Parse string */ + + return count; +} + +/* WANPIPE_ENABLE_PROC_FILE_HOOKS */ +#endif + +/* + * ****************************************************************** + * Proc FS function + */ +static int wan_atm_get_info(void* pcard, struct seq_file *m, int *stop_cnt) +{ + sdla_t *card = (sdla_t*)pcard; + + if (card->wandev.fe_iface.update_alarm_info){ + m->count = + WAN_FECALL( + &card->wandev, + update_alarm_info, + (&card->fe, m, stop_cnt)); + } + if (card->wandev.fe_iface.update_pmon_info){ + m->count = + WAN_FECALL( + &card->wandev, + update_pmon_info, + (&card->fe, m, stop_cnt)); + } + + return m->count; +} + + +/****** End ****************************************************************/ diff -Nur linux.org/drivers/net/wan/sdla_bitstrm.c linux-2.6.17/drivers/net/wan/sdla_bitstrm.c --- linux.org/drivers/net/wan/sdla_bitstrm.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/drivers/net/wan/sdla_bitstrm.c 2006-08-30 10:07:16.000000000 +0000 @@ -0,0 +1,5724 @@ +/***************************************************************************** +* sdla_bitstrm.c WANPIPE(tm) Multiprotocol WAN Link Driver. Bit Stream module. +* +* Authors: Nenad Corbic +* Gideon Hack +* +* Copyright: (c) 1995-2004 Sangoma Technologies Inc. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version +* 2 of the License, or (at your option) any later version. +* ============================================================================ +* +* Jan 03, 2004 David Rokhvarg Added new IOCTL calls for the "lineprobe". +* Aug 10, 2002 Nenad Corbic New bitstreaming code +* Sep 20, 2001 Nenad Corbic The min() function has changed for 2.4.9 +* kernel. Thus using the wp_min() defined in +* wanpipe.h +* Aug 14, 2001 Nenad Corbic Inital version, based on Chdlc module. +* Using Gideons new bitstreaming firmware. +*****************************************************************************/ + +#include +#include +#include /* WAN router definitions */ +#include /* WANPIPE common user API definitions */ +#include +#include /* BSTRM firmware API definitions */ +#include /* Socket Driver common area */ +#include +#include +#include + + +/****** Defines & Macros ****************************************************/ + +/* reasons for enabling the timer interrupt on the adapter */ +#define TMR_INT_ENABLED_UDP 0x01 +#define TMR_INT_ENABLED_UPDATE 0x02 +#define TMR_INT_ENABLED_CONFIG 0x10 +#define TMR_INT_ENABLED_TE 0x20 + +#define MAX_IP_ERRORS 10 + +#define BSTRM_DFLT_DATA_LEN 1500 /* default MTU */ +#define BSTRM_HDR_LEN 1 + +#define BSTRM_API 0x01 + +#define PORT(x) (x == 0 ? "PRIMARY" : "SECONDARY" ) +#define MAX_BH_BUFF 200 + +#undef PRINT_DEBUG +#ifdef PRINT_DEBUG +#define dbg_printk(format, a...) printk(format, ## a) +#else +#define dbg_printk(format, a...) +#endif + + +#define INC_CRC_CNT(a) if (++a >= MAX_CRC_QUEUE) a=0; +#define GET_FIN_CRC_CNT(a) { if (--a < 0) a=MAX_CRC_QUEUE-1; \ + if (--a < 0) a=MAX_CRC_QUEUE-1; } + +#define FLIP_CRC(a,b) { b=0; \ + b |= (a&0x000F)<<12 ; \ + b |= (a&0x00F0) << 4; \ + b |= (a&0x0F00) >> 4; \ + b |= (a&0xF000) >> 12; } + +#define DECODE_CRC(a) { a=( (((~a)&0x000F)<<4) | \ + (((~a)&0x00F0)>>4) | \ + (((~a)&0x0F00)<<4) | \ + (((~a)&0xF000)>>4) ); } +#define BITSINBYTE 8 + +#define MAX_CRC_QUEUE 3 + +#define NO_FLAG 0 +#define OPEN_FLAG 1 +#define CLOSING_FLAG 2 + +#define HDLC_ENCODE 0 +#define HDLC_ENCODE_IDLE_UPDATE 0 +#define HDLC_DECODE 0 + +#define MAX_TX_QUEUE_SIZE 50 +#define MAX_RX_FREE_SKB 10 +#define MAX_MTU_SIZE 1600 +#define MAX_CHAN_TX_UP_SIZE 1200 + +#define MAX_T1_CHAN_TX_UP_SIZE 50*NUM_OF_T1_CHANNELS //1200 bytes +#define MAX_E1_CHAN_TX_UP_SIZE 40*(NUM_OF_E1_CHANNELS-1) //1240 bytes +#define MAX_E1_UNFRM_CHAN_TX_UP_SIZE 40*(NUM_OF_E1_CHANNELS) //1240 bytes + + +//(MAX_MTU_SIZE-100) +#define SWITCH_TX_UP_DFLT 240*3 +//Max Rx Pkt + +#define TX_QUEUE_LOW (MAX_TX_QUEUE_SIZE*1/10) +#define TX_QUEUE_MID (MAX_TX_QUEUE_SIZE*5/10) +#define TX_QUEUE_HIGH (MAX_TX_QUEUE_SIZE*9/10) + +#define TX_BH_CRIT 1 +#define RX_BH_CRIT 0 + +#define TX_IDLE_FLAG 0x04 +#define BRD_IDLE_FLAG 0x02 + +#define QUEUE_SYNC 0 +#define QUEUE_LOW 1 +#define QUEUE_HIGH 2 + +/* chan->tq_control fileds */ +#define WAIT_DEVICE_BUFFERS 0 +#define WAIT_DEVICE_FAST 1 +#define WAIT_DEVICE_SLOW 2 + +atomic_t intr_cnt; +atomic_t intr_skip; + +atomic_t tx_data; +atomic_t rx_data; + +#define HDLC_ENG_BUF_LEN 5000 + + +#if 0 +# define HDLC_IDLE_ABORT 1 +#else +# undef HDLC_IDLE_ABORT +#endif + +/******Data Structures*****************************************************/ + +/* This structure is placed in the private data area of the device structure. + * The card structure used to occupy the private area but now the following + * structure will incorporate the card structure along with BSTRM specific data + */ + +typedef struct bitstrm_private_area +{ + wanpipe_common_t common; + sdla_t *card; +// netdevice_t *dev; + char if_name[WAN_IFNAME_SZ+1]; + unsigned long router_start_time; + unsigned long router_up_time; + unsigned long tick_counter; /* For 5s timeout counter */ + u8 config_bstrm; + unsigned char mc; /* Mulitcast support on/off */ + char udp_pkt_src; + char update_comms_stats; /* updating comms stats */ + + u8 true_if_encoding; + + unsigned char rx_decode_buf[HDLC_ENG_BUF_LEN]; + unsigned int rx_decode_len; + unsigned char rx_decode_bit_cnt; + unsigned char rx_decode_onecnt; + + unsigned char tx_decode_buf[HDLC_ENG_BUF_LEN]; + unsigned int tx_decode_len; + unsigned char tx_decode_bit_cnt; + unsigned char tx_decode_onecnt; + + unsigned long hdlc_flag; + unsigned short rx_orig_crc; + unsigned short rx_crc[MAX_CRC_QUEUE]; + unsigned short crc_fin; + unsigned short tx_crc_fin; + unsigned short rx_crc_tmp; + unsigned short tx_crc_tmp; + int crc_cur; + int crc_prv; + unsigned short tx_crc; + unsigned char tx_flag; + unsigned char tx_flag_offset; + unsigned char tx_flag_offset_data; + unsigned char tx_flag_idle; + + struct sk_buff_head rx_free_queue; + struct sk_buff_head rx_used_queue; + struct sk_buff_head tx_queue; + + unsigned long time_slot_map; + unsigned int time_slots; + struct sk_buff *rx_skb; + + struct sk_buff *tx_skb; + unsigned long rx_timeout; + unsigned short rx_max_timeout; + + unsigned char tx_idle_flag; + + struct net_device_stats ifstats; + netdevice_t *sw_dev; + unsigned char sw_if_name[WAN_IFNAME_SZ+1]; + unsigned int max_tx_up_size; + unsigned long tq_control; + unsigned char hdlc_eng; + unsigned short max_tx_queue_sz; + unsigned char ignore_modem; + + unsigned int protocol; + unsigned char udp_pkt_data[sizeof(wan_udp_pkt_t)+10]; + atomic_t udp_pkt_len; + unsigned char seven_bit_hdlc; + unsigned char bits_in_byte; + + unsigned char debug_stream; + unsigned char debug_stream_1; + unsigned char debug_char; + + wan_bitstrm_conf_if_t cfg; + + unsigned char rbs_on; + unsigned char rbs_chan; + unsigned char rbs_sig; + + //FIXME: add driver stats as per frame relay! +} bitstrm_private_area_t; + +/* Route Status options */ +#define NO_ROUTE 0x00 +#define ADD_ROUTE 0x01 +#define ROUTE_ADDED 0x02 +#define REMOVE_ROUTE 0x03 + + +/* variable for tracking how many interfaces to open for WANPIPE on the + two ports */ + +extern void disable_irq(unsigned int); +extern void enable_irq(unsigned int); + + +/****** Function Prototypes *************************************************/ +/* WAN link driver entry points. These are called by the WAN router module. */ +static int update (wan_device_t* wandev); +static int new_if (wan_device_t* wandev, netdevice_t* dev, + wanif_conf_t* conf); +static int del_if(wan_device_t *wandev, netdevice_t *dev); + + +/* Network device interface */ +static int if_init (netdevice_t* dev); +static int if_open (netdevice_t* dev); +static int if_close (netdevice_t* dev); +static int if_do_ioctl(netdevice_t *dev, struct ifreq *ifr, int cmd); + +static struct net_device_stats* if_stats (netdevice_t* dev); +static int if_send (struct sk_buff* skb, netdevice_t* dev); + +/* BSTRM Firmware interface functions */ +static int bstrm_configure (sdla_t* card, void* data); +static int bstrm_comm_enable (sdla_t* card); +static int bstrm_read_version (sdla_t* card, char* str); +static int bstrm_set_intr_mode (sdla_t* card, unsigned mode); +static int set_adapter_config (sdla_t* card); +static int bstrm_send (sdla_t* card, void* data, unsigned len, unsigned char flag); +static int bstrm_read_comm_err_stats (sdla_t* card); +static int bstrm_read_op_stats (sdla_t* card); +static int bstrm_error (sdla_t *card, int err, wan_mbox_t *mb); + + +static int bstrm_disable_comm_shutdown (sdla_t *card); +static void if_tx_timeout (netdevice_t *dev); + + +/* Miscellaneous BSTRM Functions */ +static int set_bstrm_config (sdla_t* card); +static void init_bstrm_tx_rx_buff( sdla_t* card); +static int process_bstrm_exception(sdla_t *card); +static int process_global_exception(sdla_t *card); +static int update_comms_stats(sdla_t* card, + bitstrm_private_area_t* bstrm_priv_area); +static void port_set_state (sdla_t *card, int); +static int config_bstrm (sdla_t *card); +static void disable_comm (sdla_t *card); +static int bstrm_comm_disable (sdla_t *card); +static int bstrm_set_FE_config (sdla_t *card); + + +/* Interrupt handlers */ +static void wpbit_isr (sdla_t* card); +static void rx_intr (sdla_t* card); +static void timer_intr(sdla_t *); + + /* Bottom half handlers */ +static void bstrm_rx_bh (unsigned long data); +static void bstrm_tx_bh (unsigned long data); +static int bstrm_bh_cleanup (sdla_t *card, struct sk_buff *skb); +static struct sk_buff * bh_enqueue (sdla_t *card); + + +/* Miscellaneous functions */ +static int intr_test( sdla_t* card); +static int process_udp_mgmt_pkt(sdla_t* card, netdevice_t* dev, + bitstrm_private_area_t* bstrm_priv_area, + char local); + +/* Bitstream decoding functions */ +static void init_crc(void); +static void calc_rx_crc(bitstrm_private_area_t *chan); +static void calc_tx_crc(bitstrm_private_area_t *chan, unsigned char byte); +static void decode_byte (bitstrm_private_area_t *chan, unsigned char *byte); +static void hdlc_decode (bitstrm_private_area_t *chan, unsigned char *buf, int len); +static void tx_up_decode_pkt(bitstrm_private_area_t *chan); + +static void init_rx_hdlc_eng(sdla_t *card, bitstrm_private_area_t *chan, int hard); + +static int hdlc_encode(bitstrm_private_area_t *chan,struct sk_buff **skb); +static void encode_byte (bitstrm_private_area_t *chan, unsigned char *byte, int flag); + +static int bstrm_get_config_info(void* priv, struct seq_file* m, int*); + +static void +wanpipe_switch_datascope_tx_up(bitstrm_private_area_t *chan,struct sk_buff *skb); + + +/* TE1 */ +static WRITE_FRONT_END_REG_T write_front_end_reg; +static READ_FRONT_END_REG_T read_front_end_reg; +static void bstrm_enable_timer (void* card_id); +static void bstrm_handle_front_end_state(void* card_id); +static int bstrm_bh_data_tx_up(sdla_t *card, struct sk_buff *skb, bitstrm_private_area_t * chan); +static void bstrm_switch_send(sdla_t *card, bitstrm_private_area_t * chan, struct sk_buff *skb); +static int bstrm_bind_dev_switch (sdla_t *card, bitstrm_private_area_t *chan, char *sw_dev_name); +static int bstrm_unbind_dev_switch (sdla_t *card, bitstrm_private_area_t *chan); + +static int protocol_init (sdla_t*card,netdevice_t *dev, + bitstrm_private_area_t*chan, + wanif_conf_t* conf); + +static int protocol_stop (sdla_t *card, netdevice_t *dev); +static int protocol_start (sdla_t *card, netdevice_t *dev); +static int protocol_shutdown (sdla_t *card, netdevice_t *dev); + +static void send_ppp_term_request (netdevice_t *dev); + +static int bstrm_set_te_signaling_config (void* card_id,unsigned long ts_sig_map); +static int bstrm_disable_te_signaling (void* card,unsigned long); +static int bstrm_read_te_signaling_config (void* card); + +static int send_rbs_oob_msg (sdla_t *card, bitstrm_private_area_t *chan); + + +#define LINEPROBE +#ifdef LINEPROBE +static int api_enable_comms(sdla_t * card); +static int api_disable_comms(sdla_t* card); +static int setup_api_timeslots(sdla_t* card); +#endif + +const int MagicNums[8] = { 0x1189, 0x2312, 0x4624, 0x8C48, 0x1081, 0x2102, 0x4204, 0x8408 }; +unsigned short CRC_TABLE[256]; +const char FLAG[]={ 0x7E, 0xFC, 0xF9, 0xF3, 0xE7, 0xCF, 0x9F, 0x3F }; +/****** Public Functions ****************************************************/ + +/*============================================================================ + * Cisco HDLC protocol initialization routine. + * + * This routine is called by the main WANPIPE module during setup. At this + * point adapter is completely initialized and firmware is running. + * o read firmware version (to make sure it's alive) + * o configure adapter + * o initialize protocol-specific fields of the adapter data space. + * + * Return: 0 o.k. + * < 0 failure. + */ +int wpbit_init (sdla_t* card, wandev_conf_t* conf) +{ + unsigned char port_num; + int i,err; + struct sk_buff *skb; + unsigned long max_permitted_baud = 0; + unsigned long smp_flags; + + union + { + char str[80]; + } u; + + volatile wan_mbox_t* mb; + wan_mbox_t* mb1; + unsigned long timeout; + + /* Verify configuration ID */ + if (conf->config_id != WANCONFIG_BITSTRM) { + DEBUG_EVENT( "%s: invalid configuration ID %u!\n", + card->devname, conf->config_id); + return -EINVAL; + } + + /* Find out which Port to use */ + if ((conf->comm_port == WANOPT_PRI) || (conf->comm_port == WANOPT_SEC)){ + if (card->next){ + if (conf->comm_port != card->next->u.b.comm_port){ + card->u.b.comm_port = conf->comm_port; + }else{ + DEBUG_EVENT( "%s: ERROR - %s port used!\n", + card->wandev.name, PORT(conf->comm_port)); + return -EINVAL; + } + }else{ + card->u.b.comm_port = conf->comm_port; + } + }else{ + DEBUG_EVENT( "%s: ERROR - Invalid Port Selected!\n", + card->wandev.name); + return -EINVAL; + } + + + /* Initialize protocol-specific fields */ + if (card->type != SDLA_S514){ + + DEBUG_EVENT( "%s: ERROR - T1/E1 Bitstrm doesn't support S508 cards!\n", + card->devname); + return -EOPNOTSUPP; + + }else{ + /* for a S514 adapter, set a pointer to the actual mailbox in the */ + /* allocated virtual memory area */ + if (card->u.b.comm_port == WANOPT_PRI){ + card->mbox_off = PRI_BASE_ADDR_MB_STRUCT; + }else{ + card->mbox_off = SEC_BASE_ADDR_MB_STRUCT; + } + } + + mb = &card->wan_mbox; + mb1 = &card->wan_mbox; + if (!card->configured){ + unsigned char return_code = 0x00; + + /* The board will place an 'I' in the return code to indicate that it is + ready to accept commands. We expect this to be completed in less + than 1 second. */ + + timeout = jiffies; + do { + return_code = 0x00; + card->hw_iface.peek(card->hw, + card->mbox_off+offsetof(wan_mbox_t, wan_return_code), + &return_code, + sizeof(unsigned char)); + if ((jiffies - timeout) > 1*HZ) break; + }while(return_code != 'I'); + if (return_code != 'I') { + DEBUG_EVENT( + "%s: Initialization not completed by adapter\n", + card->devname); + DEBUG_EVENT( "Please contact Sangoma representative.\n"); + return -EIO; + } + } + + card->wandev.ignore_front_end_status = conf->ignore_front_end_status; + + //ALEX_TODAY err=check_conf_hw_mismatch(card,conf->te_cfg.media); + err = (card->hw_iface.check_mismatch) ? + card->hw_iface.check_mismatch(card->hw,conf->fe_cfg.media) : -EINVAL; + if (err){ + return err; + } + + card->u.b.serial=0; + + + if (IS_TE1_MEDIA(&conf->fe_cfg)){ + + memcpy(&card->fe.fe_cfg, &conf->fe_cfg, sizeof(sdla_fe_cfg_t)); + sdla_te_iface_init(&card->wandev.fe_iface); + card->fe.name = card->devname; + card->fe.card = card; + card->fe.write_fe_reg = write_front_end_reg; + card->fe.read_fe_reg = read_front_end_reg; + + card->wandev.fe_enable_timer = bstrm_enable_timer; + card->wandev.te_link_state = bstrm_handle_front_end_state; + + conf->interface = + (IS_T1_CARD(card)) ? WANOPT_V35 : WANOPT_RS232; + + if (card->u.b.comm_port == WANOPT_PRI){ + conf->clocking = WANOPT_EXTERNAL; + } + + if (IS_TE1_UNFRAMED(&card->fe)){ + card->u.b.serial=1; + } + + DEBUG_EVENT("%s: Config Media = %s\n", + card->devname, FE_MEDIA_DECODE(&card->fe)); + + }else if (IS_56K_MEDIA(&conf->fe_cfg)){ + + memcpy(&card->fe.fe_cfg, &conf->fe_cfg, sizeof(sdla_fe_cfg_t)); + sdla_56k_iface_init(&card->wandev.fe_iface); + card->fe.name = card->devname; + card->fe.card = card; + card->fe.write_fe_reg = write_front_end_reg; + card->fe.read_fe_reg = read_front_end_reg; + + if (card->u.c.comm_port == WANOPT_PRI){ + conf->clocking = WANOPT_EXTERNAL; + } + + card->u.b.serial=1; + + DEBUG_EVENT("%s: Config Media = %s\n", + card->devname, FE_MEDIA_DECODE(&card->fe)); + + }else{ + card->u.b.serial=1; + /* FIXME: Remove this line */ + card->fe.fe_status = FE_CONNECTED; + + DEBUG_EVENT("%s: Config Media = Unknown\n", + card->devname); + } + + if (card->u.b.serial){ + DEBUG_EVENT("%s: Configuring Driver for Serial Mode!\n", + card->devname); + } + + /* Read firmware version. Note that when adapter initializes, it + * clears the mailbox, so it may appear that the first command was + * executed successfully when in fact it was merely erased. To work + * around this, we execute the first command twice. + */ + + if (bstrm_read_version(card, u.str)) + return -EIO; + + DEBUG_EVENT( "%s: Running Bit Streaming firmware v%s\n", + card->devname, u.str); + + if (set_adapter_config(card)) { + DEBUG_EVENT( "%s: Failed to set adapter type!\n", + card->devname); + return -EIO; + } + + card->isr = &wpbit_isr; + card->poll = NULL; + card->exec = NULL; + card->wandev.update = &update; + card->wandev.new_if = &new_if; + card->wandev.del_if = &del_if; + card->wandev.udp_port = conf->udp_port; + card->wandev.new_if_cnt = 0; + + // Proc fs functions + card->wandev.get_config_info = &bstrm_get_config_info; + + /* Initialize Bit Stream Configuration */ + memcpy(&card->u.b.cfg,&conf->u.bitstrm,sizeof(wan_bitstrm_conf_t)); + +#if 0 + card->u.b.sync_options = conf->sync_options; + card->u.b.cfg.rx_sync_char = conf->rx_sync_char; + card->u.b.cfg.monosync_tx_time_fill_char = conf->monosync_tx_time_fill_char; + + card->u.b.cfg.max_length_tx_data_block = conf->max_length_tx_data_block; + card->u.b.cfg.rx_complete_length = conf->rx_complete_length; + card->u.b.cfg.rx_complete_timer = conf->rx_complete_timer; +#endif + + /* reset the number of times the 'update()' proc has been called */ + card->u.b.update_call_count = 0; + + card->wandev.ttl = conf->ttl; + card->wandev.interface = conf->interface; + + card->wandev.clocking = conf->clocking; + + port_num = card->u.b.comm_port; + + /* Setup Port Bps */ + if(card->wandev.clocking) { + if(port_num == WANOPT_PRI) { + /* For Primary Port 0 */ + max_permitted_baud = + (card->type == SDLA_S514) ? + PRI_MAX_BAUD_RATE_S514 : + PRI_MAX_BAUD_RATE_S508; + + }else if(port_num == WANOPT_SEC) { + /* For Secondary Port 1 */ + max_permitted_baud = + (card->type == SDLA_S514) ? + SEC_MAX_BAUD_RATE_S514 : + SEC_MAX_BAUD_RATE_S508; + } + + if(conf->bps > max_permitted_baud) { + conf->bps = max_permitted_baud; + DEBUG_EVENT( "%s: Baud too high!\n", + card->wandev.name); + DEBUG_EVENT( "%s: Baud rate set to %lu bps\n", + card->wandev.name, max_permitted_baud); + } + card->wandev.bps = conf->bps; + }else{ + card->wandev.bps = 0; + } + + /* Setup the Port MTU */ + if(port_num == WANOPT_PRI) { + /* For Primary Port 0 */ + card->wandev.mtu = wp_min(conf->mtu, PRI_MAX_LENGTH_TX_DATA_BLOCK); + } else if(port_num == WANOPT_SEC) { + /* For Secondary Port 1 */ + card->wandev.mtu = wp_min(conf->mtu, SEC_MAX_LENGTH_TX_DATA_BLOCK); + } + + /* Set up the interrupt status area */ + /* Read the BSTRM Configuration and obtain: + * Ptr to shared memory infor struct + * Use this pointer to calculate the value of card->u.b.flags ! + */ + mb1->wan_data_len = 0; + mb1->wan_command = READ_BSTRM_CONFIGURATION; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb1); + if(err != OK) { + bstrm_error(card, err, mb1); + return -EIO; + } + + card->flags_off = + (((BSTRM_CONFIGURATION_STRUCT *)mb1->wan_data)-> + ptr_shared_mem_info_struct); + + card->intr_type_off = + card->flags_off + + offsetof(SHARED_MEMORY_INFO_STRUCT, interrupt_info_struct) + + offsetof(INTERRUPT_INFORMATION_STRUCT, interrupt_type); + card->intr_perm_off = + card->flags_off + + offsetof(SHARED_MEMORY_INFO_STRUCT, interrupt_info_struct) + + offsetof(INTERRUPT_INFORMATION_STRUCT, interrupt_permission); + card->fe_status_off = + card->flags_off + + offsetof(SHARED_MEMORY_INFO_STRUCT, FT1_info_struct) + + offsetof(FT1_INFORMATION_STRUCT, parallel_port_A_input); + + card->u.b.rx_discard_off = + card->flags_off + + offsetof(SHARED_MEMORY_INFO_STRUCT, BSTRM_info_struct) + + offsetof(BSTRM_INFORMATION_STRUCT, Rx_discard_count); + + card->u.b.tx_idle_off = + card->flags_off + + offsetof(SHARED_MEMORY_INFO_STRUCT, BSTRM_info_struct) + + offsetof(BSTRM_INFORMATION_STRUCT, Tx_idle_count); + + if (!card->wandev.piggyback){ + int err; + + /* This is for the ports link state */ + card->wandev.state = WAN_DUALPORT; + card->u.b.state = WAN_DISCONNECTED; + + + /* Perform interrupt testing */ + err = intr_test(card); + + if(err || (card->timer_int_enabled == 0 /* MAX_INTR_TEST_COUNTER*/)) { + DEBUG_EVENT( "%s: Interrupt test failed (%i)\n", + card->devname, card->timer_int_enabled); + DEBUG_EVENT( "%s: Please choose another interrupt\n", + card->devname); + return -EIO; + } + DEBUG_EVENT( "%s: Interrupt test passed (%i)\n", + card->devname, card->timer_int_enabled); + card->configured = 1; + } + + /* If we are using BSTRM in backup mode, this flag will + * indicate not to look for IP addresses in config_bstrm()*/ + card->backup = conf->backup; + + DEBUG_EVENT( "%s: Initializing CRC tables\n",card->devname); + init_crc(); + + card->u.b.tq_working=0; + + /* Allocate and initialize BH circular buffer */ + /* Add 1 to MAX_BH_BUFF so we don't have test with (MAX_BH_BUFF-1) */ + skb_queue_head_init(&card->u.b.rx_isr_queue); + skb_queue_head_init(&card->u.b.rx_isr_free_queue); + + memset(card->u.b.time_slot_map,0,sizeof(card->u.b.time_slot_map)); + card->u.b.time_slots=NUM_OF_T1_CHANNELS; + + if (IS_E1_CARD(card)){ + card->u.b.time_slots=NUM_OF_E1_CHANNELS; + } + + if (IS_TE1_MEDIA(&conf->fe_cfg)){ + int tx_time_slots=card->u.b.time_slots; + + if (IS_E1_CARD(card) && !IS_TE1_UNFRAMED(&card->fe) && card->u.b.time_slots == 32){ + tx_time_slots=31; + } + + if (card->u.b.cfg.max_length_tx_data_block % tx_time_slots){ + + DEBUG_EVENT( "\n"); + DEBUG_EVENT( "%s: Cfg max_length_tx_data_block : %d, time_slots: %d\n", + card->devname, + card->u.b.cfg.max_length_tx_data_block, + tx_time_slots); + + card->u.b.cfg.max_length_tx_data_block-= + (card->u.b.cfg.max_length_tx_data_block% + tx_time_slots); + + card->u.b.cfg.max_length_tx_data_block+=tx_time_slots; + +#if 0 + DEBUG_EVENT( "%s: Error: Max tx data block %i not multiple of channels %i\n", + card->devname,card->u.b.cfg.max_length_tx_data_block, + card->u.b.time_slots); + bstrm_skb_queue_purge(&card->u.b.rx_isr_free_queue); + return -EINVAL; +#else + DEBUG_EVENT( "%s: Warning: Adjusting max tx block to %i\n", + card->devname,card->u.b.cfg.max_length_tx_data_block); +#endif + } + + if (card->u.b.cfg.rx_complete_length % card->u.b.time_slots){ + + DEBUG_EVENT( "%s: Cfg rx_complete_length : %d, time_slots: %d\n", + card->devname, + card->u.b.cfg.rx_complete_length, + card->u.b.time_slots); + + card->u.b.cfg.rx_complete_length-= + (card->u.b.cfg.rx_complete_length% + card->u.b.time_slots); + + card->u.b.cfg.rx_complete_length+=card->u.b.time_slots; + DEBUG_EVENT( "%s: Warning: Adjusting max rx block to %i\n", + card->devname,card->u.b.cfg.rx_complete_length); + + } + + + if (card->u.b.cfg.max_length_tx_data_block >= MAX_E1_CHANNELS*50){ + DEBUG_EVENT("%s: Error: Tx data block exceeds max=%i\n", + card->devname,MAX_E1_CHANNELS*50); + return -EINVAL; + } + } + + card->u.b.tx_chan_multiple= + card->u.b.cfg.max_length_tx_data_block/card->u.b.time_slots; + + DEBUG_EVENT( "\n"); + DEBUG_EVENT( "%s: Configuring: \n",card->devname); + if (IS_TE1_CARD(card)){ + DEBUG_EVENT( "%s: ChanNum =%i\n", + card->devname, card->u.b.time_slots); + DEBUG_EVENT( "%s: TxChanMult =%i\n", + card->devname, card->u.b.tx_chan_multiple); + } + DEBUG_EVENT( "%s: TxMTU =%i\n", + card->devname, card->u.b.cfg.max_length_tx_data_block); + DEBUG_EVENT( "%s: RxMTU =%i\n", + card->devname, card->u.b.cfg.rx_complete_length); + DEBUG_EVENT( "%s: IdleFlag =0x%x\n", + card->devname, + card->u.b.cfg.monosync_tx_time_fill_char); + + /* RBS Map only supports 24 T1 channels */ + card->u.b.cfg.rbs_map&=0x00FFFFFF; + + if (IS_T1_CARD(card)){ + + DEBUG_EVENT( "%s: RBS Control =%s Map=0x%08lX\n", + card->devname, + card->u.b.cfg.rbs_map? + "ON":"OFF",card->u.b.cfg.rbs_map); + }else{ + if (card->u.b.cfg.rbs_map){ + DEBUG_EVENT("\n"); + DEBUG_EVENT("%s: Warning: Robbit only supported on T1!\n", + card->devname); + card->u.b.cfg.rbs_map=0; + } + } + + DEBUG_EVENT("\n"); + + /* This is for the ports link state */ + card->wandev.state = WAN_CONNECTING; + card->u.b.state = WAN_DISCONNECTED; + + /* Initialize the task queue */ + tasklet_init(&card->u.b.wanpipe_rx_task, bstrm_rx_bh, (unsigned long)card); + tasklet_init(&card->u.b.wanpipe_tx_task, bstrm_tx_bh, (unsigned long)card); + + for (i=0;i<10;i++){ + skb=dev_alloc_skb(card->u.b.cfg.rx_complete_length+50+sizeof(api_rx_hdr_t)); + if (!skb){ + DEBUG_EVENT( "%s: Failed to allocate rx isr queue mem!\n", + card->devname); + bstrm_skb_queue_purge(&card->u.b.rx_isr_free_queue); + card->wandev.state = WAN_UNCONFIGURED; + return -ENOMEM; + + } + skb_queue_tail(&card->u.b.rx_isr_free_queue,skb); + } + + +#if 0 +//NENAD + { + int x; + card->u.b.tx_scratch_buf_len=1200; + for (x=0;xu.b.tx_scratch_buf_len;x++){ + card->u.b.tx_scratch_buf[x]=0x7E;//(x%32); + } + } +#endif + + + wan_spin_lock_irq(&card->wandev.lock,&smp_flags); + err=config_bstrm(card); + wan_spin_unlock_irq(&card->wandev.lock,&smp_flags); + if (err){ + DEBUG_EVENT( "%s: Failed to configure adapter!\n",card->devname); + disable_comm(card); + + wan_spin_lock_irq(&card->wandev.lock,&smp_flags); + bstrm_skb_queue_purge(&card->u.b.rx_isr_free_queue); + wan_spin_unlock_irq(&card->wandev.lock,&smp_flags); + + card->wandev.state = WAN_UNCONFIGURED; + return err; + } + + + set_bit(SEND_CRIT,&card->wandev.critical); + + card->disable_comm = &disable_comm; + DEBUG_TEST("%s: Config DONE\n",card->devname); + return 0; +} + +/******* WAN Device Driver Entry Points *************************************/ + +/*============================================================================ + * Update device status & statistics + * This procedure is called when updating the PROC file system and returns + * various communications statistics. These statistics are accumulated from 3 + * different locations: + * 1) The 'if_stats' recorded for the device. + * 2) Communication error statistics on the adapter. + * 3) BSTRM operational statistics on the adapter. + * The board level statistics are read during a timer interrupt. Note that we + * read the error and operational statistics during consecitive timer ticks so + * as to minimize the time that we are inside the interrupt handler. + * + */ + +static int update (wan_device_t* wandev) +{ + sdla_t* card = wandev->private; + netdevice_t* dev; + bitstrm_private_area_t* bstrm_priv_area; + //unsigned long smp_flags; + + /* sanity checks */ + if((wandev == NULL) || (wandev->private == NULL)) + return -EFAULT; + + if(wandev->state == WAN_UNCONFIGURED) + return -ENODEV; + + /* more sanity checks */ + if(test_bit(PERI_CRIT, (void*)&card->wandev.critical)) + return -EAGAIN; + + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + if(dev == NULL) + return -ENODEV; + + if((bstrm_priv_area=dev->priv) == NULL) + return -ENODEV; + + if(bstrm_priv_area->update_comms_stats){ + return -EAGAIN; + } + +#if 0 + bstrm_priv_area->ifstats.rx_fifo_errors=0; + bstrm_priv_area->ifstats.rx_frame_errors=0; + bstrm_priv_area->ifstats.tx_carrier_errors=0; + bstrm_priv_area->ifstats.rx_bytes=0; + bstrm_priv_area->ifstats.tx_bytes=0; + bstrm_priv_area->ifstats.rx_packets=0; + bstrm_priv_area->ifstats.tx_packets=0; + bstrm_priv_area->ifstats.tx_fifo_errors=0; +#endif + +#if 1 + DEBUG_EVENT( "%s:%s: Tx B=%i: Rx U=%i: Rx F=%i: Rx-U-BH=%i Rx-F-Bh=%i Idle 0x%x\n", + card->devname, + dev->name, + skb_queue_len(&bstrm_priv_area->tx_queue), + skb_queue_len(&bstrm_priv_area->rx_used_queue), + skb_queue_len(&bstrm_priv_area->rx_free_queue), + skb_queue_len(&card->u.b.rx_isr_queue), + skb_queue_len(&card->u.b.rx_isr_free_queue), + bstrm_priv_area->tx_idle_flag); +#endif +#if 0 + DEBUG_EVENT( "%s: Tx Data = %i Rx Data = %i\n", + card->devname, atomic_read(&tx_data),atomic_read(&rx_data)); + + + DEBUG_EVENT( "%s: Sw Dev = %s\n", + bstrm_priv_area->if_name, + bstrm_priv_area->sw_dev ? + bstrm_priv_area->sw_dev->name : "None"); + DEBUG_EVENT( "%s: ISR=%li Rx=%li Tx=%li RxBh=%li RxBhBsy=%li\n", + card->devname, + card->statistics.isr_entry, + card->statistics.isr_rx, + card->statistics.isr_tx, + card->statistics.poll_entry, + card->statistics.poll_tbusy_bad_status); +#endif + +#if 0 + if (bstrm_priv_area->common.usedby == SWITCH && bstrm_priv_area->sw_dev){ + bitstrm_private_area_t *sw_chan= + (bitstrm_private_area_t *)bstrm_priv_area->sw_dev->priv; + sdla_t *sw_card=sw_chan->card; + + DEBUG_EVENT( "SWITCH DIFF: ISR=%li Rx=%li Tx=%li RxBh=%li\n", + card->statistics.isr_entry-sw_card->statistics.isr_entry, + card->statistics.isr_rx-sw_card->statistics.isr_rx, + card->statistics.isr_tx-sw_card->statistics.isr_tx, + card->statistics.poll_entry-sw_card->statistics.poll_entry); + } + + DEBUG_TEST("%s: Intr cnt %i Intr skip %i Irq Equalize %i ISR SKIP=0x%x\n", + card->devname, + atomic_read(&intr_cnt), + atomic_read(&intr_skip), + card->irq_equalize, + card->u.b.wait_for_buffers); + DEBUG_EVENT( "\n"); + +#endif + +#if 0 + /* TE1 Change the update_comms_stats variable to 3, + * only for T1/E1 card, otherwise 2 for regular + * S514/S508 card. + * Each timer interrupt will update only one type + * of statistics. + */ + bstrm_priv_area->update_comms_stats = + (IS_TE1_CARD(card) || IS_56K_CARD(card)) ? 3 : 2; + + wan_spin_lock_irq(&card->wandev.lock,&smp_flags); + if (test_bit(0,&card->in_isr)){ + wan_spin_unlock_irq(&card->wandev.lock,&smp_flags); + return -EBUSY; + } + update_comms_stats(card, bstrm_priv_area); + bstrm_priv_area->update_comms_stats--; + update_comms_stats(card, bstrm_priv_area); + bstrm_priv_area->update_comms_stats--; + update_comms_stats(card, bstrm_priv_area); + bstrm_priv_area->update_comms_stats--; + + wan_spin_unlock_irq(&card->wandev.lock,&smp_flags); +#endif + return 0; +} + + +/*============================================================================ + * Create new logical channel. + * This routine is called by the router when ROUTER_IFNEW IOCTL is being + * handled. + * o parse media- and hardware-specific configuration + * o make sure that a new channel can be created + * o allocate resources, if necessary + * o prepare network device structure for registaration. + * + * Return: 0 o.k. + * < 0 failure (channel will not be created) + */ +static int new_if (wan_device_t* wandev, netdevice_t* dev, wanif_conf_t* conf) +{ + int i; + struct sk_buff *skb; + sdla_t* card = wandev->private; + bitstrm_private_area_t* bstrm_priv_area; + unsigned long smp_flags; + int err=0; + + DEBUG_EVENT( "%s: Configuring Interface: %s\n", + card->devname, conf->name); + + if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) { + DEBUG_EVENT( "%s: Invalid interface name!\n", + card->devname); + return -EINVAL; + } + + if (card->u.b.serial && card->wandev.new_if_cnt){ + DEBUG_EVENT( "%s: Error: multipe interfaces are only allowed on T1/E1 cards!\n", + card->devname); + return -EEXIST; + } + + /* allocate and initialize private data */ + bstrm_priv_area = kmalloc(sizeof(bitstrm_private_area_t), GFP_KERNEL); + + if(bstrm_priv_area == NULL) + return -ENOMEM; + + memset(bstrm_priv_area, 0, sizeof(bitstrm_private_area_t)); + + memcpy(&bstrm_priv_area->cfg, &conf->u.bitstrm, sizeof(wan_bitstrm_conf_if_t)); + + bstrm_priv_area->card = card; + + bstrm_priv_area->common.sk=NULL; + bstrm_priv_area->common.state = WAN_DISCONNECTED; + bstrm_priv_area->common.dev = dev; + + bstrm_priv_area->common.config_id=card->wandev.config_id; + + bstrm_priv_area->debug_stream=0; + bstrm_priv_area->debug_char=0xFF; + + /* Initialize circular buffers for each interface + * and allocate skb buffers. This must be done first + * because the new_if_error, tries to purge the + * rx_free_queue. + * + * THUS: DO NOT GO TO new_if_error ABOVE HERE ! + */ + + skb_queue_head_init(&bstrm_priv_area->rx_free_queue); + skb_queue_head_init(&bstrm_priv_area->rx_used_queue); + skb_queue_head_init(&bstrm_priv_area->tx_queue); + + /* initialize interface name */ + strcpy(bstrm_priv_area->if_name, conf->name); + + for (i=0;irx_free_queue,skb); + } + + /* Obtain a free skb buffer that will be used to construct + * a bitstream */ + bstrm_priv_area->rx_skb=skb_dequeue(&bstrm_priv_area->rx_free_queue); + if (!bstrm_priv_area->rx_skb){ + /* Santiy check this should never happen because + * we just allocated it */ + err=-ENOMEM; + goto new_if_error; + } + + + if (IS_TE1_CARD(card)){ + + /* Channel definition section. If not channels defined + * return error */ + + if (IS_E1_CARD(card) && !IS_TE1_UNFRAMED(&card->fe)){ + conf->active_ch=conf->active_ch&0x7FFFFFFF; + } + + if ((bstrm_priv_area->time_slot_map=conf->active_ch) == 0){ + DEBUG_EVENT( "%s: Invalid Channel Selection 0x%lX\n", + card->devname,bstrm_priv_area->time_slot_map); + err=-EINVAL; + goto new_if_error; + } + + DEBUG_EVENT( "%s: %s: Iface cfg channels = 0x%08lX\n", + card->devname,conf->name,bstrm_priv_area->time_slot_map); + + + /* Default the max_tx_up_size */ + bstrm_priv_area->max_tx_up_size=MAX_T1_CHAN_TX_UP_SIZE; + if (IS_E1_CARD(card)){ + if (IS_TE1_UNFRAMED(&card->fe)){ + bstrm_priv_area->max_tx_up_size=MAX_E1_UNFRM_CHAN_TX_UP_SIZE; + }else{ + bstrm_priv_area->max_tx_up_size=MAX_E1_CHAN_TX_UP_SIZE; + } + } + + + /* If user defined value exists, us it */ + if (bstrm_priv_area->cfg.max_tx_up_size){ + bstrm_priv_area->max_tx_up_size=bstrm_priv_area->cfg.max_tx_up_size; + } + + for (i=0;iu.b.time_slots;i++){ + if (test_bit(i,&bstrm_priv_area->time_slot_map)){ + bstrm_priv_area->time_slots++; + } + } + + if (bstrm_priv_area->max_tx_up_size % bstrm_priv_area->time_slots){ + bstrm_priv_area->max_tx_up_size-= + bstrm_priv_area->max_tx_up_size % + bstrm_priv_area->time_slots; + bstrm_priv_area->max_tx_up_size+=bstrm_priv_area->time_slots; + } + + }else{ + bstrm_priv_area->max_tx_up_size=MAX_T1_CHAN_TX_UP_SIZE; + if (bstrm_priv_area->cfg.max_tx_up_size){ + bstrm_priv_area->max_tx_up_size=bstrm_priv_area->cfg.max_tx_up_size; + } + } + + bstrm_priv_area->rx_max_timeout=HZ; + bstrm_priv_area->rx_timeout=jiffies; + bstrm_priv_area->tx_idle_flag=card->u.b.cfg.monosync_tx_time_fill_char; + + bstrm_priv_area->hdlc_eng=conf->hdlc_streaming; + bstrm_priv_area->bits_in_byte=BITSINBYTE; + if (bstrm_priv_area->hdlc_eng){ + bstrm_priv_area->tx_idle_flag=0x7E; + bstrm_priv_area->seven_bit_hdlc = bstrm_priv_area->cfg.seven_bit_hdlc; + if (bstrm_priv_area->seven_bit_hdlc){ + bstrm_priv_area->bits_in_byte = 7; + } + } + + bstrm_priv_area->max_tx_queue_sz=MAX_TX_QUEUE_SIZE; + if (bstrm_priv_area->cfg.max_tx_queue_size){ + bstrm_priv_area->max_tx_queue_sz=bstrm_priv_area->cfg.max_tx_queue_size; + } + + /* Setup wanpipe as a router (WANPIPE) or as an API */ + if( strcmp(conf->usedby, "WANPIPE") == 0) { + + bstrm_priv_area->protocol=conf->protocol; + bstrm_priv_area->common.usedby=WANPIPE; + bstrm_priv_area->hdlc_eng=1; + bstrm_priv_area->tx_idle_flag=0x7E; + + DEBUG_EVENT( "%s: Running in WANPIPE mode !\n", + wandev->name); + + if (conf->protocol != WANOPT_NO){ + dev->priv=bstrm_priv_area; + if ((err=protocol_init(card,dev,bstrm_priv_area,conf)) != 0){ + goto new_if_error; + } + + if (conf->ignore_dcd == WANOPT_YES || conf->ignore_cts == WANOPT_YES){ + DEBUG_EVENT( "%s: Ignore modem changes DCD/CTS\n",card->devname); + bstrm_priv_area->ignore_modem=1; + }else{ + DEBUG_EVENT( "%s: Restart protocol on modem changes DCD/CTS\n", + card->devname); + } + } + + } else if( strcmp(conf->usedby, "API") == 0) { + bstrm_priv_area->common.usedby=API; + bstrm_priv_area->protocol=0; + DEBUG_EVENT( "%s: Running in API mode !\n", + wandev->name); + + } else if( strcmp(conf->usedby, "STACK") == 0) { + bstrm_priv_area->common.usedby=STACK; + bstrm_priv_area->protocol=0; + DEBUG_EVENT( "%s: Running in STACK mode !\n", + wandev->name); + + } else if( strcmp(conf->usedby, "SWITCH") == 0) { + bstrm_priv_area->common.usedby=SWITCH; + bstrm_priv_area->protocol=0; + DEBUG_EVENT( "%s: Running in SWITCH mode !\n", + wandev->name); + +#if 1 + if (card->u.b.cfg.rx_complete_length != card->u.b.cfg.max_length_tx_data_block){ + DEBUG_EVENT( "%s: Config Error: SWITCH tx and rx data size must be equal! (Tx=%i != Rx=%i)\n", + card->devname, + card->u.b.cfg.max_length_tx_data_block, + card->u.b.cfg.rx_complete_length); + err=-EINVAL; + goto new_if_error; + } + + bstrm_priv_area->max_tx_up_size=card->u.b.cfg.rx_complete_length; +#endif + + set_bit(WAIT_DEVICE_BUFFERS,&bstrm_priv_area->tq_control); + + }else{ + DEBUG_EVENT( "%s: Error, Invalid operation mode, API only!\n", + wandev->name); + + err=-EINVAL; + goto new_if_error; + } + + /* prepare network device data space for registration */ + + dev->init = &if_init; + dev->priv = bstrm_priv_area; + bstrm_priv_area->common.dev = dev; + + bstrm_priv_area->hdlc_flag=0; + set_bit(NO_FLAG,&bstrm_priv_area->hdlc_flag); + DEBUG_EVENT( "\n"); + + bstrm_priv_area->rx_crc[0]=-1; + bstrm_priv_area->rx_crc[1]=-1; + bstrm_priv_area->rx_crc[2]=-1; + bstrm_priv_area->tx_crc=-1; + bstrm_priv_area->tx_flag= 0x7E; //card->u.b.cfg.monosync_tx_time_fill_char; + bstrm_priv_area->tx_flag_idle= 0x7E; //card->u.b.cfg.monosync_tx_time_fill_char; + + if (bstrm_priv_area->common.usedby == SWITCH){ + strncpy(bstrm_priv_area->sw_if_name,conf->sw_dev_name,WAN_IFNAME_SZ); + } + + if (IS_TE1_CARD(card)){ + /* Check that the time slot is not being used. If it is + * stop the interface setup. Notice, though we proceed + * to check for all timeslots before we start binding + * the channels in. This way, we don't have to go back + * and clean the time_slot_map */ + for (i=0;iu.b.time_slots;i++){ + if (test_bit(i,&bstrm_priv_area->time_slot_map)){ + + DEBUG_CFG( "Configuring %s for timeslot %i\n", + conf->name, i+1); + + bstrm_priv_area->rbs_chan=i+1; + + if (IS_T1_CARD(card)){ + if (test_bit(i,&card->u.b.cfg.rbs_map)){ + bstrm_priv_area->rbs_on=1; + } + } + + if (IS_E1_CARD(card)){ + if (card->u.b.time_slot_map[i+1]){ + DEBUG_EVENT( "%s: Channel/Time Slot resource conflict!\n", + card->devname); + DEBUG_EVENT( "%s: %s: Channel %i, aready in use!\n", + card->devname,dev->name,(i+1)); + + err=-EEXIST; + goto new_if_error; + } + }else{ + if (card->u.b.time_slot_map[i]){ + DEBUG_EVENT( "%s: Channel/Time Slot resource conflict!\n", + card->devname); + DEBUG_EVENT( "%s: %s: Channel %i, aready in use!\n", + card->devname,dev->name,(i+1)); + + err=-EEXIST; + goto new_if_error; + } + } + } + } + + + if (bstrm_priv_area->rbs_on){ + if (bstrm_priv_area->time_slots > 1){ + DEBUG_EVENT("%s:%s: Error: Interface with multiple timeslots %i!\n", + card->devname,bstrm_priv_area->if_name, + bstrm_priv_area->time_slots); + DEBUG_EVENT("%s:%s: Configured for Robbit Signalling!!!\n", + card->devname,bstrm_priv_area->if_name); + DEBUG_EVENT("%s:%s: Config for single timeslot per iface!\n", + card->devname,bstrm_priv_area->if_name); + DEBUG_EVENT("\n"); + err = -EINVAL; + goto new_if_error; + } + + if (bstrm_priv_area->hdlc_eng && !bstrm_priv_area->seven_bit_hdlc){ + DEBUG_EVENT("%s:%s: Warning: Forcing hdlc eng to 7bit hdlc, rbs on!\n", + card->devname,bstrm_priv_area->if_name); + bstrm_priv_area->seven_bit_hdlc=1; + } + } + + /* WARNING: The new_if() function should not fail + * After this point */ + + wan_spin_lock_irq(&card->wandev.lock,&smp_flags); + /*Bind an interface to a time slot map. The resource + * check was done above. We need to lock this area because + * the tx isr and rx bottom half are running */ + for (i=0;iu.b.time_slots;i++){ + if (test_bit(i,&bstrm_priv_area->time_slot_map)){ + if (IS_E1_CARD(card)){ + card->u.b.time_slot_map[i+1] = bstrm_priv_area; + }else{ + card->u.b.time_slot_map[i] = bstrm_priv_area; + } + } + } + wan_spin_unlock_irq(&card->wandev.lock,&smp_flags); + + } + + DEBUG_EVENT( "\n"); + DEBUG_EVENT( "%s: Configuring %s: \n", + card->devname, + bstrm_priv_area->if_name); + + if (IS_TE1_CARD(card)){ + DEBUG_EVENT( "%s: TimeSlot Bind Map =0x%08lX\n", + card->devname, + bstrm_priv_area->time_slot_map); + } + DEBUG_EVENT( "%s: Tx Idle Flag =0x%X\n", + card->devname, + bstrm_priv_area->tx_idle_flag); + + DEBUG_EVENT( "%s: Max Tx Queue Size =%d\n", + card->devname, + bstrm_priv_area->max_tx_queue_sz); + + if (IS_TE1_CARD(card)){ + DEBUG_EVENT( "%s: Max Tx Up Size =%i\n", + card->devname, + bstrm_priv_area->max_tx_up_size); + } + + DEBUG_EVENT( "%s: HDLC Engine =%s Bits=%d\n", + card->devname, + bstrm_priv_area->hdlc_eng?"ON":"OFF", + bstrm_priv_area->seven_bit_hdlc?7:8); + + DEBUG_EVENT( "\n"); + + card->wandev.new_if_cnt++; + + return 0; + +new_if_error: + + if (bstrm_priv_area){ + bstrm_skb_queue_purge(&bstrm_priv_area->rx_free_queue); + + if (bstrm_priv_area->rx_skb){ + dev_kfree_skb_any(bstrm_priv_area->rx_skb); + bstrm_priv_area->rx_skb=NULL; + } + + protocol_shutdown(card,dev); + + bstrm_priv_area->common.dev=NULL; + kfree(bstrm_priv_area); + } + + dev->priv=NULL; + + return err; +} + +/*============================================================================ + * Delete logical channel. + */ +static int del_if (wan_device_t* wandev, netdevice_t* dev) +{ + bitstrm_private_area_t* bstrm_priv_area = dev->priv; + sdla_t *card = wandev->private; + int i; + unsigned long smp_flags; + + if (!bstrm_priv_area){ + return 0; + } + + wan_spin_lock_irq(&card->wandev.lock, &smp_flags); + + if (test_bit(0,&card->in_isr)){ + DEBUG_EVENT( "%s: Del if critical with ISR\n", + card->devname); + } + + if (IS_TE1_CARD(card)){ + /* Un Bind an interface to a time slot map */ + for (i=0;iu.b.time_slots;i++){ + if (test_bit(i,&bstrm_priv_area->time_slot_map)){ + if (IS_E1_CARD(card)){ + card->u.b.time_slot_map[i+1] = NULL; + }else{ + card->u.b.time_slot_map[i] = NULL; + } + } + } + } + if (bstrm_priv_area->rx_skb){ + dev_kfree_skb_any(bstrm_priv_area->rx_skb); + bstrm_priv_area->rx_skb=NULL; + } + + if (bstrm_priv_area->tx_skb){ + dev_kfree_skb_any(bstrm_priv_area->tx_skb); + bstrm_priv_area->tx_skb=NULL; + } + + bstrm_skb_queue_purge(&bstrm_priv_area->tx_queue); + bstrm_skb_queue_purge(&bstrm_priv_area->rx_free_queue); + bstrm_skb_queue_purge(&bstrm_priv_area->rx_used_queue); + + wan_spin_unlock_irq(&card->wandev.lock, &smp_flags); + + protocol_shutdown(card,dev); + + card->wandev.new_if_cnt--; + + return 0; +} + +/****** Network Device Interface ********************************************/ + +/*============================================================================ + * Initialize Linux network interface. + * + * This routine is called only once for each interface, during Linux network + * interface registration. Returning anything but zero will fail interface + * registration. + */ +static int if_init (netdevice_t* dev) +{ + bitstrm_private_area_t* bstrm_priv_area = dev->priv; + sdla_t* card = bstrm_priv_area->card; + wan_device_t* wandev = &card->wandev; + + /* Initialize device driver entry points */ + dev->open = &if_open; + dev->stop = &if_close; + dev->hard_start_xmit = &if_send; + dev->get_stats = &if_stats; +#if defined(LINUX_2_4)||defined(LINUX_2_6) + dev->tx_timeout = &if_tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; +#endif + dev->do_ioctl = &if_do_ioctl; + + /* Initialize media-specific parameters */ + if (!bstrm_priv_area->protocol){ + dev->flags |= IFF_POINTOPOINT; + dev->flags |= IFF_NOARP; + } + + /* Enable Mulitcasting if user selected */ + if (!bstrm_priv_area->protocol && bstrm_priv_area->mc == WANOPT_YES){ + dev->flags |= IFF_MULTICAST; + } + + if (!bstrm_priv_area->protocol){ + dev->type = ARPHRD_PPP; + } + + if (bstrm_priv_area->common.usedby == SWITCH){ + dev->mtu = card->u.b.cfg.max_length_tx_data_block; + }else{ + if (!bstrm_priv_area->protocol){ + dev->mtu = card->wandev.mtu; + } + } + + /* for API usage, add the API header size to the requested MTU size */ + if(bstrm_priv_area->common.usedby == API) { + dev->mtu += sizeof(api_tx_hdr_t); + } + + if (!bstrm_priv_area->protocol){ + dev->hard_header_len = 0; + } + + /* Initialize hardware parameters */ + dev->irq = wandev->irq; + dev->dma = wandev->dma; + dev->base_addr = wandev->ioport; + card->hw_iface.getcfg(card->hw, SDLA_MEMBASE, &dev->mem_start); //ALEX_TODAY wandev->maddr; + card->hw_iface.getcfg(card->hw, SDLA_MEMEND, &dev->mem_end); //ALEX_TODAY wandev->maddr + wandev->msize - 1; + + /* Set transmit buffer queue length + * If too low packets will not be retransmitted + * by stack. + */ + dev->tx_queue_len = 100; + + return 0; +} + + + +/** + * if_do_ioctl - Ioctl handler for fr + * @dev: Device subject to ioctl + * @ifr: Interface request block from the user + * @cmd: Command that is being issued + * + * This function handles the ioctls that may be issued by the user + * to control the settings of a FR. It does both busy + * and security checks. This function is intended to be wrapped by + * callers who wish to add additional ioctl calls of their own. + */ +/* SNMP */ +static int if_do_ioctl(netdevice_t *dev, struct ifreq *ifr, int cmd) +{ + bitstrm_private_area_t* chan= (bitstrm_private_area_t*)dev->priv; + unsigned long smp_flags; + sdla_t *card; + wan_udp_pkt_t *wan_udp_pkt; + int err=0; + custom_control_call_t custom_control_pkt; + + if (!chan){ + return -ENODEV; + } + card=chan->card; + + NET_ADMIN_CHECK(); + + switch(cmd) + { + + case SIOC_WANPIPE_GET_TIME_SLOTS: + err=card->u.b.time_slots; + break; + + case SIOC_WANPIPE_GET_MEDIA_TYPE: + err=card->fe.fe_cfg.media; + break; + + case SIOC_WANPIPE_BIND_SK: + + if (!ifr){ + err= -EINVAL; + break; + } + + spin_lock_irqsave(&card->wandev.lock,smp_flags); + err=wan_bind_api_to_svc(chan,ifr->ifr_data); + spin_unlock_irqrestore(&card->wandev.lock,smp_flags); + + if (!err){ + chan->ifstats.tx_fifo_errors=0; + chan->ifstats.rx_errors=0; + } + break; + + case SIOC_WANPIPE_UNBIND_SK: + + if (!ifr){ + err= -EINVAL; + break; + } + + spin_lock_irqsave(&card->wandev.lock,smp_flags); + err=wan_unbind_api_from_svc(chan,ifr->ifr_data); + spin_unlock_irqrestore(&card->wandev.lock,smp_flags); + + if (chan->hdlc_eng){ + init_rx_hdlc_eng(card,chan,1); + } + break; + + case SIOC_WANPIPE_CHECK_TX: + case SIOC_ANNEXG_CHECK_TX: + err=0; + break; + + case SIOC_WANPIPE_DEV_STATE: + err = chan->common.state; + break; + + case SIOC_ANNEXG_KICK: + err=0; + break; + + + case SIOC_WANPIPE_BITSTRM_T1E1_CFG: + + DEBUG_DBG("%s: SIOC_WANPIPE_BITSTRM_T1E1_CFG\n", card->devname); + + if (card->comm_enabled){ + spin_lock_irqsave(&card->wandev.lock, smp_flags); + bstrm_disable_comm_shutdown (card); + spin_unlock_irqrestore(&card->wandev.lock, smp_flags); + } + + if (copy_from_user(&card->fe.fe_cfg,ifr->ifr_data,sizeof(sdla_fe_cfg_t))){ + DEBUG_EVENT("%s: Error: Failed to copy from user in ioctl()\n", + card->devname); + return -EFAULT; + } + + spin_lock_irqsave(&card->wandev.lock, smp_flags); + + if (IS_TE1_CARD(card)) { + + DEBUG_DBG("%s: (IOCTL) for %s selecting : \n", + card->devname, + (IS_T1_CARD(card))?"T1":"E1"); + + if(IS_T1_CARD(card)){ + + DEBUG_DBG("INTERFACE_LEVEL_V35\n"); + + card->wandev.interface = WANOPT_V35; + card->u.b.cfg.rx_complete_length = 720; + card->u.b.cfg.max_length_tx_data_block = 720; + card->u.b.time_slots = NO_ACTIVE_RX_TIME_SLOTS_T1; + }else{ + DEBUG_DBG("INTERFACE_LEVEL_RS232\n"); + + card->wandev.interface = WANOPT_RS232; + //Must be less than original 720, because + //default .conf file is for T1. + //It is max len which can be pushed into + //the "pre allocated" sock buff. + card->u.b.cfg.rx_complete_length = 704; //divisible by 32 + card->u.b.cfg.max_length_tx_data_block = 682;//divisible by 31 + card->u.b.time_slots = NO_ACTIVE_RX_TIME_SLOTS_E1; + } + if (card->wandev.fe_iface.unconfig){ + card->wandev.fe_iface.unconfig(&card->fe); + } + } + + err=config_bstrm(card); + spin_unlock_irqrestore(&card->wandev.lock, smp_flags); + + return err; + + case SIOC_CUSTOM_BITSTRM_COMMANDS: + + DEBUG_DBG("SIOC_CUSTOM_BITSTRM_COMMANDS\n"); + + if(copy_from_user(&custom_control_pkt, ifr->ifr_data, sizeof(custom_control_call_t)) ){ + return -EFAULT; + } + + switch(custom_control_pkt.control_code) { + + case SET_BIT_IN_PMC_REGISTER: + + if (IS_TE1_CARD(card)){ + unsigned char val = 0; + unsigned char new_val; + + val = read_front_end_reg(card, custom_control_pkt.reg); + + DEBUG_DBG("%s: read val : 0x%02X\n", card->devname, val); + + new_val = val | (0x01 << custom_control_pkt.bit_number); + + err = write_front_end_reg(card, custom_control_pkt.reg, new_val); + + if(err){ + printk( KERN_INFO + "%s:SET_BIT_IN_PMC_REGISTER command failed! err : 0x%02X\n", + card->devname, err); + } + + val = read_front_end_reg(card, custom_control_pkt.reg); + + DEBUG_DBG("%s: read val after OR : 0x%02X\n", card->devname, val); + + }else{ + DEBUG_EVENT( + "%s:SET_BIT_IN_PMC_REGISTER command is invalid for the card type!\n", + card->devname); + err = 1; + } + break; + + case RESET_BIT_IN_PMC_REGISTER: + + if (IS_TE1_CARD(card)){ + unsigned char val = 0; + unsigned char new_val; + + val = read_front_end_reg(card, custom_control_pkt.reg); + + new_val = val &= (~(0x01 << custom_control_pkt.bit_number)); + + err = write_front_end_reg(card, custom_control_pkt.reg, new_val); + + if(err){ + DEBUG_EVENT( + "%s:RESET_BIT_IN_PMC_REGISTER command failed! err : 0x%02X\n", + card->devname, err); + } + }else{ + DEBUG_EVENT( + "%s:RESET_BIT_IN_PMC_REGISTER command is invalid for the card type!\n", + card->devname); + err = 1; + } + + break; + } + + return err; + + case SIOC_WANPIPE_PIPEMON: + + if (atomic_read(&chan->udp_pkt_len) != 0){ + return -EBUSY; + } + + atomic_set(&chan->udp_pkt_len,MAX_LGTH_UDP_MGNT_PKT); + + /* For performance reasons test the critical + * here before spin lock */ + if (test_bit(0,&card->in_isr)){ + atomic_set(&chan->udp_pkt_len,0); + return -EBUSY; + } + + + wan_udp_pkt=(wan_udp_pkt_t*)chan->udp_pkt_data; + if (copy_from_user(&wan_udp_pkt->wan_udp_hdr,ifr->ifr_data,sizeof(wan_udp_hdr_t))){ + atomic_set(&chan->udp_pkt_len,0); + return -EFAULT; + } + + spin_lock_irqsave(&card->wandev.lock, smp_flags); + + /* We have to check here again because we don't know + * what happened during spin_lock */ + if (test_bit(0,&card->in_isr)) { + DEBUG_EVENT( "%s:%s Pipemon command failed, Driver busy: try again.\n", + card->devname,dev->name); + atomic_set(&chan->udp_pkt_len,0); + spin_unlock_irqrestore(&card->wandev.lock, smp_flags); + return -EBUSY; + } + + process_udp_mgmt_pkt(card,dev,chan,1); + + spin_unlock_irqrestore(&card->wandev.lock, smp_flags); + + /* This area will still be critical to other + * PIPEMON commands due to udp_pkt_len + * thus we can release the irq */ + + if (atomic_read(&chan->udp_pkt_len) > sizeof(wan_udp_pkt_t)){ + DEBUG_EVENT( "%s: Error: Pipemon buf too bit on the way up! %i\n", + card->devname,atomic_read(&chan->udp_pkt_len)); + atomic_set(&chan->udp_pkt_len,0); + return -EINVAL; + } + + if (copy_to_user(ifr->ifr_data,&wan_udp_pkt->wan_udp_hdr,sizeof(wan_udp_hdr_t))){ + atomic_set(&chan->udp_pkt_len,0); + return -EFAULT; + } + + atomic_set(&chan->udp_pkt_len,0); + return 0; + + case SIOC_WRITE_RBS_SIG: + { + unsigned char abcd_bits; + + if (!chan->rbs_on){ + DEBUG_EVENT("%s: Error: Write RBS bits signalling turned off!\n", + chan->if_name); + return -EINVAL; + } + + if (copy_from_user(&abcd_bits,ifr->ifr_data,1)){ + return -EFAULT; + } + + card->wandev.fe_iface.set_rbsbits( + &card->fe, + chan->rbs_chan, + abcd_bits); + err=0; + } + break; + + case SIOC_READ_RBS_SIG: + + if (!chan->rbs_on){ + DEBUG_EVENT("%s: Error: Write RBS bits signalling turned off!\n", + chan->if_name); + return -EINVAL; + } + + + if (copy_to_user(ifr->ifr_data,&chan->rbs_sig,1)){ + return -EFAULT; + } + + err=0; + break; + + default: + if (chan->protocol == WANCONFIG_PPP || + chan->protocol == WANCONFIG_CHDLC){ + return wp_sppp_do_ioctl(dev,ifr,cmd); + } + return -EOPNOTSUPP; + } + return err; +} + +/*============================================================================ + * Open network interface. + * o enable communications and interrupts. + * o prevent module from unloading by incrementing use count + * + * Return 0 if O.k. or errno. + */ +static int if_open (netdevice_t* dev) +{ + bitstrm_private_area_t* bstrm_priv_area = dev->priv; + sdla_t* card = bstrm_priv_area->card; + struct timeval tv; + int err = 0; + + /* Only one open per interface is allowed */ + + if (open_dev_check(dev)) + return -EBUSY; + + do_gettimeofday(&tv); + bstrm_priv_area->router_start_time = tv.tv_sec; + + netif_start_queue(dev); + + protocol_start(card,dev); + + if (bstrm_priv_area->common.usedby == SWITCH){ + int err; + err=bstrm_bind_dev_switch(card,bstrm_priv_area,bstrm_priv_area->sw_if_name); + if (err){ + DEBUG_EVENT( "%s: Error: Device %s failed to bind to %s\n", + card->devname,bstrm_priv_area->if_name, + bstrm_priv_area->sw_if_name); + + return err; + }else{ + bitstrm_private_area_t *sw_chan; + sdla_t *sw_card; + + if (bstrm_priv_area->sw_dev && + bstrm_priv_area->common.state != WAN_CONNECTED){ + + sw_chan=(bitstrm_private_area_t *)bstrm_priv_area->sw_dev->priv; + sw_card=sw_chan->card; + + if (!sw_card->comm_enabled || !card->comm_enabled){ + DEBUG_EVENT( "%s: Switch not connected: %s \n", + bstrm_priv_area->common.dev->name, + bstrm_priv_area->sw_dev->name); + }else{ + unsigned long smp_flags; + DEBUG_EVENT( "%s: Setting switch to connected %s\n", + bstrm_priv_area->common.dev->name, + bstrm_priv_area->sw_dev->name); + + wan_spin_lock_irq(&card->wandev.lock,&smp_flags); + sw_chan->common.state = WAN_CONNECTED; + bstrm_priv_area->common.state=WAN_CONNECTED; + + set_bit(WAIT_DEVICE_BUFFERS,&bstrm_priv_area->tq_control); + set_bit(WAIT_DEVICE_BUFFERS,&sw_chan->tq_control); + + wan_spin_unlock_irq(&card->wandev.lock,&smp_flags); + } + } + } + }else{ + bstrm_priv_area->common.state=card->wandev.state; + DEBUG_EVENT( "%s: Interface %s: %s\n", + card->devname, + dev->name, + STATE_DECODE(bstrm_priv_area->common.state)); + } + + wanpipe_open(card); + + return err; +} + +/*============================================================================ + * Close network interface. + * o if this is the last close, then disable communications and interrupts. + * o reset flags. + */ + + +static int if_close (netdevice_t* dev) +{ + bitstrm_private_area_t* bstrm_priv_area = dev->priv; + sdla_t* card = bstrm_priv_area->card; + unsigned long smp_flags; + + stop_net_queue(dev); + + protocol_stop(card,dev); + + if (bstrm_priv_area->common.usedby == SWITCH){ + wan_spin_lock_irq(&card->wandev.lock,&smp_flags); + bstrm_unbind_dev_switch(card,bstrm_priv_area); + wan_spin_unlock_irq(&card->wandev.lock,&smp_flags); + } + + bstrm_priv_area->common.state=WAN_DISCONNECTED; + wan_spin_lock_irq(&card->wandev.lock,&smp_flags); + wan_update_api_state(bstrm_priv_area); + wan_unbind_api_from_svc(bstrm_priv_area,bstrm_priv_area->common.sk); + wan_spin_unlock_irq(&card->wandev.lock,&smp_flags); + +#if defined(LINUX_2_1) + dev->start=0; +#endif + wanpipe_close(card); + return 0; +} + + +static void disable_comm (sdla_t *card) +{ + unsigned long smp_flags=0; + + wan_spin_lock_irq(&card->wandev.lock, &smp_flags); + + if (card->u.b.cfg.rbs_map){ + bstrm_disable_te_signaling(card,card->u.b.cfg.rbs_map); + } + + if (card->comm_enabled){ + bstrm_disable_comm_shutdown (card); + }else{ + card->hw_iface.poke_byte(card->hw, card->intr_perm_off, 0x00); + } + + wan_spin_unlock_irq(&card->wandev.lock, &smp_flags); + + tasklet_kill(&card->u.b.wanpipe_rx_task); + tasklet_kill(&card->u.b.wanpipe_tx_task); + + wan_spin_lock_irq(&card->wandev.lock, &smp_flags); + bstrm_skb_queue_purge(&card->u.b.rx_isr_queue); + bstrm_skb_queue_purge(&card->u.b.rx_isr_free_queue); + wan_spin_unlock_irq(&card->wandev.lock, &smp_flags); + + + /* TE1 - Unconfiging */ + if (IS_TE1_CARD(card)) { + if (card->wandev.fe_iface.unconfig){ + card->wandev.fe_iface.unconfig(&card->fe); + } + } + return; +} + + +/*============================================================================ + * Handle transmit timeout event from netif watchdog + */ +static void if_tx_timeout (netdevice_t *dev) +{ + bitstrm_private_area_t* chan = dev->priv; + sdla_t *card = chan->card; + + /* If our device stays busy for at least 5 seconds then we will + * kick start the device by making dev->tbusy = 0. We expect + * that our device never stays busy more than 5 seconds. So this + * is only used as a last resort. + */ + + ++card->wandev.stats.collisions; + + printk (KERN_INFO "%s: Transmit timed out on %s\n", card->devname,dev->name); + netif_wake_queue (dev); + + if (chan->common.usedby == API){ + wan_wakeup_api(chan); + }else if (chan->common.usedby == STACK){ + wanpipe_lip_kick(chan,0); + } + +} + + + +/*============================================================================ + * Send a packet on a network interface. + * o set tbusy flag (marks start of the transmission) to block a timer-based + * transmit from overlapping. + * o check link state. If link is not up, then drop the packet. + * o execute adapter send command. + * o free socket buffer + * + * Return: 0 complete (socket buffer must be freed) + * non-0 packet may be re-transmitted (tbusy must be set) + * + * Notes: + * 1. This routine is called either by the protocol stack or by the "net + * bottom half" (with interrupts enabled). + * 2. Setting tbusy flag will inhibit further transmit requests from the + * protocol stack and can be used for flow control with protocol layer. + */ +static int if_send (struct sk_buff* skb, netdevice_t* dev) +{ + bitstrm_private_area_t *bstrm_priv_area = dev->priv; + sdla_t *card = bstrm_priv_area->card; + unsigned long smp_flags; + + if (skb == NULL){ + /* If we get here, some higher layer thinks we've missed an + * tx-done interrupt. + */ + DEBUG_EVENT( "%s: interface %s got kicked!\n", + card->devname, dev->name); + + wake_net_dev(dev); + return 0; + } + + spin_lock_irqsave(&card->wandev.lock,smp_flags); + if (skb_queue_len(&bstrm_priv_area->tx_queue) > bstrm_priv_area->max_tx_queue_sz){ + bstrm_priv_area->tick_counter = jiffies; + if (card->u.b.serial){ + card->hw_iface.set_bit(card->hw, card->intr_perm_off, APP_INT_ON_TX_BLOCK); + } + WAN_NETIF_STOP_QUEUE(dev); + spin_unlock_irqrestore(&card->wandev.lock,smp_flags); + return 1; + } + spin_unlock_irqrestore(&card->wandev.lock,smp_flags); + + +#if defined(LINUX_2_1) + if (dev->tbusy){ + + /* If our device stays busy for at least 5 seconds then we will + * kick start the device by making dev->tbusy = 0. We expect + * that our device never stays busy more than 5 seconds. So this + * is only used as a last resort. + */ + ++card->wandev.stats.collisions; + if((jiffies - bstrm_priv_area->tick_counter) < (5 * HZ)) { + return 1; + } + if_tx_timeout(dev); + } +#endif + + if (test_bit(WAIT_DEVICE_BUFFERS,&bstrm_priv_area->tq_control) && + skb_queue_len(&bstrm_priv_area->tx_queue) >= TX_QUEUE_MID){ + + bitstrm_private_area_t *sw_chan=NULL; + + if (net_ratelimit()){ + DEBUG_EVENT("%s: Balancing switching devices, limiting tx!\n", + bstrm_priv_area->if_name); + } + dev_kfree_skb_any(skb); + + if (bstrm_priv_area->sw_dev){ + sw_chan=(bitstrm_private_area_t *)bstrm_priv_area->sw_dev->priv; + if (sw_chan){ + if (test_bit(WAIT_DEVICE_BUFFERS,&sw_chan->tq_control) && + skb_queue_len(&sw_chan->tx_queue) >= TX_QUEUE_MID){ + + DEBUG_EVENT("%s: Switching devices balanced %d %d\n", + sw_chan->if_name, + skb_queue_len(&bstrm_priv_area->tx_queue), + skb_queue_len(&sw_chan->tx_queue)); + + sw_chan->tq_control=0; + bstrm_priv_area->tq_control=0; + } + } + } + + }else if(card->u.b.state != WAN_CONNECTED || + bstrm_priv_area->common.state != WAN_CONNECTED){ + + ++card->wandev.stats.tx_dropped; + bstrm_priv_area->ifstats.tx_carrier_errors++; + + dev_kfree_skb_any(skb); + + }else if(test_bit(SEND_CRIT,&card->wandev.critical)){ + + ++card->wandev.stats.tx_dropped; + bstrm_priv_area->ifstats.tx_carrier_errors++; + DEBUG_EVENT( "SEND CRIT\n"); + + dev_kfree_skb_any(skb); + + }else{ + + +#if 0 + //FIXME: NENAD DEBUG + dev_kfree_skb_any(skb); + dev->trans_start = jiffies; + goto if_send_exit_crit; +#endif + + /* If it's an API packet pull off the API + * header. Also check that the packet size + * is larger than the API header + */ + + wan_skb_unlink(skb); + + if (bstrm_priv_area->common.usedby == SWITCH){ + wanpipe_switch_datascope_tx_up(bstrm_priv_area,skb); + } + + if (bstrm_priv_area->common.usedby == API){ + if (skb->len <= sizeof(api_tx_hdr_t)){ + ++card->wandev.stats.tx_dropped; + bstrm_priv_area->ifstats.tx_dropped++; + dev_kfree_skb_any(skb); + goto if_send_exit_crit; + } + skb_pull(skb,sizeof(api_tx_hdr_t)); + } + + if (bstrm_priv_area->common.usedby != SWITCH && + bstrm_priv_area->hdlc_eng){ + if (hdlc_encode(bstrm_priv_area,&skb) != 0){ + ++card->wandev.stats.tx_dropped; + bstrm_priv_area->ifstats.tx_dropped++; + + dev_kfree_skb_any(skb); + goto if_send_exit_crit; + } + } + +#if 0 + { + int i; + DEBUG_EVENT( "\n"); + DEBUG_EVENT( "\n"); + DEBUG_EVENT( "Tx Packet: \n"); + for (i=0;ilen;i++){ + printk("%x ",skb->data[i]); + } + printk("\n"); + } +#endif + + card->wandev.stats.tx_packets++; + card->wandev.stats.tx_bytes+=skb->len; + bstrm_priv_area->ifstats.tx_packets++; + bstrm_priv_area->ifstats.tx_bytes += skb->len; + + spin_lock_irqsave(&card->wandev.lock,smp_flags); + if (bstrm_priv_area->common.usedby != SWITCH && + bstrm_priv_area->hdlc_eng){ + bstrm_priv_area->tx_idle_flag = bstrm_priv_area->tx_flag_idle; + } + + skb_queue_tail(&bstrm_priv_area->tx_queue,skb); + spin_unlock_irqrestore(&card->wandev.lock,smp_flags); + + bstrm_priv_area->tick_counter = jiffies; + + if (card->u.b.serial && + !test_bit(WAIT_DEVICE_BUFFERS,&bstrm_priv_area->tq_control)){ + card->hw_iface.set_bit(card->hw, card->intr_perm_off, APP_INT_ON_TX_BLOCK); + } +#if defined(LINUX_2_4)||defined(LINUX_2_6) + dev->trans_start = jiffies; +#endif + + } + +if_send_exit_crit: + + spin_lock_irqsave(&card->wandev.lock,smp_flags); + start_net_queue(dev); + spin_unlock_irqrestore(&card->wandev.lock,smp_flags); + + return 0; +} + + +/*============================================================================ + * Get ethernet-style interface statistics. + * Return a pointer to struct enet_statistics. + */ +static struct net_device_stats* if_stats (netdevice_t* dev) +{ + bitstrm_private_area_t* bstrm_priv_area; + + if ((bstrm_priv_area=dev->priv) == NULL) + return NULL; + + return &bstrm_priv_area->ifstats; +} + +/****** Cisco HDLC Firmware Interface Functions *******************************/ + +/*============================================================================ + * Read firmware code version. + * Put code version as ASCII string in str. + */ +static int bstrm_read_version (sdla_t* card, char* str) +{ + int data_len = 0; + + wan_mbox_t* mb = &card->wan_mbox; + int rc; + memset(mb, 0, sizeof(wan_cmd_t)); + mb->wan_data_len = 0; + mb->wan_command = READ_BSTRM_CODE_VERSION; + rc = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (rc != WAN_CMD_TIMEOUT){ + if (str) { /* is not null */ + data_len = mb->wan_data_len; + memcpy(str, mb->wan_data, data_len); + str[data_len] = '\0'; + } + }else{ + bstrm_error(card,rc,mb); + } + return (rc); +} + +/*----------------------------------------------------------------------------- + * Configure BSTRM firmware. + */ +static int bstrm_configure (sdla_t* card, void* data) +{ + int err; + + wan_mbox_t *mb = &card->wan_mbox; + memset(mb, 0, sizeof(wan_cmd_t)); + memcpy(mb->wan_data, data, sizeof(BSTRM_CONFIGURATION_STRUCT)); + mb->wan_command = SET_BSTRM_CONFIGURATION; + mb->wan_data_len = sizeof(BSTRM_CONFIGURATION_STRUCT); + + err=card->hw_iface.cmd(card->hw, card->mbox_off, mb); + + if (err){ + DEBUG_EVENT("%s: BSTRM CFG ERR: Len=%i Data=0x%X\n", + card->devname,mb->wan_data_len,mb->wan_data[0]); + } + return err; +} + + +/*============================================================================ + * Set interrupt mode -- HDLC Version. + */ + +static int bstrm_set_intr_mode (sdla_t* card, unsigned mode) +{ + wan_mbox_t* mb = &card->wan_mbox; + int rc; + BSTRM_INT_TRIGGERS_STRUCT* int_data = + (BSTRM_INT_TRIGGERS_STRUCT *)mb->wan_data; + + memset(mb, 0, sizeof(wan_cmd_t)); + int_data->BSTRM_interrupt_triggers = mode; + int_data->IRQ = card->wandev.irq; //ALEX_TODAY card->hw.irq; + int_data->interrupt_timer = 1; + + mb->wan_data_len = sizeof(BSTRM_INT_TRIGGERS_STRUCT); + mb->wan_command = SET_BSTRM_INTERRUPT_TRIGGERS; + rc = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (rc == WAN_CMD_TIMEOUT) + bstrm_error (card, rc, mb); + return rc; +} + + +/*=========================================================== + * bstrm_disable_comm_shutdown + * + * Shutdown() disables the communications. We must + * have a sparate functions, because we must not + * call bstrm_error() hander since the private + * area has already been replaced */ + +static int bstrm_disable_comm_shutdown (sdla_t *card) +{ + wan_mbox_t* mb = &card->wan_mbox; + int rc; + BSTRM_INT_TRIGGERS_STRUCT* int_data = + (BSTRM_INT_TRIGGERS_STRUCT *)mb->wan_data; + + memset(mb, 0, sizeof(wan_cmd_t)); + /* Disable Interrutps */ + int_data->BSTRM_interrupt_triggers = 0; + int_data->IRQ = card->wandev.irq; //ALEX_TODAY card->hw.irq; + int_data->interrupt_timer = 1; + + mb->wan_command = SET_BSTRM_INTERRUPT_TRIGGERS; + mb->wan_data_len = sizeof(BSTRM_INT_TRIGGERS_STRUCT); + rc = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + + /* Disable Communications */ + mb->wan_command = DISABLE_BSTRM_COMMUNICATIONS; + mb->wan_data_len = 0; + rc = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + card->comm_enabled = 0; + + return 0; +} + +/*============================================================================ + * Enablenications. + */ + +static int bstrm_comm_enable (sdla_t* card) +{ + wan_mbox_t* mb = &card->wan_mbox; + int rc; + + mb->wan_data_len = 0; + mb->wan_command = ENABLE_BSTRM_COMMUNICATIONS; + rc = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (rc == WAN_CMD_TIMEOUT) + bstrm_error(card, rc, mb); + else + card->comm_enabled = 1; + + return rc; +} + +/*============================================================================ + * Read communication error statistics. + */ +static int bstrm_read_comm_err_stats (sdla_t* card) +{ + int rc; + wan_mbox_t* mb = &card->wan_mbox; + + mb->wan_data_len = 0; + mb->wan_command = READ_COMMS_ERROR_STATS; + rc = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (rc == WAN_CMD_TIMEOUT) + bstrm_error(card,rc,mb); + return rc; +} + + +/*============================================================================ + * Read BSTRM operational statistics. + */ +static int bstrm_read_op_stats (sdla_t* card) +{ + int rc; + wan_mbox_t* mb = &card->wan_mbox; + + mb->wan_data_len = 0; + mb->wan_command = READ_BSTRM_OPERATIONAL_STATS; + rc = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (rc == WAN_CMD_TIMEOUT) + bstrm_error(card,rc,mb); + return rc; +} + + +/*============================================================================ + * Update communications error and general packet statistics. + */ +static int update_comms_stats(sdla_t* card, + bitstrm_private_area_t* bstrm_priv_area) +{ + wan_mbox_t* mb = &card->wan_mbox; + COMMS_ERROR_STATS_STRUCT* err_stats; + BSTRM_OPERATIONAL_STATS_STRUCT *op_stats; + + if(bstrm_priv_area->update_comms_stats == 3) { + /* 1. On the first timer interrupt, update T1/E1 alarms + * and PMON counters (only for T1/E1 card) (TE1) + */ + /* TE1 Update T1/E1 alarms */ + if (IS_TE1_CARD(card)) { + card->wandev.fe_iface.read_alarm(&card->fe, 0); + /* TE1 Update T1/E1 perfomance counters */ + card->wandev.fe_iface.read_pmon(&card->fe, 0); + }else if (IS_56K_CARD(card)) { + /* 56K Update CSU/DSU alarms */ + card->wandev.fe_iface.read_alarm(&card->fe, 1); + } + + }else { + /* 2. On the second timer interrupt, read the comms error + * statistics + */ + if(bstrm_priv_area->update_comms_stats == 2) { + if(bstrm_read_comm_err_stats(card)) + return 1; + err_stats = (COMMS_ERROR_STATS_STRUCT *)mb->wan_data; + card->wandev.stats.rx_over_errors = + err_stats->Rx_overrun_err_count; + card->wandev.stats.rx_fifo_errors = + err_stats->Rx_dis_pri_bfrs_full_count; + card->wandev.stats.rx_missed_errors = + card->wandev.stats.rx_fifo_errors; + } else { + + /* on the third timer interrupt, read the operational + * statistics + */ + if(bstrm_read_op_stats(card)) + return 1; + op_stats = (BSTRM_OPERATIONAL_STATS_STRUCT *)mb->wan_data; + } + } + + return 0; +} + +/*============================================================================ + * Send packet. + * Return: 0 - o.k. + * 1 - no transmit buffers available + */ +static int bstrm_send (sdla_t* card, void* data, unsigned len, unsigned char flag) +{ + BSTRM_DATA_TX_STATUS_EL_STRUCT txbuf; + + card->hw_iface.peek(card->hw, card->u.b.txbuf_off, &txbuf, sizeof(txbuf)); + if (txbuf.opp_flag) + return 1; + + if (flag){ + txbuf.misc_Tx_bits = (volatile unsigned char)UPDATE_TX_TIME_FILL_CHAR; + txbuf.Tx_time_fill_char = flag; + }else{ + txbuf.misc_Tx_bits=0; + } + + txbuf.block_length = len; + + /* WARNING: + * The txbuf->block_lenght and txbuf->opp_flag should + * never execute one after another. Since opp_flag and + * block_lenght reside beside each other in memory, + * some ISA busses will write, OUT OF ORDER, to the + * oppflag before the block length is updated */ + + card->hw_iface.poke(card->hw, txbuf.ptr_data_bfr, data, len); + + txbuf.opp_flag = 1; /* start transmission */ + card->hw_iface.poke(card->hw, card->u.b.txbuf_off, &txbuf, sizeof(txbuf)); + + /* Update transmit buffer control fields */ + card->u.b.txbuf_off += sizeof(txbuf); + if (card->u.b.txbuf_off > card->u.b.txbuf_last_off) + card->u.b.txbuf_off = card->u.b.txbuf_base_off; + return 0; +} + +/*============================================================================ + * TE1 + * Read value from PMC register. + */ +static unsigned char read_front_end_reg (void* card1, ...) +{ + va_list args; + sdla_t* card = (sdla_t*)card1; + wan_mbox_t* mb = &card->wan_mbox; + u16 reg; + int rc; + char* data = mb->wan_data; + + va_start(args, card1); + reg = (u16)va_arg(args, int); + va_end(args); + + mb->wan_data_len = sizeof(FRONT_END_REG_STRUCT); + mb->wan_command = READ_FRONT_END_REGISTER; + ((FRONT_END_REG_STRUCT *)data)->register_number = (unsigned short)reg; + rc = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (rc == WAN_CMD_TIMEOUT) + bstrm_error(card,rc,mb); + return(((FRONT_END_REG_STRUCT *)data)->register_value); +} + +/*============================================================================ + * TE1 + * Write value to PMC register. + */ +static int write_front_end_reg (void* card1, ...) +{ + va_list args; + sdla_t* card = (sdla_t*)card1; + wan_mbox_t* mb = &card->wan_mbox; + u16 reg; + u8 value; + int rc; + char* data = mb->wan_data; + int retry=10; + + va_start(args, card1); + reg = (u16)va_arg(args, int); + value = (u8)va_arg(args, int); + va_end(args); + + do { + ((FRONT_END_REG_STRUCT *)data)->register_number = (unsigned short)reg; + ((FRONT_END_REG_STRUCT *)data)->register_value = value; + mb->wan_data_len = sizeof(FRONT_END_REG_STRUCT); + mb->wan_command = WRITE_FRONT_END_REGISTER; + rc = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (rc == WAN_CMD_TIMEOUT) + bstrm_error(card,rc,mb); + }while (rc && --retry); + + return rc; +} + +/*============================================================================ + * Enable timer interrupt + */ +static void bstrm_enable_timer (void* card_id) +{ + sdla_t* card = (sdla_t*)card_id; + + card->u.b.timer_int_enabled |= TMR_INT_ENABLED_TE; + card->hw_iface.set_bit(card->hw, card->intr_perm_off, APP_INT_ON_TIMER); + return; +} + +/****** Firmware Error Handler **********************************************/ + +/*============================================================================ + * Firmware error handler. + * This routine is called whenever firmware command returns non-zero + * return code. + * + * Return zero if previous command has to be cancelled. + */ +static int bstrm_error (sdla_t *card, int err, wan_mbox_t *mb) +{ + unsigned cmd = mb->wan_command; + + switch (err) { + + case CMD_TIMEOUT: + DEBUG_EVENT( "%s: command 0x%02X timed out!\n", + card->devname, cmd); + break; + + case T1_E1_AMI_NOT_SUPPORTED: + DEBUG_EVENT( "%s: AMI decoding not supported\n", + card->devname); + break; + + case S514_BOTH_PORTS_SAME_CLK_MODE: + if(cmd == SET_BSTRM_CONFIGURATION) { + DEBUG_EVENT( + "%s: Configure both ports for the same clock source\n", + card->devname); + break; + } + + default: + DEBUG_EVENT( "%s: command 0x%02X returned 0x%02X!\n", + card->devname, cmd, err); + } + + return 0; +} + +/********** Bottom Half Handlers ********************************************/ + +/* NOTE: There is no API, BH support for Kernels lower than 2.2.X. + * DO NOT INSERT ANY CODE HERE, NOTICE THE + * PREPROCESSOR STATEMENT ABOVE, UNLESS YOU KNOW WHAT YOU ARE + * DOING + */ + +static void bstrm_tx_bh (unsigned long data) +{ +#define card ((sdla_t*)data) + BSTRM_DATA_TX_STATUS_EL_STRUCT txbuf; + bitstrm_private_area_t* chan; + int ch=0; + char kick_tx_isr=0; + char frame_multiple=0; + + set_bit(8, &card->u.b.tq_working); + + if (test_bit(SEND_CRIT,&card->wandev.critical)){ + clear_bit(SEND_CRIT,&card->wandev.critical); + } + + card->hw_iface.peek(card->hw, card->u.b.txbuf_off, &txbuf, sizeof(txbuf)); + if (test_bit(0,(unsigned long*)&txbuf.opp_flag)){ + DEBUG_EVENT( "%s: Error: Tx buffer busy in Tx intr!\n", + card->devname); + goto tx_bh_exit; + } + +#if 0 + //FIXME: NENAD DEBUG + goto tx_nenad_skip; +#endif + card->u.b.tx_scratch_buf_len=0; + + if (card->u.b.serial){ + /* For non T1/E1 cards, send a whole skb buffer + * down the stack. i.e. no channelization */ + struct sk_buff *skb; + netdevice_t *dev; + + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + + if (!dev || !(dev->flags & IFF_UP)){ + DEBUG_EVENT("%s: Dev down\n",__FUNCTION__); + goto tx_bh_exit; + } + + chan = (bitstrm_private_area_t *)wan_netif_priv(dev); + if (!chan){ + goto tx_bh_exit; + } + + if (chan->common.usedby == SWITCH && + test_bit(WAIT_DEVICE_BUFFERS,&chan->tq_control)){ + DEBUG_EVENT("%s: Warning: Tx Intr while waiting for buffers\n", + chan->common.dev->name); + } + + if (is_queue_stopped(chan->common.dev)){ + if (chan->common.usedby == API){ + start_net_queue(chan->common.dev); + wan_wakeup_api(chan); + }else if (chan->common.usedby == SWITCH){ + start_net_queue(chan->common.dev); + }else{ + wake_net_dev(chan->common.dev); + } + } + + skb=skb_dequeue(&chan->tx_queue); + if (!skb){ + goto tx_bh_exit; + } + + if (bstrm_send(card,skb->data,skb->len,chan->hdlc_eng?skb->cb[0]:0)){ + DEBUG_EVENT( "%s: Error: Tx Bh: failed to send buffer busy!\n", + card->devname); + } + + dev_kfree_skb_any(skb); + + if (skb_queue_len(&chan->tx_queue)){ + card->hw_iface.set_bit(card->hw, card->intr_perm_off, APP_INT_ON_TX_BLOCK); + } + goto tx_bh_exit; + } + + for (;;){ + + /* Do not tx on E1 channel 0 since it is a signalling + * channel */ + + if (!IS_TE1_UNFRAMED(&card->fe) && card->u.b.time_slots == NUM_OF_E1_CHANNELS && ch == 0){ + goto tx_time_slot_handled; + } + + chan=(bitstrm_private_area_t*)card->u.b.time_slot_map[ch]; + if (!chan || !(chan->common.dev->flags & IFF_UP)){ + DEBUG_TEST("%s: Timeslot %i not configured!\n", + card->devname,(ch+1)); + card->u.b.tx_scratch_buf[card->u.b.tx_scratch_buf_len]= + card->u.b.cfg.monosync_tx_time_fill_char; + card->u.b.tx_scratch_buf_len++; + goto tx_time_slot_handled; + } + + if (!chan->tx_skb){ + + if (is_queue_stopped(chan->common.dev)){ + if (chan->common.usedby == API){ + start_net_queue(chan->common.dev); + wan_wakeup_api(chan); + }else if (chan->common.usedby == STACK){ + start_net_queue(chan->common.dev); + wanpipe_lip_kick(chan,0); + }else if (chan->common.usedby == SWITCH){ + start_net_queue(chan->common.dev); + }else{ + wake_net_dev(chan->common.dev); + } + } + + if (chan->common.usedby == SWITCH && + test_bit(WAIT_DEVICE_BUFFERS,&chan->tq_control)){ + card->u.b.tx_scratch_buf[card->u.b.tx_scratch_buf_len]=chan->tx_idle_flag; + card->u.b.tx_scratch_buf_len++; + goto tx_time_slot_handled; + } + + chan->tx_skb = skb_dequeue(&chan->tx_queue); + if (!chan->tx_skb){ +#if 0 + if (net_ratelimit()){ + DEBUG_TEST("%s: Channel %s: no data \n", + card->devname,chan->if_name); + } +#endif + card->u.b.tx_scratch_buf[card->u.b.tx_scratch_buf_len]=chan->tx_idle_flag; + card->u.b.tx_scratch_buf_len++; + chan->ifstats.tx_fifo_errors++; + goto tx_time_slot_handled; + } + } + + if (!chan->tx_skb || chan->tx_skb->len == 0){ +#if 0 + if (net_ratelimit()){ + DEBUG_EVENT("%s: Channel %s: %i skb empty\n", + card->devname,chan->if_name,ch+1); + } +#endif + card->u.b.tx_scratch_buf[card->u.b.tx_scratch_buf_len]=chan->tx_idle_flag; + card->u.b.tx_scratch_buf_len++; + chan->ifstats.tx_fifo_errors++; + + if (chan->tx_skb){ + dev_kfree_skb_any(chan->tx_skb); + chan->tx_skb=NULL; + } + + goto tx_time_slot_handled; + } + + card->u.b.tx_scratch_buf[card->u.b.tx_scratch_buf_len]=chan->tx_skb->data[0]; + card->u.b.tx_scratch_buf_len++; + + skb_pull(chan->tx_skb,1); + + /* We must check for existance of the pointer, + * because the channel might be unconfigued */ + if (chan->tx_skb->len < 1){ + dev_kfree_skb_any(chan->tx_skb); + chan->tx_skb=NULL; + }else{ + kick_tx_isr=1; + } + +tx_time_slot_handled: + + /* How many times should we go around */ + if (++ch >= card->u.b.time_slots){ + ch=0; + if (++frame_multiple >= card->u.b.tx_chan_multiple){ + break; + } + } + } + +#if 0 +//NENAD +tx_nenad_skip: + +#endif + + if (bstrm_send(card,&card->u.b.tx_scratch_buf[0],card->u.b.tx_scratch_buf_len,0)){ + DEBUG_EVENT( "%s: Error: Tx Bh: failed to send buffer busy!\n", + card->devname); + } + +tx_bh_exit: + clear_bit(8, &card->u.b.tq_working); + + +#undef card +} + +static void bstrm_rx_bh (unsigned long data) +{ +#define card ((sdla_t*)data) + struct sk_buff *skb; + bitstrm_private_area_t* chan; + int ch=0,stream_full=0; + volatile unsigned char *buf; + + bstrm_test_rx_tx_discard(card); + + if (!skb_queue_len(&card->u.b.rx_isr_queue)){ + while(bstrm_bh_data_tx_up(card,NULL,NULL)); + card->statistics.poll_tbusy_bad_status++; + return; + } + + card->statistics.poll_entry++; + + while ((skb=skb_dequeue(&card->u.b.rx_isr_queue)) != NULL){ + + if (!skb->len){ + DEBUG_EVENT( "RX Error, skb=NULL or skb->len=0 \n"); + bstrm_bh_cleanup(card,skb); + continue; + } + + ch=0; + + if (card->u.b.serial){ + netdevice_t *dev; + + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + + if (!dev || !(dev->flags&IFF_UP)){ + bstrm_bh_cleanup(card,skb); + continue; + } + + chan = (bitstrm_private_area_t *)wan_netif_priv(dev); + if (!chan){ + bstrm_bh_cleanup(card,skb); + continue; + } + + if (chan->common.usedby == SWITCH){ + + bstrm_bh_data_tx_up(card,skb,chan); + + bstrm_switch_send(card,chan,skb); + + bstrm_bh_cleanup(card,skb); + + }else{ + bstrm_bh_data_tx_up(card,skb,NULL); + bstrm_bh_cleanup(card,skb); + } + continue; + } + + for (;;){ + + chan=(bitstrm_private_area_t*)card->u.b.time_slot_map[ch]; + if (!chan || !(chan->common.dev->flags & IFF_UP)){ + DEBUG_TEST("%s: Timeslot %i (ch=%i) not configured!\n", + card->devname,(ch+1),ch); + skb_pull(skb,1); + card->wandev.stats.rx_over_errors=ch; + card->wandev.stats.rx_fifo_errors++; + goto rx_time_slot_handled; + } + + if (chan->rbs_on){ + if (chan->rbs_sig != card->u.b.rbs_sig[ch]){ + chan->rbs_sig=card->u.b.rbs_sig[ch]; + send_rbs_oob_msg (card,chan); + DEBUG_TEST("%s: RBS Change 0x%X\n", + chan->if_name,chan->rbs_sig); + } + } + + if (!chan->rx_skb){ + /* The free queues might be busy, try + * here again. If we fail then we have a buffering + * problem. Increment a dropped packet */ + + DEBUG_TEST("%s: Rx_SKB from free queue! Free Q Len=%i\n", + card->devname,skb_queue_len(&chan->rx_free_queue)); + chan->rx_skb=skb_dequeue(&chan->rx_free_queue); + if (!chan->rx_skb){ + DEBUG_EVENT( "%s: Timeslot %i no rx buf!\n", + card->devname,(ch+1)); + chan->ifstats.rx_dropped++; + skb_pull(skb,1); + goto rx_time_slot_handled; + } + chan->rx_timeout=jiffies; + } + + if (skb_queue_len(&chan->rx_used_queue)){ + stream_full=1; + } + + buf=skb_put(chan->rx_skb,1); + buf[0]=skb->data[0]; + skb_pull(skb,1); + +#if 0 +//NENAD + + if (ch > 1){ + if (buf[0] == 0x20+(ch-1)){ + if (!chan->debug_stream){ + DEBUG_EVENT("%s: Ch=%i:Got First Sync = 0x%X Len=%i\n", + chan->common.dev->name,ch,buf[0],chan->rx_skb->len); + chan->debug_stream=1; + chan->debug_char=buf[0]; + } + }else{ + if (chan->debug_stream){ + DEBUG_EVENT("%s: Ch=%i:Out of sync First = 0x%X Idle=0x%X Len=%i\n", + chan->common.dev->name,ch,buf[0],chan->tx_idle_flag, + chan->rx_skb->len); + chan->debug_stream=0; + } + } + } +#endif + + if (chan->rx_skb->len >= chan->max_tx_up_size){ + + /* A bit stream has reached maximum size. + * we must pass it to the next layer, ether + * HDLC decoder or API. For now just push it + * into the used queue */ + + if (chan->common.usedby == SWITCH){ + //if (skb->len != 0){ + // DEBUG_EVENT( "%s: SWITCH Sending %i, orig skb %i\n", + // card->devname,chan->rx_skb->len, skb->len); + //} + + /* Try to pass the packet up the stack if + * the API is registered */ + bstrm_bh_data_tx_up(card, NULL, chan); + + /* Send the packet to our switched device*/ + bstrm_switch_send(card,chan,chan->rx_skb); + + /* Re-initialize the buffer, to be reused */ + chan->rx_skb->data=(chan->rx_skb->head+16); + chan->rx_skb->len=1; + skb_trim(chan->rx_skb,0); + + }else{ + skb_queue_tail(&chan->rx_used_queue,chan->rx_skb); + chan->rx_skb=NULL; + chan->rx_skb=skb_dequeue(&chan->rx_free_queue); + stream_full=1; + } + chan->rx_timeout=jiffies; + if (chan->rx_skb && chan->rx_skb->len){ + DEBUG_EVENT( "%s: Rx got new buffer skb len=%i\n", + chan->common.dev->name,chan->rx_skb->len); + } + } + +rx_time_slot_handled: + if (skb->len < 1){ + break; + } + + if (++ch >= card->u.b.time_slots){ + ch=0; + } + + }//for(;;) + + /* Initialize the rx_intr skb buffer, and get it ready + * for another use */ + + bstrm_bh_cleanup(card,skb); + + if (!stream_full){ + continue; + } + + stream_full=bstrm_bh_data_tx_up(card,NULL,NULL); + } + + while (stream_full){ + stream_full=bstrm_bh_data_tx_up(card,NULL,NULL); + } + + return; +#undef card +} + + +static void bstrm_switch_send(sdla_t *card, bitstrm_private_area_t * chan, struct sk_buff *skb) +{ + struct sk_buff *new_skb; + + if (!skb) + return; + + if (chan->sw_dev && (chan->sw_dev->flags&IFF_UP)){ + + if (is_queue_stopped(chan->sw_dev)){ + DEBUG_EVENT( "%s:%s: (Debug): Warning: dev busy %s\n", + card->devname,chan->if_name,chan->sw_dev->name); + goto switch_send_done; + } + + if (!test_bit(WAIT_DEVICE_BUFFERS,&chan->tq_control)){ + + if (skb_queue_len(&chan->tx_queue) < TX_QUEUE_LOW){ + DEBUG_EVENT("%s: Device queue low %i\n", + chan->common.dev->name, + skb_queue_len(&chan->tx_queue)); + + }else if (skb_queue_len(&chan->tx_queue) > TX_QUEUE_HIGH){ + DEBUG_EVENT("%s: Device queue high %i\n", + chan->common.dev->name, + skb_queue_len(&chan->tx_queue)); + } + } + + new_skb=skb_copy(skb,GFP_ATOMIC); + if (!new_skb){ + DEBUG_EVENT( "%s: ERROR: BH SW failed to allocate memory !\n", + card->devname); + card->wandev.stats.rx_errors++; + chan->ifstats.rx_errors++; + }else{ + if (!chan->sw_dev->hard_start_xmit || + chan->sw_dev->hard_start_xmit(new_skb,chan->sw_dev) != 0){ + kfree(new_skb); + DEBUG_EVENT( "%s: Failed to send on SW dev %s\n", + chan->if_name,chan->sw_dev->name); + goto switch_send_done; + } + card->wandev.stats.rx_packets++; + card->wandev.stats.rx_bytes+=skb->len; + chan->ifstats.rx_packets++; + chan->ifstats.rx_bytes+=skb->len; + } + }else{ + chan->ifstats.rx_fifo_errors++; + } + +switch_send_done: + return; +} + +static int bstrm_bh_data_tx_up(sdla_t*card, struct sk_buff *non_te1_skb, bitstrm_private_area_t *chan_ptr) +{ + struct wan_dev_le *devle = NULL; + netdevice_t *dev; + bitstrm_private_area_t *chan; + struct sk_buff *new_skb,*skb; + int err=0; + int switch_dev=0; + + /* Test if channel is specified */ + if ((chan=chan_ptr) != NULL){ + dev=chan->common.dev; + + /* Channel exists, the SWITCH code is trying + * to send a packet up the stack. Thus + * check if this device is actually in SWITCH + * mode */ + if (dev && chan->common.usedby == SWITCH){ + + /* If API socket is not bound in + * then exit */ + if (chan->common.sk == NULL){ + return 0; + }else{ + + /* API exists, then get the + * skb buffer from the rx_skb */ + if (card->u.b.serial){ + skb=non_te1_skb; + }else{ + skb=chan->rx_skb; + } + + /* During Switching, only a single + * buffer is used, not a queue */ + if (skb){ + + /* Buffer exists, thus, set the + * switch flag, indicating below + * not to re-initialize this buffer */ + switch_dev=1; + goto switch_hdlc_send; + }else{ + + /* This should never happen */ + return 0; + } + } + } + } + + /* The Serial cards, don't use queues, thus, + * they give us the skb buffer */ + if (card->u.b.serial && non_te1_skb==NULL){ + return err; + } + + WAN_LIST_FOREACH(devle, &card->wandev.dev_head, dev_link){ + dev = WAN_DEVLE2DEV(devle); + if (dev == NULL || wan_netif_priv(dev) == NULL) + continue; + chan = wan_netif_priv(dev); + + if (!card->u.b.serial){ + skb = skb_dequeue(&chan->rx_used_queue); + if (!skb){ + continue; + } + + if (skb_queue_len(&chan->rx_used_queue)){ + err=1; + } + }else{ + skb = non_te1_skb; + if (!skb){ + return err; + } + } + + /* This is just a precaution, SWITCH device + * shouldnt be here */ + if (chan->common.usedby == SWITCH){ + goto tx_up_skb_recover; + + }else if (chan->common.usedby == API){ + /* Test if the API socket is bound in */ + if (chan->common.sk == NULL){ + chan->ifstats.rx_errors++; + goto tx_up_skb_recover; + } + } + +switch_hdlc_send: + + if (chan->hdlc_eng){ +#if 0 + DEBUG_EVENT("HDLC: UP\n"); + DEBUG_EVENT( "PKT: "); + { + int i; + for (i=0;ilen;i++){ + if (skb->data[i] != 0x7E){ + DEBUG_EVENT("%s: Data = 0x%X\n",card->devname,skb->data); + } + //printk("%02X ",skb->data[i]); + } + //printk("\n"); + } +#endif + hdlc_decode(chan, + (skb->data), + (skb->len)); + }else{ + + if (skb_headroom(skb) < sizeof(api_rx_hdr_t)){ + new_skb=skb_copy_expand(skb,sizeof(api_rx_hdr_t),0,GFP_ATOMIC); + }else{ + new_skb=skb_copy(skb,GFP_ATOMIC); + } + + if (!new_skb){ + DEBUG_EVENT( "%s: ERROR: Failed to clone skb buffer, no memory !\n", + card->devname); + ++card->wandev.stats.rx_errors; + chan->ifstats.rx_errors++; + + }else{ + unsigned char *buf; + int api_err; + +#if 0 +//NENAD + if (chan->debug_char == 0x25){ + int i,x; + static int out_of_sync_off=0; + for(i=0;ilen;i++){ + if (new_skb->data[i] == chan->debug_char){ + if (!chan->debug_stream_1){ + DEBUG_EVENT("%s: Got Second Sync = 0x%X Offset=%i\n", + chan->common.dev->name,new_skb->data[i],i); + chan->debug_stream_1=1; + + if (out_of_sync_off && out_of_sync_off < i){ + for (x=out_of_sync_off;x<=i;x++){ + DEBUG_EVENT("0x%X\n",new_skb->data[x]); + } + out_of_sync_off=0; + } + } + }else{ + if (chan->debug_stream_1){ + DEBUG_EVENT("%s: Out of sync Sec = 0x%X Idle=0x%X Offset=%i\n", + chan->common.dev->name,new_skb->data[i], + chan->tx_idle_flag,i); + chan->debug_stream_1=0; + out_of_sync_off=i; + } + } + } + } +#endif + + if (chan->common.usedby == STACK){ + + if (wanpipe_lip_rx(chan,new_skb) != 0){ + wan_skb_free(new_skb); + ++card->wandev.stats.rx_dropped; + ++chan->ifstats.rx_dropped; + goto tx_up_skb_recover; + } + + }else{ + + buf = skb_push(new_skb,sizeof(api_rx_hdr_t)); + memset(buf, 0, sizeof(api_rx_hdr_t)); + + new_skb->protocol = htons(PVC_PROT); + new_skb->mac.raw = new_skb->data; + new_skb->dev = dev; + new_skb->pkt_type = WAN_PACKET_DATA; + + api_err=wan_api_rx(chan,new_skb); + + if (api_err != 0){ + /* Sock full cannot send, queue us for another + * try */ + if (net_ratelimit()){ + DEBUG_EVENT( "%s: Error: Rx sock full err %d used 0x%lx sk %p\n", + card->devname,\ + err, + chan->common.used, + chan->common.sk); + } + wan_skb_free(new_skb); + + ++card->wandev.stats.rx_dropped; + ++chan->ifstats.rx_dropped; + + wan_wakeup_api(chan); + goto tx_up_skb_recover; + } + + } + + ++card->wandev.stats.rx_packets; + card->wandev.stats.rx_bytes+=skb->len; + chan->ifstats.rx_packets++; + chan->ifstats.rx_bytes+=skb->len; + + } //if new_skb + + }//if HDLC_DECODE + +tx_up_skb_recover: + + if (switch_dev){ + err=0; + break; + } + + if (!card->u.b.serial){ + skb->data=(skb->head+16); + skb->len=1; + skb_trim(skb,0); + skb_queue_tail(&chan->rx_free_queue,skb); + }else{ + break; + } + }//for() + + return err; +} + +static int bstrm_bh_cleanup (sdla_t *card,struct sk_buff *skb) +{ + if (!skb) + return 0; + + /* Reset the buffer to zero */ + skb->data = skb->head + 16; + /* This is a trick. The skb_trim checks if the skb->len is greater + * than the new len. Thus, fake the skb->len to 1 */ + skb->len=1; + skb_trim(skb,0); + + skb_queue_tail(&card->u.b.rx_isr_free_queue,skb); + return 0; +} + +static struct sk_buff * bh_enqueue (sdla_t *card) +{ + /* Check for full */ + struct sk_buff *skb; + + skb=skb_dequeue(&card->u.b.rx_isr_free_queue); + if (!skb){ + DEBUG_TEST( "%s: Error: No skb in bh_enqueue\n", + card->devname); + return NULL; + } + + if (skb->len){ + DEBUG_EVENT( "%s: Error: Bh Enqueue Skb len %i\n", + card->devname,skb->len); + return NULL; + } + + return skb; +} + +/* END OF API BH Support */ + + +/* HDLC Bitstream Decode Functions */ + +static void hdlc_decode (bitstrm_private_area_t *chan, unsigned char *buf, int len) +{ + int i; + int word_len=len-(len%4); + int found=0; + + /* Before decoding the packet, make sure that the current + * bit stream contains data. Decoding is very expensive, + * thus perform word (32bit) comparision test */ +#if 1 + for (i=0;icard; + + /* Test each bit in an incoming bitstream byte. Search + * for an hdlc flag 0x7E, six 1s in a row. Once the + * flag is obtained, construct the data packets. + * The complete data packets are sent up the API stack */ + + for (i=0; iseven_bit_hdlc && i==7){ + continue; + } + + if (test_bit(i,&byte)){ + /* Got a 1 */ + + ++chan->rx_decode_onecnt; + + /* Make sure that we received a valid flag, + * before we start decoding incoming data */ + if (!test_bit(NO_FLAG,&chan->hdlc_flag)){ + chan->rx_decode_buf[chan->rx_decode_len] |= (1 << chan->rx_decode_bit_cnt); + + if (++chan->rx_decode_bit_cnt >= BITSINBYTE){ + + /* Completed a byte of data, update the + * crc count, and start on the next + * byte. */ + calc_rx_crc(chan); +#ifdef PRINT_PKT + printk(" %02X", data); +#endif + ++chan->rx_decode_len; + + if (chan->rx_decode_len > HDLC_ENG_BUF_LEN){ + DEBUG_EVENT("%s: Error: Rx hdlc overflow\n", + chan->if_name); + init_rx_hdlc_eng(card,chan,1); + ++chan->ifstats.rx_frame_errors; + ++card->wandev.stats.rx_frame_errors; + }else{ + chan->rx_decode_buf[chan->rx_decode_len]=0; + chan->rx_decode_bit_cnt=0; + chan->hdlc_flag=0; + set_bit(CLOSING_FLAG,&chan->hdlc_flag); + } + } + } + }else{ + /* Got a zero */ + if (chan->rx_decode_onecnt == 5){ + + /* bit stuffed zero detected, + * do not increment our decode_bit_count. + * thus, ignore this bit*/ + + + }else if (chan->rx_decode_onecnt == 6){ + + /* Got a Flag */ + if (test_bit(CLOSING_FLAG,&chan->hdlc_flag)){ + + /* Got a closing flag, thus asemble + * the packet and send it up the + * stack */ + chan->hdlc_flag=0; + set_bit(OPEN_FLAG,&chan->hdlc_flag); + + if (chan->rx_decode_len >= 3){ + + GET_FIN_CRC_CNT(chan->crc_cur); + FLIP_CRC(chan->rx_crc[chan->crc_cur],chan->crc_fin); + DECODE_CRC(chan->crc_fin); + + /* Check CRC error before passing data up + * the API socket */ + if (chan->crc_fin==chan->rx_orig_crc){ + tx_up_decode_pkt(chan); + }else{ + DEBUG_TEST("%s: Rx crc error, len=%i\n", + chan->if_name,chan->rx_decode_len); + ++chan->ifstats.rx_crc_errors; + ++card->wandev.stats.rx_crc_errors; + + init_rx_hdlc_eng(card,chan,1); + } + }else{ + DEBUG_TEST("%s: Rx abt error\n",chan->if_name); + ++chan->ifstats.rx_frame_errors; + ++card->wandev.stats.rx_frame_errors; + } + + }else if (test_bit(NO_FLAG,&chan->hdlc_flag)){ + /* Got a very first flag */ + chan->hdlc_flag=0; + set_bit(OPEN_FLAG,&chan->hdlc_flag); + } + + /* After a flag, initialize the decode and + * crc buffers and get ready for the next + * data packet */ + init_rx_hdlc_eng(card,chan,0); + }else{ + /* Got a valid zero, thus increment the + * rx_decode_bit_cnt, as a result of which + * a zero is left in the consturcted + * byte. NOTE: we must have a valid flag */ + + if (!test_bit(NO_FLAG,&chan->hdlc_flag)){ + if (++chan->rx_decode_bit_cnt >= BITSINBYTE){ + calc_rx_crc(chan); +#ifdef PRINT_PKT + printk(" %02X", data); +#endif + ++chan->rx_decode_len; + + if (chan->rx_decode_len > HDLC_ENG_BUF_LEN){ + DEBUG_EVENT("%s: Error: Rx hdlc overflow\n", + chan->if_name); + init_rx_hdlc_eng(card,chan,1); + ++chan->ifstats.rx_frame_errors; + ++card->wandev.stats.rx_frame_errors; + }else{ + chan->rx_decode_buf[chan->rx_decode_len]=0; + chan->rx_decode_bit_cnt=0; + chan->hdlc_flag=0; + set_bit(CLOSING_FLAG,&chan->hdlc_flag); + } + } + } + } + chan->rx_decode_onecnt=0; + } + } + + return; +} + + +static void init_crc(void) +{ + int i,j; + + for(i=0;i<256;i++){ + CRC_TABLE[i]=0; + for (j=0;jcrc_cur); + + /* Save the incoming CRC value, so it can be checked + * against the calculated one */ + chan->rx_orig_crc = (((chan->rx_orig_crc<<8)&0xFF00) | chan->rx_decode_buf[chan->rx_decode_len]); + + chan->rx_crc_tmp = (chan->rx_decode_buf[chan->rx_decode_len] ^ chan->rx_crc[chan->crc_prv]) & 0xFF; + chan->rx_crc[chan->crc_cur] = chan->rx_crc[chan->crc_prv] >> 8; + chan->rx_crc[chan->crc_cur] &= 0x00FF; + chan->rx_crc[chan->crc_cur] ^= CRC_TABLE[chan->rx_crc_tmp]; + chan->rx_crc[chan->crc_cur] &= 0xFFFF; + INC_CRC_CNT(chan->crc_prv); +} + +static void calc_tx_crc(bitstrm_private_area_t *chan,unsigned char byte) +{ + chan->tx_crc_tmp = (byte ^ chan->tx_crc) & 0xFF; + chan->tx_crc = chan->tx_crc >> 8; + chan->tx_crc &= 0x00FF; + chan->tx_crc ^= CRC_TABLE[chan->tx_crc_tmp]; + chan->tx_crc &= 0xFFFF; +} + +static void tx_up_decode_pkt(bitstrm_private_area_t *chan) +{ + unsigned char *buf; + struct sk_buff *skb = dev_alloc_skb(chan->rx_decode_len+sizeof(api_rx_hdr_t)); + if (!skb){ + DEBUG_EVENT( "%s: HDLC Tx up: failed to allocate memory!\n", + chan->card->devname); + chan->card->wandev.stats.rx_dropped++; + chan->ifstats.rx_dropped++; + return; + } + + if (chan->common.usedby==STACK){ + + if (wanpipe_lip_rx(chan,skb) != 0){ + dev_kfree_skb_any(skb); + chan->card->wandev.stats.rx_dropped++; + chan->ifstats.rx_dropped++; + }else{ + chan->card->wandev.stats.rx_packets++; + chan->card->wandev.stats.rx_bytes += chan->rx_decode_len; + chan->ifstats.rx_packets++; + chan->ifstats.rx_bytes+=chan->rx_decode_len; + } + + }else if (chan->common.usedby==API || chan->common.usedby==SWITCH){ + + buf = skb_put(skb,sizeof(api_rx_hdr_t)); + memset(buf, 0, sizeof(api_rx_hdr_t)); + + buf = skb_put(skb,chan->rx_decode_len); + memcpy(buf, + chan->rx_decode_buf, + chan->rx_decode_len); + + skb->protocol = htons(PVC_PROT); + skb->mac.raw = skb->data; + skb->dev = chan->common.dev; + skb->pkt_type = WAN_PACKET_DATA; + + if (wan_api_rx(chan,skb) != 0){ + dev_kfree_skb_any(skb); + chan->card->wandev.stats.rx_dropped++; + chan->ifstats.rx_dropped++; + }else{ + chan->card->wandev.stats.rx_packets++; + chan->card->wandev.stats.rx_bytes += chan->rx_decode_len; + chan->ifstats.rx_packets++; + chan->ifstats.rx_bytes+=chan->rx_decode_len; + } + }else{ + + if (chan->rx_decode_len <= 2){ + dev_kfree_skb_any(skb); + chan->card->wandev.stats.rx_frame_errors++; + chan->ifstats.rx_frame_errors++; + }else{ + skb_reserve(skb,4); + + buf=skb_put(skb,(chan->rx_decode_len-2)); + memcpy(buf, + chan->rx_decode_buf, + chan->rx_decode_len-2); + + chan->card->wandev.stats.rx_packets++; + chan->card->wandev.stats.rx_bytes += chan->rx_decode_len; + chan->ifstats.rx_packets++; + chan->ifstats.rx_bytes+=chan->rx_decode_len; + + skb->mac.raw = skb->data; + skb->dev = chan->common.dev; + + if (chan->protocol == WANCONFIG_PPP || + chan->protocol == WANCONFIG_CHDLC){ + + skb->protocol = htons(ETH_P_WAN_PPP); + wp_sppp_input(chan->common.dev,skb); + + }else{ + skb->protocol = htons(ETH_P_IP); + netif_rx(skb); + } + } + } + return; + +} + +static void init_rx_hdlc_eng(sdla_t *card, bitstrm_private_area_t *bstrm_priv_area, int hard) +{ + if (hard){ + bstrm_priv_area->hdlc_flag=0; + set_bit(NO_FLAG,&bstrm_priv_area->hdlc_flag); + } + + bstrm_priv_area->rx_decode_len=0; + bstrm_priv_area->rx_decode_buf[bstrm_priv_area->rx_decode_len]=0; + bstrm_priv_area->rx_decode_bit_cnt=0; + bstrm_priv_area->rx_decode_onecnt=0; + + bstrm_priv_area->rx_crc[0]=-1; + bstrm_priv_area->rx_crc[1]=-1; + bstrm_priv_area->rx_crc[2]=-1; + bstrm_priv_area->crc_cur=0; + bstrm_priv_area->crc_prv=0; +} + +static int hdlc_encode(bitstrm_private_area_t *chan,struct sk_buff **skb_ptr) +{ + struct sk_buff *skb=*skb_ptr; + unsigned char crc_tmp; + int i; + unsigned char *data_ptr; +#if 0 + chan->tx_decode_len=0; + + /* First byte of the outgoing bit stream must be a flag. + * The current flag has been properly bit shifted based on the + * last packet we sent */ + DEBUG_TX("TX: Flag Idle 0x%02X, Offset Data 0x%02X, BitCnt %i\n", + chan->tx_flag_idle,chan->tx_flag_offset_data,chan->tx_flag_offset); + + chan->tx_decode_buf[chan->tx_decode_len] = chan->tx_flag_idle; + chan->tx_decode_len++; + chan->tx_decode_buf[chan->tx_decode_len] = chan->tx_flag_idle; + chan->tx_decode_len++; + + /* Initialize the next byte in the encode buffer as + * well as the crc bytes */ + chan->tx_decode_buf[chan->tx_decode_len]=0; + chan->tx_crc=-1; + chan->tx_crc_fin=0; + + /* Before encoding data bytes, we must update the bit + * shift offset, casued by previous bit suffing. This, + * will shift the whole data packet by maximum of 7 bits */ + chan->tx_decode_bit_cnt=chan->tx_flag_offset; + chan->tx_decode_buf[chan->tx_decode_len]=chan->tx_flag_offset_data; + chan->tx_decode_onecnt=0; +#else + chan->tx_decode_len=0; + chan->tx_crc=-1; + chan->tx_crc_fin=0; + chan->tx_decode_onecnt=0; + + memset(&chan->tx_decode_buf[0],0,3); + chan->tx_decode_bit_cnt=0; + +#ifdef HDLC_IDLE_ABORT + chan->tx_flag_idle=0x7E; + chan->tx_flag_offset_data=0; + chan->tx_flag_offset=0; + encode_byte(chan,&chan->tx_flag_idle,2); +#else + encode_byte(chan,&chan->tx_flag_idle,2); + encode_byte(chan,&chan->tx_flag_idle,2); + encode_byte(chan,&chan->tx_flag_offset_data,2); + + if (!chan->seven_bit_hdlc || chan->tx_flag_offset < 5){ + chan->tx_decode_len--; + } +#endif + + + DEBUG_TX("TX: Flag Idle 0x%02X, Offset Data 0x%02X, FlagBitCnt %i, DataBitCnt %i\n", + chan->tx_flag_idle, + chan->tx_flag_offset_data, + chan->tx_flag_offset, + chan->tx_decode_bit_cnt); + + if (chan->seven_bit_hdlc){ + chan->tx_decode_bit_cnt= + ((chan->tx_flag_offset+2)%chan->bits_in_byte); + }else{ + chan->tx_decode_bit_cnt=chan->tx_flag_offset; + } + + DEBUG_TX("TX: DataBitCnt %i\n", + chan->tx_decode_bit_cnt); + + chan->tx_decode_onecnt=0; +#endif + /* For all bytes in an incoming data packet, calculate + * crc bytes, and encode each byte into the outgoing + * bit stream (encoding buffer). */ + for (i=0;ilen;i++){ + calc_tx_crc(chan,skb->data[i]); + encode_byte(chan,&skb->data[i],0); + } + + /* Decode and bit shift the calculated CRC values */ + FLIP_CRC(chan->tx_crc,chan->tx_crc_fin); + DECODE_CRC(chan->tx_crc_fin); + + /* Encode the crc values into the bit stream + * encode buffer */ + crc_tmp=(chan->tx_crc_fin>>8)&0xFF; + encode_byte(chan,&crc_tmp,0); + crc_tmp=(chan->tx_crc_fin)&0xFF; + encode_byte(chan,&crc_tmp,0); + + /* End the bit stream encode buffer with the + * closing flag */ + + + encode_byte(chan,&chan->tx_flag,1); + +#ifdef HDLC_IDLE_ABORT + chan->tx_flag_idle=0xFF; + chan->tx_flag_offset_data=0; + encode_byte(chan,&chan->tx_flag_idle,2); +#endif + + /* We will re-use the incoming skb buffer to + * store the newly created encoded bit stream. + * Therefore, reset the skb buffer to 0, thus + * erasing the incoming data packet */ + skb_trim(skb,0); + + /* Make sure that the current skb buffer has + * enough room to hold the newly created encoded + * bit stream. Due to bit stuffing, hdlc headers + * and crc the encoded bit stream is bigger than + * the incoming data packet. If we need more room + * reallocate a new buffer */ + if (skb_tailroom(skb) < chan->tx_decode_len){ + struct sk_buff *skb2 = NULL; + skb2 = dev_alloc_skb(chan->tx_decode_len+15); + if (!skb2){ + return -ENOMEM; + } + + wan_dev_kfree_skb(skb,FREE_WRITE); + skb=skb2; + *skb_ptr=skb2; + + wan_skb_unlink(skb); + } + + /* Copy the encoded bit stream into the skb buffer which will be + * sent down to the card */ + data_ptr=skb_put(skb,chan->tx_decode_len); + memcpy(data_ptr,chan->tx_decode_buf,chan->tx_decode_len); + +#if 0 + { + int i; + DEBUG_EVENT( "ENCPKT: "); + for (i=0;itx_decode_len;i++){ + printk("%02X ", chan->tx_decode_buf[i]); + } + printk("\n"); + DEBUG_EVENT( "\n"); + } + +#endif + + /* Reset the encode buffer */ + chan->tx_decode_len=0; + + /* Record the tx idle flag that + * should follow after this packet + * is sent out the port */ + skb->cb[0]=chan->tx_flag_idle; + +#if 0 + { + int i; + unsigned char *data=wan_skb_data(skb); + DEBUG_EVENT("PKT: "); + for (i=0;itx_decode_buf[chan->tx_decode_len] |= (1<< chan->tx_decode_bit_cnt); + if (++chan->tx_decode_bit_cnt >= chan->bits_in_byte){ + ++chan->tx_decode_len; + chan->tx_decode_buf[chan->tx_decode_len]=0; + chan->tx_decode_bit_cnt=0; + } + + if (++chan->tx_decode_onecnt == 5){ + /* Stuff a zero bit */ + if (!flag){ + if (++chan->tx_decode_bit_cnt >= chan->bits_in_byte){ + ++chan->tx_decode_len; + chan->tx_decode_buf[chan->tx_decode_len]=0; + chan->tx_decode_bit_cnt=0; + } + } + chan->tx_decode_onecnt=0; + } + }else{ + /* Got 0 */ + chan->tx_decode_onecnt=0; + if (++chan->tx_decode_bit_cnt >= chan->bits_in_byte){ + ++chan->tx_decode_len; + chan->tx_decode_buf[chan->tx_decode_len]=0; + chan->tx_decode_bit_cnt=0; + } + } + } + + if (flag == 1){ + /* The closing flag has been encoded into the + * buffer. We must check how much has the last flag + * bit shifted due to bit stuffing of previous data. + * The maximum bit shift is 7 bits, thus a standard + * flag 0x7E can be have 7 different values. The + * FLAG buffer will give us a correct flag, based + * on the bit shift count. */ + chan->tx_flag_idle = FLAG[chan->tx_decode_bit_cnt]; + chan->tx_flag_offset=chan->tx_decode_bit_cnt; + + /* The bit shifted part of the flag, that crossed the byte + * boudary, must be saved, and inserted at the beginning of + * the next outgoing packet */ + chan->tx_flag_offset_data=chan->tx_decode_buf[chan->tx_decode_len]; + } + + return; +} + + +/****** Interrupt Handlers **************************************************/ + +/*============================================================================ + * Cisco HDLC interrupt service routine. + */ +static void wpbit_isr (sdla_t* card) +{ + unsigned char intr_type = 0x00; + GLOBAL_INFORMATION_STRUCT global_info; + int i; + + if (!card->hw){ + return; + } + + card->statistics.isr_entry++; + + /* if critical due to peripheral operations + * ie. update() or getstats() then reset the interrupt and + * wait for the board to retrigger. + */ + if(test_bit(PERI_CRIT, (void*)&card->wandev.critical)) { + DEBUG_EVENT( "ISR CRIT TO PERI\n"); + goto isr_done; + } + + card->hw_iface.peek(card->hw, card->intr_type_off, &intr_type, 1); + switch(intr_type) { + + case RX_APP_INT_PEND: /* 0x01: receive interrupt */ + card->statistics.isr_rx++; + rx_intr(card); + break; + + case TX_APP_INT_PEND: /* 0x02: transmit interrupt */ + + card->statistics.isr_tx++; + + // Do not disable Tx interrupt + // for TE1 cards. + if(card->u.b.serial) { + card->hw_iface.clear_bit(card->hw, card->intr_perm_off, APP_INT_ON_TX_BLOCK); + } + + if (!card->u.b.sw_card){ + tasklet_hi_schedule(&card->u.b.wanpipe_tx_task); + }else{ + bstrm_tx_bh((unsigned long)card); + } + break; + + case COMMAND_COMPLETE_APP_INT_PEND:/* 0x04: cmd cplt */ + ++ card->timer_int_enabled; + break; + + case BSTRM_EXCEP_COND_APP_INT_PEND: /* 0x20 */ + process_bstrm_exception(card); + break; + + case GLOBAL_EXCEP_COND_APP_INT_PEND: + process_global_exception(card); + + if (IS_56K_CARD(card) || IS_TE1_CARD(card)) { + FRONT_END_STATUS_STRUCT FE_status; + + card->hw_iface.peek(card->hw, card->fe_status_off, + &FE_status, sizeof(FE_status)); + FE_status.opp_flag = 0x01; + card->hw_iface.poke(card->hw, card->fe_status_off, + &FE_status, sizeof(FE_status)); + } + + break; + + case TIMER_APP_INT_PEND: + timer_intr(card); + break; + + default: + card->statistics.isr_spurious++; + DEBUG_EVENT( "%s: spurious interrupt 0x%02X!\n", + card->devname, intr_type); + card->hw_iface.peek(card->hw, card->flags_off + offsetof(SHARED_MEMORY_INFO_STRUCT, global_info_struct), + &global_info, sizeof(global_info)); + DEBUG_EVENT( "Code name: "); + for(i = 0; i < 4; i ++){ + printk("%c", global_info.code_name[i]); + } + printk("\n"); + DEBUG_EVENT( "\nCode version: "); + for(i = 0; i < 4; i ++){ + printk("%c", global_info.code_version[i]); + } + printk("\n"); + break; + } + +isr_done: + + clear_bit(0,&card->in_isr); + card->hw_iface.poke_byte(card->hw, card->intr_type_off, 0x00); + return; +} + +/*============================================================================ + * Receive interrupt handler. + */ +static void rx_intr (sdla_t* card) +{ + BSTRM_DATA_RX_STATUS_EL_STRUCT rxbuf; + struct sk_buff *skb; + unsigned len; + unsigned addr; + unsigned char *buf; + int i; + + card->hw_iface.peek(card->hw, card->u.b.rxmb_off, &rxbuf, sizeof(rxbuf)); + addr = rxbuf.ptr_data_bfr; + if (rxbuf.opp_flag != 0x01) { + GLOBAL_INFORMATION_STRUCT global_info; + + card->hw_iface.peek(card->hw, card->flags_off + offsetof(SHARED_MEMORY_INFO_STRUCT, global_info_struct), + &global_info, sizeof(global_info)); + DEBUG_EVENT( + "%s: corrupted Rx buffer @ 0x%X, flag = 0x%02X!\n", + card->devname, (unsigned)card->u.b.rxmb_off, rxbuf.opp_flag); + DEBUG_EVENT( "Code name: "); + for(i = 0; i < 4; i ++) + DEBUG_EVENT( "%c", + global_info.code_name[i]); + DEBUG_EVENT( "\nCode version: "); + for(i = 0; i < 4; i ++) + DEBUG_EVENT( "%c", + global_info.code_version[i]); + DEBUG_EVENT( "\n"); + + + /* Bug Fix: Mar 6 2000 + * If we get a corrupted mailbox, it measn that driver + * is out of sync with the firmware. There is no recovery. + * If we don't turn off all interrupts for this card + * the machine will crash. + */ + DEBUG_EVENT( "%s: Critical router failure ...!!!\n", card->devname); + DEBUG_EVENT( "Please contact Sangoma Technologies !\n"); + bstrm_set_intr_mode(card,0); + return; + } + + len = rxbuf.block_length; + if (len != card->u.b.cfg.rx_complete_length){ + DEBUG_EVENT( "%s: Invalid rx packet: Len=%i < %i\n", + card->devname,len,card->u.b.cfg.rx_complete_length); + } + + /* Obtain a free skb packet from the bh rx queue. + * The packet has been pre allocated to the max rx + * size */ + skb = bh_enqueue(card); + if (!skb){ + ++card->wandev.stats.rx_dropped; + if (net_ratelimit()){ + DEBUG_EVENT( "%s: Critical Error! Rx dropped Rx CH Free=%i Full=%i\n", + card->devname, + wan_skb_queue_len(&card->u.b.rx_isr_queue), + wan_skb_queue_len(&card->u.b.rx_isr_free_queue)); + } + goto kick_rx_bh; + } + + buf = skb_put(skb, len); + card->hw_iface.peek(card->hw, addr, buf, len); + +// DEBUG_EVENT( "PKT (rxbug=%lX, addr=%X, len=%d): ", (unsigned long)card->u.b.rxmb, addr,len); +// { +// int i, flag; +// for (i=0;iu.b.cfg.rbs_map){ + int channel_range = GET_TE_CHANNEL_RANGE(&card->fe); + card->hw_iface.peek(card->hw, card->fe.te_param.ptr_te_Rx_sig_off, + &card->u.b.rbs_sig[0], channel_range); + //card->hw_iface.peek(card->hw, card->u_fe.te_iface.ptr_te_Rx_sig_off, + // &card->u.b.rbs_sig[0], channel_range); + } + + skb_queue_tail(&card->u.b.rx_isr_queue,skb); + +kick_rx_bh: + + if (!card->u.b.sw_card){ + tasklet_hi_schedule(&card->u.b.wanpipe_rx_task); + }else{ + bstrm_rx_bh((u32)card); + } + + /* Release buffer element and calculate a pointer to the next one */ + rxbuf.opp_flag = 0x00; + card->hw_iface.poke(card->hw, card->u.b.rxmb_off, &rxbuf, sizeof(rxbuf)); + card->u.b.rxmb_off += sizeof(rxbuf); + if (card->u.b.rxmb_off > card->u.b.rxbuf_last_off){ + card->u.b.rxmb_off = card->u.b.rxbuf_base_off; + } +} + +/*============================================================================ + * Timer interrupt handler. + * The timer interrupt is used for two purposes: + * 1) Processing udp calls from 'cpipemon'. + * 2) Reading board-level statistics for updating the proc file system. + */ +void timer_intr(sdla_t *card) +{ + netdevice_t* dev; + bitstrm_private_area_t* bstrm_priv_area = NULL; + + /* TE timer interrupt */ + if (card->u.b.timer_int_enabled & TMR_INT_ENABLED_TE) { + card->wandev.fe_iface.polling(&card->fe); + bstrm_handle_front_end_state(card); + card->u.b.timer_int_enabled &= ~TMR_INT_ENABLED_TE; + } + + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + if (dev == NULL){ + card->u.b.timer_int_enabled = 0; + goto timer_intr_exit; + } + + bstrm_priv_area = dev->priv; + + /* process a udp call if pending */ +#if 0 + if(card->u.b.timer_int_enabled & TMR_INT_ENABLED_UDP) { + process_udp_mgmt_pkt(card, dev, bstrm_priv_area); + card->u.b.timer_int_enabled &= ~TMR_INT_ENABLED_UDP; + } +#endif + + /* read the communications statistics if required */ + if(card->u.b.timer_int_enabled & TMR_INT_ENABLED_UPDATE) { + update_comms_stats(card, bstrm_priv_area); + if(!(--bstrm_priv_area->update_comms_stats)) { + card->u.b.timer_int_enabled &= + ~TMR_INT_ENABLED_UPDATE; + } + } + +timer_intr_exit: + + /* only disable the timer interrupt if there are no udp or statistic */ + /* updates pending */ + if(!card->u.b.timer_int_enabled) { + card->hw_iface.clear_bit(card->hw, card->intr_perm_off, APP_INT_ON_TIMER); + } +} + +/*------------------------------------------------------------------------------ + Miscellaneous Functions + - set_bstrm_config() used to set configuration options on the board +------------------------------------------------------------------------------*/ + +static int set_bstrm_config(sdla_t* card) +{ + BSTRM_CONFIGURATION_STRUCT cfg; + int rc; + //wan_mbox_t* mb = &card->wan_mbox; + + memset(&cfg, 0, sizeof(BSTRM_CONFIGURATION_STRUCT)); + + if(card->wandev.clocking){ + cfg.baud_rate = card->wandev.bps; + } + + cfg.line_config_options = (card->wandev.interface == WANOPT_RS232) ? + INTERFACE_LEVEL_RS232 : INTERFACE_LEVEL_V35; + + cfg.modem_config_options = 0; + cfg.modem_status_timer = 500; + + cfg.API_options = 0; /*PERMIT_APP_INT_TX_RX_BFR_ERR*/ + + DEBUG_EVENT("%s: Sync Options = 0x%X\n", + card->devname, card->u.b.cfg.sync_options); + + cfg.SYNC_options = card->u.b.cfg.sync_options; + cfg.Rx_sync_char = card->u.b.cfg.rx_sync_char; + cfg.monosync_Tx_time_fill_char = card->u.b.cfg.monosync_tx_time_fill_char; + + cfg.buffer_options=0; + + cfg.max_length_Tx_data_block = card->u.b.cfg.max_length_tx_data_block; + cfg.Rx_complete_length = card->u.b.cfg.rx_complete_length; + cfg.Rx_complete_timer = card->u.b.cfg.rx_complete_timer; + + cfg.statistics_options = TX_DATA_BYTE_COUNT_STAT | + RX_DATA_BYTE_COUNT_STAT | + TX_THROUGHPUT_STAT | + RX_THROUGHPUT_STAT; + + rc = bstrm_configure(card, &cfg); + + return rc; +} + + +/*============================================================================ + * Process global exception condition + */ +static int process_global_exception(sdla_t *card) +{ + wan_mbox_t* mbox = &card->wan_mbox; + int rc; + + mbox->wan_data_len = 0; + mbox->wan_command = READ_GLOBAL_EXCEPTION_CONDITION; + rc = card->hw_iface.cmd(card->hw, card->mbox_off, mbox); + if(rc != WAN_CMD_TIMEOUT ){ + + switch(mbox->wan_return_code) { + + case EXCEP_MODEM_STATUS_CHANGE: + + if (IS_TE1_CARD(card)){ + card->wandev.fe_iface.isr(&card->fe); + bstrm_handle_front_end_state(card); + break; + } + + if (IS_56K_CARD(card)) { + + FRONT_END_STATUS_STRUCT FE_status; + + card->hw_iface.peek(card->hw, + card->fe_status_off, + &FE_status, + sizeof(FE_status)); + + card->fe.fe_param.k56_param.RR8_reg_56k = + FE_status.FE_U.stat_56k.RR8_56k; + card->fe.fe_param.k56_param.RRA_reg_56k = + FE_status.FE_U.stat_56k.RRA_56k; + card->fe.fe_param.k56_param.RRC_reg_56k = + FE_status.FE_U.stat_56k.RRC_56k; + card->wandev.fe_iface.read_alarm(&card->fe, 0); + + bstrm_handle_front_end_state(card); + break; + + } + + DEBUG_EVENT( "%s: Modem status change\n", + card->devname); + + switch(mbox->wan_data[0] & (DCD_HIGH | CTS_HIGH)) { + case (DCD_HIGH): + DEBUG_EVENT( "%s: DCD high, CTS low\n",card->devname); + break; + case (CTS_HIGH): + DEBUG_EVENT( "%s: DCD low, CTS high\n",card->devname); + break; + case ((DCD_HIGH | CTS_HIGH)): + DEBUG_EVENT( "%s: DCD high, CTS high\n",card->devname); + break; + default: + DEBUG_EVENT( "%s: DCD low, CTS low\n",card->devname); + break; + } + break; + + default: + DEBUG_EVENT( "%s: Global exception %x\n", + card->devname, mbox->wan_return_code); + break; + } + } + return 0; +} + + +/*============================================================================ + * Process chdlc exception condition + */ +static int process_bstrm_exception(sdla_t *card) +{ + wan_mbox_t* mb = &card->wan_mbox; + int rc; + + mb->wan_data_len = 0; + mb->wan_command = READ_BSTRM_EXCEPTION_CONDITION; + rc = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if(rc != WAN_CMD_TIMEOUT) { + switch (rc) { + + case NO_BSTRM_EXCEP_COND_TO_REPORT: + DEBUG_EVENT( "%s: No exceptions reported.\n", + card->devname); + break; + + case EXCEP_RX_DISCARD: + case EXCEP_TX_IDLE: + { + RX_DISC_TX_IDLE_EXCEP_STRUCT *idle_strct = + (RX_DISC_TX_IDLE_EXCEP_STRUCT *)mb->wan_data; + + if (idle_strct->Rx_discard_count){ + DEBUG_EVENT( "%s: Error Rx discard %lu\n", + card->devname,idle_strct->Rx_discard_count); + } + if (idle_strct->Tx_idle_count){ + DEBUG_EVENT( "%s: Error Tx idle count %lu\n", + card->devname,idle_strct->Tx_idle_count); + } + } + break; + + case EXCEP_SYNC_LOST: + DEBUG_EVENT("%s: Bitstrm Exception: Sync Lost!\n",card->devname); + break; + + case EXCEP_SYNC_ACHIEVED: + DEBUG_EVENT("%s: Bitstrm Exception: Sync Achieved!\n",card->devname); + break; + + default: + DEBUG_EVENT( "%s: Bstrm Exception condition 0x%X\n", + card->devname,rc); + break; + } + } + return 0; +} + + +/*============================================================================= + * Process UDP management packet. + */ + +static int process_udp_mgmt_pkt(sdla_t* card, netdevice_t* dev, + bitstrm_private_area_t* bstrm_priv_area, + char local_dev) +{ + unsigned char *buf; + unsigned int len; + struct sk_buff *new_skb; + int udp_mgmt_req_valid = 1; + wan_udp_pkt_t *wan_udp_pkt; + wan_mbox_t *mb = &card->wan_mbox; + struct timeval tv; + int err; + + wan_udp_pkt = (wan_udp_pkt_t *) bstrm_priv_area->udp_pkt_data; + + if(!local_dev){ + + if(bstrm_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK){ + + /* Only these commands are support for remote debugging. + * All others are not */ + switch(wan_udp_pkt->wan_udp_command){ + + case READ_GLOBAL_STATISTICS: + case READ_MODEM_STATUS: + case READ_BSTRM_STATUS: + case READ_COMMS_ERROR_STATS: + case READ_BSTRM_OPERATIONAL_STATS: + case BPIPE_ROUTER_UP_TIME: + + /* These two commands are executed for + * each request */ + case READ_BSTRM_CONFIGURATION: + case READ_BSTRM_CODE_VERSION: + udp_mgmt_req_valid = 1; + break; + default: + udp_mgmt_req_valid = 0; + break; + } + } + }else{ + udp_mgmt_req_valid=1; + } + + if(!udp_mgmt_req_valid) { + + /* set length to 0 */ + wan_udp_pkt->wan_udp_data_len = 0; + + /* set return code */ + wan_udp_pkt->wan_udp_return_code = 0xCD; + + if (net_ratelimit()){ + DEBUG_EVENT( + "%s: Warning, Illegal UDP command attempted from network: %x\n", + card->devname,wan_udp_pkt->wan_udp_command); + } + + } else { + + switch(wan_udp_pkt->wan_udp_command) { + + case BPIPE_ROUTER_UP_TIME: + do_gettimeofday( &tv ); + bstrm_priv_area->router_up_time = tv.tv_sec - + bstrm_priv_area->router_start_time; + *(unsigned long *)&wan_udp_pkt->wan_udp_data = + bstrm_priv_area->router_up_time; + mb->wan_data_len = sizeof(unsigned long); + wan_udp_pkt->wan_udp_data_len = sizeof(unsigned long); + wan_udp_pkt->wan_udp_return_code = 0; + break; + + case WAN_GET_MEDIA_TYPE: + case WAN_FE_GET_STAT: + case WAN_FE_SET_LB_MODE: + case WAN_FE_FLUSH_PMON: + case WAN_FE_GET_CFG: + if (IS_TE1_CARD(card)){ + card->wandev.fe_iface.process_udp( + &card->fe, + &wan_udp_pkt->wan_udp_cmd, + &wan_udp_pkt->wan_udp_data[0]); + }else if (IS_56K_CARD(card)){ + card->wandev.fe_iface.process_udp( + &card->fe, + &wan_udp_pkt->wan_udp_cmd, + &wan_udp_pkt->wan_udp_data[0]); + }else{ + if (wan_udp_pkt->wan_udp_command == WAN_GET_MEDIA_TYPE){ + wan_udp_pkt->wan_udp_data_len = sizeof(unsigned char); + wan_udp_pkt->wan_udp_return_code = CMD_OK; + }else{ + wan_udp_pkt->wan_udp_return_code = WAN_UDP_INVALID_CMD; + } + } + mb->wan_data_len = wan_udp_pkt->wan_udp_data_len; + break; + + case WAN_GET_PROTOCOL: + wan_udp_pkt->wan_udp_chdlc_num_frames = card->wandev.config_id; + wan_udp_pkt->wan_udp_return_code = CMD_OK; + mb->wan_data_len = wan_udp_pkt->wan_udp_data_len = 1; + break; + + case WAN_GET_PLATFORM: + wan_udp_pkt->wan_udp_data[0] = WAN_LINUX_PLATFORM; + wan_udp_pkt->wan_udp_return_code = CMD_OK; + mb->wan_data_len = wan_udp_pkt->wan_udp_data_len = 1; + break; + +#ifdef LINEPROBE + case ENABLE_BSTRM_COMMUNICATIONS: + DEBUG_DBG("%s: process_udp_mgmt_pkt(): ENABLE_BSTRM_COMMUNICATIONS\n",card->devname); + if (IS_TE1_CARD(card)){ + /* + * If application enables communications, there + * must be no alarms.If no alarms, manualy (arg + * 2 is 1) poll the alarms again to set the + * Front End to the correct state. */ + card->wandev.fe_iface.read_alarm(&card->fe, 1); + setup_api_timeslots(card); + } + wan_udp_pkt->wan_udp_return_code = api_enable_comms(card); + break; + + case DISABLE_BSTRM_COMMUNICATIONS: + DEBUG_DBG("%s: process_udp_mgmt_pkt():DISABLE_BSTRM_COMMUNICATIONS\n",card->devname); + wan_udp_pkt->wan_udp_return_code = api_disable_comms(card); + break; +#endif //LINEPROBE + + default: + /* it's a board command */ + mb->wan_command = wan_udp_pkt->wan_udp_command; + mb->wan_data_len = wan_udp_pkt->wan_udp_data_len; + if (mb->wan_data_len) { + memcpy(&mb->wan_data, + (unsigned char *)wan_udp_pkt->wan_udp_data, + mb->wan_data_len); + } + /* run the command on the board */ + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err == OK) { + /* copy the result back to our buffer */ + memcpy(&wan_udp_pkt->wan_udp_cmd, mb, sizeof(wan_cmd_t)); + + if (mb->wan_data_len) { + memcpy(&wan_udp_pkt->wan_udp_data, + &mb->wan_data, + mb->wan_data_len); + } + } + } + + } /* end of else */ + + /* Fill UDP TTL */ + wan_udp_pkt->wan_ip_ttl= card->wandev.ttl; + + if (local_dev){ + wan_udp_pkt->wan_udp_request_reply = UDPMGMT_REPLY; + return 0; + } + + len = wan_reply_udp(card,bstrm_priv_area->udp_pkt_data, mb->wan_data_len); + + + if(bstrm_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK){ + /* Must check if we interrupted if_send() routine. The + * tx buffers might be used. If so drop the packet */ + //if (!test_bit(SEND_CRIT,&card->wandev.critical)) { + // + // if(!bstrm_send(card, bstrm_priv_area->udp_pkt_data, len)) { + // ++ card->wandev.stats.tx_packets; + // card->wandev.stats.tx_bytes += len; + // } + //} + } else { + + /* Pass it up the stack + Allocate socket buffer */ + if ((new_skb = dev_alloc_skb(len)) != NULL) { + /* copy data into new_skb */ + + buf = skb_put(new_skb, len); + memcpy(buf, bstrm_priv_area->udp_pkt_data, len); + + /* Decapsulate pkt and pass it up the protocol stack */ + new_skb->protocol = htons(ETH_P_IP); + new_skb->dev = dev; + new_skb->mac.raw = new_skb->data; + + netif_rx(new_skb); + } else { + + DEBUG_EVENT( "%s: no socket buffers available!\n", + card->devname); + } + } + + atomic_set(&bstrm_priv_area->udp_pkt_len,0); + + return 0; +} + +#ifdef LINEPROBE + +static int api_enable_comms(sdla_t * card) +{ + int rc; + + if (IS_TE1_CARD(card)){ + if (card->fe.fe_status == FE_CONNECTED) { + if (card->u.b.state != WAN_CONNECTED) { + if(card->comm_enabled == 0) { + rc = bstrm_comm_enable (card); + if (rc == 0){ + port_set_state(card, WAN_CONNECTED); + } + }else{ + rc = COMMS_ALREADY_ENABLED; + } + }else{ + rc = IF_IN_DISCONNECED_STATE; + } + }else{ + rc = FRONT_END_IN_DISCONNECTED_STATE; + } + }else{ + rc = 0; + /* FIXME: Remove this line */ + card->fe.fe_status = FE_CONNECTED; + card->u.b.state = WAN_DISCONNECTED; + port_set_state(card, WAN_CONNECTED); + } + + DEBUG_DBG("api_enable_comms(): rc : 0x%X\n", rc); + return rc; +} + +static int api_disable_comms(sdla_t* card) +{ + int rc; + + port_set_state(card, WAN_DISCONNECTED); + + if(card->comm_enabled != 0) { + rc = bstrm_comm_disable (card); + }else{ + rc = COMMS_ALREADY_DISABLED; + } + + DEBUG_DBG("api_disable_comms(): rc : 0x%X\n", rc); + return rc; +} + +static int setup_api_timeslots(sdla_t* card) +{ + int i; + bitstrm_private_area_t* bstrm_priv_area; + netdevice_t* dev; + + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + if (!dev) return -EINVAL; + bstrm_priv_area = dev->priv; + + memset(card->u.b.time_slot_map,0,sizeof(card->u.b.time_slot_map)); + + bstrm_priv_area->time_slot_map = 0xFFFFFFFF; + card->u.b.time_slots=NUM_OF_T1_CHANNELS; + + if (IS_E1_CARD(card)){ + bstrm_priv_area->time_slot_map &= 0x7FFFFFFF; + card->u.b.time_slots=NUM_OF_E1_CHANNELS; + } + + bstrm_priv_area->max_tx_up_size=MAX_T1_CHAN_TX_UP_SIZE; + + if (IS_E1_CARD(card)){ + //must be divisible by 31 and less than MAX_T1_CHAN_TX_UP_SIZE. + bstrm_priv_area->max_tx_up_size = + MAX_T1_CHAN_TX_UP_SIZE - (MAX_T1_CHAN_TX_UP_SIZE % (NUM_OF_E1_CHANNELS-1));//1178 + } + + bstrm_priv_area->time_slots = 0; + + for (i=0;iu.b.time_slots;i++){ + if (test_bit(i,&bstrm_priv_area->time_slot_map)){ + bstrm_priv_area->time_slots++; + } + } + + if (bstrm_priv_area->max_tx_up_size % bstrm_priv_area->time_slots){ + bstrm_priv_area->max_tx_up_size-= + bstrm_priv_area->max_tx_up_size % + bstrm_priv_area->time_slots; + bstrm_priv_area->max_tx_up_size+=bstrm_priv_area->time_slots; + } + + DEBUG_DBG("\n"); + DEBUG_DBG("%s: Configuring %s: \n", + card->devname, + bstrm_priv_area->if_name); + DEBUG_DBG("%s: Tx Idle Flag =0x%X\n", + card->devname, + bstrm_priv_area->tx_idle_flag); + + + DEBUG_DBG("%s: Max Tx Up Size =%i\n", + card->devname, + bstrm_priv_area->max_tx_up_size); + + DEBUG_DBG("%s: HDLC Enc/Dec =%s Bits=%d\n", + card->devname, + bstrm_priv_area->hdlc_eng?"ON":"OFF", + bstrm_priv_area->seven_bit_hdlc?7:8); + + bstrm_priv_area->hdlc_flag=0; + set_bit(NO_FLAG,&bstrm_priv_area->hdlc_flag); + DEBUG_DBG("\n"); + + bstrm_priv_area->rx_crc[0]=-1; + bstrm_priv_area->rx_crc[1]=-1; + bstrm_priv_area->rx_crc[2]=-1; + bstrm_priv_area->tx_crc=-1; + bstrm_priv_area->tx_flag= 0x7E; //card->u.b.cfg.monosync_tx_time_fill_char; + bstrm_priv_area->tx_flag_idle= 0x7E; //card->u.b.cfg.monosync_tx_time_fill_char; + + if (IS_TE1_CARD(card)){ + + DEBUG_DBG("%s: entering bind loop (card->u.b.time_slots : %d).\n", + card->devname, card->u.b.time_slots); + + /*Bind an interface to a time slot map.*/ + for (i=0;iu.b.time_slots;i++){ + + if (test_bit(i,&bstrm_priv_area->time_slot_map)){ + if (IS_E1_CARD(card)){ + + DEBUG_DBG("Binding interface %s for timeslot %i\n", + bstrm_priv_area->if_name, i+1); + + card->u.b.time_slot_map[i+1] = bstrm_priv_area; + }else{ + + DEBUG_DBG("Binding interface %s for timeslot %i\n", + bstrm_priv_area->if_name, i); + + card->u.b.time_slot_map[i] = bstrm_priv_area; + } + + bstrm_priv_area->time_slots++; + } + } + } + + card->u.b.tx_chan_multiple = 30; + + DEBUG_DBG("%s: Configuring: \n",card->devname); + if (IS_TE1_CARD(card)){ + DEBUG_DBG("%s: ChanNum =%i\n", + card->devname, card->u.b.time_slots); + DEBUG_DBG("%s: TxChanMult =%i\n", + card->devname, card->u.b.tx_chan_multiple); + } + DEBUG_DBG("%s: TxMTU =%i\n", + card->devname, card->u.b.cfg.max_length_tx_data_block); + DEBUG_DBG("%s: RxMTU =%i\n", + card->devname, card->u.b.cfg.rx_complete_length); + DEBUG_DBG("%s: IdleFlag =0x%x\n", + card->devname, + card->u.b.cfg.monosync_tx_time_fill_char); + + return 0; +} + +#endif //LINEPROBE + + +/*============================================================================ + * Initialize Receive and Transmit Buffers. + */ + +static void init_bstrm_tx_rx_buff( sdla_t* card) +{ + wan_mbox_t* mb = &card->wan_mbox; + unsigned long tx_config_off = 0; + unsigned long rx_config_off = 0; + BSTRM_TX_STATUS_EL_CFG_STRUCT tx_config; + BSTRM_RX_STATUS_EL_CFG_STRUCT rx_config; + char err; + + mb->wan_data_len = 0; + mb->wan_command = READ_BSTRM_CONFIGURATION; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if(err != OK) { + netdevice_t *dev; + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + if (dev){ + bstrm_error(card,err,mb); + } + return; + } + + tx_config_off = ((BSTRM_CONFIGURATION_STRUCT *)mb->wan_data)-> + ptr_Tx_stat_el_cfg_struct; + card->hw_iface.peek(card->hw, tx_config_off, &tx_config, sizeof(tx_config)); + rx_config_off = ((BSTRM_CONFIGURATION_STRUCT *)mb->wan_data)-> + ptr_Rx_stat_el_cfg_struct; + card->hw_iface.peek(card->hw, rx_config_off, &rx_config, sizeof(rx_config)); + + /* Setup Head and Tails for buffers */ + card->u.b.txbuf_base_off = tx_config.base_addr_Tx_status_elements; + card->u.b.txbuf_last_off = + card->u.b.txbuf_base_off + + (tx_config.number_Tx_status_elements - 1) * sizeof(BSTRM_DATA_TX_STATUS_EL_STRUCT); + + card->u.b.rxbuf_base_off = rx_config.base_addr_Rx_status_elements; + card->u.b.rxbuf_last_off = + card->u.b.rxbuf_base_off + + (rx_config.number_Rx_status_elements - 1) * sizeof(BSTRM_DATA_RX_STATUS_EL_STRUCT); + + /* Set up next pointer to be used */ + card->u.b.txbuf_off = tx_config.next_Tx_status_element_to_use; + card->u.b.rxmb_off = rx_config.next_Rx_status_element_to_use; + + /* Setup Actual Buffer Start and end addresses */ + card->u.b.rx_base_off = rx_config.base_addr_Rx_status_elements; +} + +/*============================================================================= + * Perform Interrupt Test by running READ_BSTRM_CODE_VERSION command MAX_INTR + * _TEST_COUNTER times. + */ +static int intr_test( sdla_t* card) +{ + wan_mbox_t* mb = &card->wan_mbox; + int err,i; + + card->timer_int_enabled = 0; + + err = bstrm_set_intr_mode(card, APP_INT_ON_COMMAND_COMPLETE); + + if (err == CMD_OK) { + for (i = 0; i < MAX_INTR_TEST_COUNTER; i ++) { + mb->wan_data_len = 0; + mb->wan_command = READ_BSTRM_CODE_VERSION; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != CMD_OK) + bstrm_error(card, err, mb); + } + } + else { + return err; + } + + err = bstrm_set_intr_mode(card, 0); + + if (err != CMD_OK) + return err; + + return 0; +} + +/*============================================================================ + * Set PORT state. + */ +static void port_set_state (sdla_t *card, int state) +{ + struct wan_dev_le *devle; + netdevice_t *dev; + bitstrm_private_area_t *bstrm_priv_area; + + if (card->u.b.state != state) + { + switch (state) + { + case WAN_CONNECTED: + printk (KERN_INFO "%s: Link connected!\n", + card->devname); + break; + + case WAN_CONNECTING: + printk (KERN_INFO "%s: Link connecting...\n", + card->devname); + break; + + case WAN_DISCONNECTED: + printk (KERN_INFO "%s: Link disconnected!\n", + card->devname); + break; + } + + card->wandev.state = card->u.b.state = state; + + WAN_LIST_FOREACH(devle, &card->wandev.dev_head, dev_link){ + dev = WAN_DEVLE2DEV(devle); + if (!dev || !wan_netif_priv(dev)) continue; + bstrm_priv_area = wan_netif_priv(dev); + + if (IS_TE1_CARD(card) && + bstrm_priv_area->common.usedby == SWITCH && + state == WAN_CONNECTED){ + + bitstrm_private_area_t *sw_chan; + sdla_t *sw_card; + + if (!bstrm_priv_area->sw_dev){ + DEBUG_EVENT( "%s: Switch not present: Skip connect \n", + bstrm_priv_area->common.dev->name); + continue; + } + + sw_chan=(bitstrm_private_area_t *)bstrm_priv_area->sw_dev->priv; + sw_card=sw_chan->card; + + if (!sw_card->comm_enabled){ + DEBUG_EVENT( "%s: Switch not connected: %s \n", + bstrm_priv_area->common.dev->name, + bstrm_priv_area->sw_dev->name); + continue; + }else{ + + DEBUG_EVENT( "%s: Setting switch to connected %s\n", + bstrm_priv_area->common.dev->name, + bstrm_priv_area->sw_dev->name); + + set_bit(WAIT_DEVICE_SLOW,&bstrm_priv_area->tq_control); + set_bit(WAIT_DEVICE_FAST,&sw_chan->tq_control); + + sw_chan->common.state = WAN_CONNECTED; + } + } + + bstrm_priv_area->common.state = state; + + if (bstrm_priv_area->common.usedby == STACK){ + if (state == WAN_CONNECTED){ + wanpipe_lip_connect(bstrm_priv_area,0); + }else{ + wanpipe_lip_disconnect(bstrm_priv_area,0); + } + }else if (bstrm_priv_area->common.usedby == API){ + wan_wakeup_api(bstrm_priv_area); + wan_update_api_state(bstrm_priv_area); + + }else if (bstrm_priv_area->common.usedby == WANPIPE){ + wake_net_dev(dev); + } + + /* Reset the T1 channel tx idle flag, on T1 restart, + * when HDLC engine is running */ + if (bstrm_priv_area->hdlc_eng && state == WAN_DISCONNECTED){ + bstrm_priv_area->tx_idle_flag=0x7E; + } + + if (bstrm_priv_area->protocol == WANCONFIG_PPP && state == WAN_DISCONNECTED){ + send_ppp_term_request(dev); + } + + if (IS_TE1_CARD(card) && + state == WAN_DISCONNECTED){ + struct sk_buff *skb; + bstrm_skb_queue_purge(&bstrm_priv_area->tx_queue); + while((skb = skb_dequeue(&bstrm_priv_area->rx_used_queue))!=NULL){ + skb->data=(skb->head+16); + skb->len=1; + skb_trim(skb,0); + skb_queue_tail(&bstrm_priv_area->rx_free_queue,skb); + } + + if (bstrm_priv_area->common.usedby==SWITCH){ + set_bit(WAIT_DEVICE_BUFFERS,&bstrm_priv_area->tq_control); + } + } + } + } +} + +/*=========================================================================== + * config_bstrm + * + * Configure the chdlc protocol and enable communications. + * + * The if_open() function binds this function to the poll routine. + * Therefore, this function will run every time the chdlc interface + * is brought up. We cannot run this function from the if_open + * because if_open does not have access to the remote IP address. + * + * If the communications are not enabled, proceed to configure + * the card and enable communications. + * + * If the communications are enabled, it means that the interface + * was shutdown by ether the user or driver. In this case, we + * have to check that the IP addresses have not changed. If + * the IP addresses have changed, we have to reconfigure the firmware + * and update the changed IP addresses. Otherwise, just exit. + * + */ + + +static int config_bstrm (sdla_t *card) +{ + int err; + if (card->comm_enabled){ + return 0; + } + + card->hw_iface.poke_byte(card->hw, card->intr_type_off, 0x00); + card->hw_iface.poke_byte(card->hw, card->intr_perm_off, 0x00); + + /* Setup the Board for BSTRM */ + if ((err=set_bstrm_config(card))) { + printk (KERN_INFO "%s: Failed BSTRM configuration! rc=0x%X\n", + card->devname,err); + return -EINVAL; + } + + if (IS_TE1_CARD(card)) { + + if (bstrm_set_FE_config(card)){ + DEBUG_EVENT( "%s: Failed Rx discard/Tx idle configuration!\n", + card->devname); + return -EINVAL; + } + + + if (IS_T1_CARD(card) && card->u.b.cfg.rbs_map){ + + err=bstrm_set_te_signaling_config(card,card->u.b.cfg.rbs_map); + if (err){ + return -EINVAL; + } + + err=bstrm_read_te_signaling_config(card); + if (err){ + return -EINVAL; + } + } + + + DEBUG_EVENT( "%s: Configuring onboard %s CSU/DSU\n", + card->devname, + (IS_T1_CARD(card))?"T1":"E1"); + + err = -EINVAL; + if (card->wandev.fe_iface.config){ + err = card->wandev.fe_iface.config(&card->fe); + } + if (err){ + DEBUG_EVENT("%s: Failed %s configuration!\n", + card->devname, + (IS_T1_CARD(card))?"T1":"E1"); + return -EINVAL; + } + + } + + + if (IS_56K_CARD(card)) { + printk(KERN_INFO "%s: Configuring 56K onboard CSU/DSU\n", + card->devname); + + err = -EINVAL; + if (card->wandev.fe_iface.config){ + err = card->wandev.fe_iface.config(&card->fe); + } + if (err){ + DEBUG_EVENT("%s: Failed 56K configuration!\n", + card->devname); + return -EINVAL; + } + } + + if (card->u.b.serial){ + /* Set interrupt mode and mask */ + if (bstrm_set_intr_mode(card, APP_INT_ON_RX_BLOCK | + APP_INT_ON_GLOBAL_EXCEP_COND | + APP_INT_ON_BSTRM_EXCEP_COND | APP_INT_ON_TIMER)){ + printk (KERN_INFO "%s: Failed to set interrupt triggers!\n", + card->devname); + return -EINVAL; + } + }else{ + /* Set interrupt mode and mask */ + if (bstrm_set_intr_mode(card, APP_INT_ON_RX_BLOCK | + APP_INT_ON_GLOBAL_EXCEP_COND | + APP_INT_ON_TX_BLOCK | + APP_INT_ON_BSTRM_EXCEP_COND | APP_INT_ON_TIMER)){ + printk (KERN_INFO "%s: Failed to set interrupt triggers!\n", + card->devname); + return -EINVAL; + } + } + + + /* Initialize Rx/Tx buffer control fields */ + init_bstrm_tx_rx_buff(card); + + if(IS_TE1_CARD(card) && card->wandev.ignore_front_end_status == WANOPT_NO) { + port_set_state(card, WAN_DISCONNECTED); + + }else if (IS_56K_CARD(card) && card->wandev.ignore_front_end_status == WANOPT_NO) { + port_set_state(card, WAN_DISCONNECTED); + + }else{ + if (bstrm_comm_enable(card) != 0) { + DEBUG_EVENT("%s: Failed to enable bitstrm communications!\n", + card->devname); + card->hw_iface.poke_byte(card->hw, card->intr_perm_off, 0x00); + card->comm_enabled=0; + bstrm_set_intr_mode(card,0); + return -EINVAL; + } + port_set_state(card, WAN_CONNECTED); + + DEBUG_EVENT("%s: Communications enabled on startup\n", + card->devname); + } + + /* Manually poll the 56K CSU/DSU to get the status */ + if (IS_56K_CARD(card)) { + /* 56K Update CSU/DSU alarms */ + card->wandev.fe_iface.read_alarm(&card->fe, 1); + } + + /* For TE1 cards, do not mask out the TX interrupt. + * The Tx interrupt must send idle data for + * each DS0 channel */ + if (!card->u.b.serial){ + card->hw_iface.clear_bit(card->hw, card->intr_perm_off, APP_INT_ON_TIMER); + }else{ + card->hw_iface.clear_bit(card->hw, card->intr_perm_off, + (APP_INT_ON_TIMER | APP_INT_ON_TX_BLOCK)); + } + + DEBUG_EVENT("%s: Config complete\n",card->devname); + return 0; +} + + +static int bstrm_get_config_info(void* priv, struct seq_file* m, int* stop_cnt) +{ + wan_device_t* wandev = (wan_device_t*)priv; + sdla_t* card = NULL; + + if (wandev == NULL || wandev->private == NULL) + return 0; + + card = (sdla_t*)wandev->private; + if (!card->comm_enabled){ + DEBUG_EVENT( "DEBUG: Enable communication for Bit Streaming protocol\n"); + bstrm_comm_enable (card); + }else{ + DEBUG_EVENT( "DEBUG: Communication is already enabled\n"); + } + return m->count; +} + + +// TE1 +static int set_adapter_config (sdla_t* card) +{ + wan_mbox_t* mb = &card->wan_mbox; + ADAPTER_CONFIGURATION_STRUCT* cfg = (ADAPTER_CONFIGURATION_STRUCT*)mb->wan_data; + int err; + + card->hw_iface.getcfg(card->hw, SDLA_ADAPTERTYPE, &cfg->adapter_type); + + if (IS_TE1_CARD(card) && card->u.b.serial){ + DEBUG_EVENT("%s: Configuring Front End in Unframed Mode!\n", + card->devname); + cfg->adapter_type|=OPERATE_T1E1_AS_SERIAL; + } + + cfg->adapter_config = 0x00; + cfg->operating_frequency = 00; + mb->wan_data_len = sizeof(ADAPTER_CONFIGURATION_STRUCT); + mb->wan_command = SET_ADAPTER_CONFIGURATION; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + + if(err != OK) { + bstrm_error(card,err,mb); + } + return (err); +} + +static void bstrm_handle_front_end_state(void* card_id) +{ + sdla_t* card = (sdla_t*)card_id; + + if (card->wandev.ignore_front_end_status == WANOPT_YES) { + return; + } + if (card->fe.fe_status == FE_CONNECTED) { + if (card->u.b.state != WAN_CONNECTED) { + if(card->comm_enabled == 0) { + if (bstrm_comm_enable (card) == 0){ + DEBUG_EVENT( "%s: Communications enabled\n", + card->devname); + + port_set_state(card, WAN_CONNECTED); + }else{ + DEBUG_EVENT( "%s: Failed to enable communications\n", + card->devname); + } + } + } + }else{ + port_set_state(card, WAN_DISCONNECTED); + + if(card->comm_enabled != 0) { + DEBUG_EVENT( "%s: Communications disabled\n", + card->devname); + bstrm_comm_disable (card); + } + } + +} + + +static int bstrm_comm_disable (sdla_t *card) +{ + wan_mbox_t* mb = &card->wan_mbox; + int err; + + mb->wan_command = DISABLE_BSTRM_COMMUNICATIONS; + mb->wan_data_len = 0; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + + card->comm_enabled = 0; + + return 0; + +} + +#define WAN_BSTRM_CHUNK 8 +static int bstrm_set_FE_config (sdla_t *card) +{ + wan_mbox_t* mb = &card->wan_mbox; + int err; + FE_RX_DISC_TX_IDLE_STRUCT FE_str; + int i; + + if (IS_TE1_UNFRAMED(&card->fe)){ + return 0; + } + + if (IS_T1_CARD(card)){ + FE_str.lgth_Rx_disc_bfr = card->u.b.time_slots * WAN_BSTRM_CHUNK; + FE_str.lgth_Tx_idle_bfr = card->u.b.time_slots * WAN_BSTRM_CHUNK; + }else{ + FE_str.lgth_Rx_disc_bfr = card->u.b.time_slots * WAN_BSTRM_CHUNK; + FE_str.lgth_Tx_idle_bfr = (card->u.b.time_slots-1) * WAN_BSTRM_CHUNK; + } + + FE_str.Tx_idle_data_bfr[0]=card->u.b.cfg.monosync_tx_time_fill_char; + for(i = 1; i < NO_ACTIVE_TX_TIME_SLOTS_E1; i ++) { + FE_str.Tx_idle_data_bfr[i] = card->u.b.cfg.monosync_tx_time_fill_char; + } + mb->wan_data_len = sizeof(FE_RX_DISC_TX_IDLE_STRUCT); + memcpy(mb->wan_data, &FE_str.lgth_Rx_disc_bfr, mb->wan_data_len); + mb->wan_command = SET_FE_RX_DISC_TX_IDLE_CFG; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if(err != OK){ + bstrm_error(card,err,mb); + } + + return err; +} + + +static int bstrm_bind_dev_switch (sdla_t *card, bitstrm_private_area_t*chan, char *sw_dev_name) +{ + bitstrm_private_area_t *sw_chan; + netdevice_t *sw_dev; + sdla_t *sw_card; + unsigned long smp_flags; + + if (chan->sw_dev){ + return 0; + } + + sw_dev = dev_get_by_name(sw_dev_name); + if (!sw_dev){ + DEBUG_EVENT( "%s: Device %s waiting for switch device %s\n", + card->devname, chan->if_name,sw_dev_name); + DEBUG_EVENT( "%s: Device %s not found\n", + card->devname, sw_dev_name); + return 0; + } + + if (!sw_dev->priv){ + DEBUG_EVENT( "%s: Error: Invalid switch device %s: not wanpipe device!\n", + card->devname, sw_dev->name); + dev_put(sw_dev); + return -EINVAL; + } + + if (((wanpipe_common_t*)sw_dev->priv)->usedby != SWITCH){ + DEBUG_EVENT( "%s: Error: Device %s not configured for switching\n", + card->devname, sw_dev->name); + + dev_put(sw_dev); + return -EINVAL; + } + + if (((wanpipe_common_t*)sw_dev->priv)->config_id != card->wandev.config_id){ + DEBUG_EVENT( "%s: Error: Invalid switch device (%s) config id 0x%x\n", + card->devname, sw_dev->name,((wanpipe_common_t*)sw_dev->priv)->config_id); + + dev_put(sw_dev); + return -EINVAL; + } + + sw_chan = (bitstrm_private_area_t *)sw_dev->priv; + sw_card = sw_chan->card; + + if ((strcmp(sw_chan->sw_if_name,chan->if_name)) != 0){ + DEBUG_EVENT( "%s: Error: Config mismatch: SW dev %s is not configured for switching!\n", + card->devname, sw_chan->if_name); + dev_put(sw_dev); + return -EINVAL; + } + + DEBUG_EVENT( "%s:%s Device (ch=0x%lx) mapped to %s (ch=0x%lx)\n", + card->devname, chan->if_name, chan->time_slot_map, + sw_chan->if_name, sw_chan->time_slot_map); + + wan_spin_lock_irq(&card->wandev.lock,&smp_flags); + + + if (!card->u.b.sw_card){ + sw_card->u.b.sw_card = card; + card->u.b.sw_card=sw_card; + } + + sw_chan->sw_dev = chan->common.dev; + chan->sw_dev = sw_dev; + + wan_spin_unlock_irq(&card->wandev.lock,&smp_flags); + + dev_hold(chan->common.dev); + + return 0; +} + +static int bstrm_unbind_dev_switch (sdla_t *card, bitstrm_private_area_t *chan) +{ + if (chan->sw_dev){ + bitstrm_private_area_t *sw_chan=chan->sw_dev->priv; + if (sw_chan){ + if (sw_chan->sw_dev){ + DEBUG_EVENT( "%s: Unbinding SW dev %s from %s\n", + card->devname, sw_chan->if_name, sw_chan->sw_dev->name); + dev_put(sw_chan->sw_dev); + sw_chan->sw_dev=NULL; + } + } + + DEBUG_EVENT( "%s: Unbinding SW dev %s from %s\n", + card->devname, chan->if_name, chan->sw_dev->name); + dev_put(chan->sw_dev); + chan->sw_dev=NULL; + } + + if (card->open_cnt == 1){ + if (card->u.b.sw_card){ + sdla_t *sw_card=card->u.b.sw_card; + sw_card->u.b.sw_card=NULL; + card->u.b.sw_card=NULL; + } + } + return 0; +} + + +static int protocol_init (sdla_t *card, netdevice_t *dev, + bitstrm_private_area_t *chan, + wanif_conf_t* conf) +{ + struct ppp_device *pppdev; + struct sppp *sp; + + if (chan->protocol != WANCONFIG_PPP && + chan->protocol != WANCONFIG_CHDLC){ + DEBUG_EVENT( "%s:%s: Unsupported protocol %i\n", + card->devname,chan->if_name,chan->protocol); + return -EPROTONOSUPPORT; + } + + pppdev=kmalloc(sizeof(struct ppp_device),GFP_KERNEL); + if (!pppdev){ + chan->protocol=0; + return -ENOMEM; + } + + memset(pppdev,0,sizeof(struct ppp_device)); + + chan->common.prot_ptr=(void*)pppdev; + + pppdev->dev=dev; + + /* Get authentication info. */ + if(conf->pap == WANOPT_YES){ + pppdev->sppp.myauth.proto = PPP_PAP; + }else if(conf->chap == WANOPT_YES){ + pppdev->sppp.myauth.proto = PPP_CHAP; + }else{ + pppdev->sppp.myauth.proto = 0; + } + + if(pppdev->sppp.myauth.proto){ + memcpy(pppdev->sppp.myauth.name, conf->userid, AUTHNAMELEN); + memcpy(pppdev->sppp.myauth.secret, conf->passwd, AUTHNAMELEN); + } + + pppdev->sppp.gateway = conf->gateway; + + if (conf->if_down){ + pppdev->sppp.dynamic_ip = 1; + } + + sprintf(pppdev->sppp.hwdevname,"%s",card->devname); + + wp_sppp_attach(pppdev); + + sp = &pppdev->sppp; + + dev->type = ARPHRD_PPP; + + if (chan->protocol == WANCONFIG_CHDLC){ + DEBUG_EVENT( "%s: Starting Kernel CISCO HDLC protocol\n", + card->devname); + sp->pp_flags |= PP_CISCO; + }else{ + DEBUG_EVENT( "%s: Starting Kernel Sync PPP protocol\n", + card->devname); + sp->pp_flags &= ~PP_CISCO; + } + + return 0; +} + +static int protocol_start (sdla_t *card, netdevice_t *dev) +{ + int err=0; + + bitstrm_private_area_t *chan=dev->priv; + + if (!chan) + return 0; + + if (chan->protocol == WANCONFIG_PPP || + chan->protocol == WANCONFIG_CHDLC){ + if ((err=wp_sppp_open(dev)) != 0){ + return err; + } + } + return err; +} + +static int protocol_stop (sdla_t *card, netdevice_t *dev) +{ + bitstrm_private_area_t *chan=dev->priv; + + if (!chan) + return 0; + + if (chan->protocol == WANCONFIG_PPP || + chan->protocol == WANCONFIG_CHDLC){ + wp_sppp_close(dev); + } + + return 0; +} + + + +static int protocol_shutdown (sdla_t *card, netdevice_t *dev) +{ + bitstrm_private_area_t *chan=dev->priv; + + if (!chan) + return 0; + + if (chan->protocol == WANCONFIG_PPP || + chan->protocol == WANCONFIG_CHDLC){ + wp_sppp_detach(dev); + + dev->do_ioctl = NULL; + dev->hard_header = NULL; + dev->rebuild_header = NULL; + + if (chan->common.prot_ptr){ + kfree(chan->common.prot_ptr); + chan->common.prot_ptr= NULL; + } + } + return 0; +} + +static void send_ppp_term_request (netdevice_t *dev) +{ + struct sk_buff *new_skb; + unsigned char *buf; + bitstrm_private_area_t *chan=dev->priv; + + if (chan->ignore_modem) + return; + + DEBUG_EVENT( "%s: (Debug) Wanpipe sending PPP TERM\n",dev->name); + if ((new_skb = dev_alloc_skb(8)) != NULL) { + /* copy data into new_skb */ + + buf = skb_put(new_skb, 8); + sprintf(buf,"%c%c%c%c%c%c%c%c", 0xFF,0x03,0xC0,0x21,0x05,0x98,0x00,0x07); + + /* Decapsulate pkt and pass it up the protocol stack */ + new_skb->protocol = htons(ETH_P_WAN_PPP); + new_skb->dev = dev; + new_skb->mac.raw = new_skb->data; + + wp_sppp_input(dev,new_skb); + } +} + + +static void +wanpipe_switch_datascope_tx_up(bitstrm_private_area_t *chan,struct sk_buff *skb) +{ + + struct sk_buff *new_skb; + sdla_t*card=chan->card; + api_rx_hdr_t *buf; + + if (chan->common.sk == NULL){ + return; + } + + if (skb_headroom(skb) < sizeof(api_rx_hdr_t)){ + new_skb=skb_copy_expand(skb,sizeof(api_rx_hdr_t),0,GFP_ATOMIC); + }else{ + new_skb=skb_copy(skb,GFP_ATOMIC); + } + + if (!new_skb){ + DEBUG_EVENT( "%s: ERROR: Failed to clone skb buffer, no memory !\n", + card->devname); + return; + } + + buf = (api_rx_hdr_t*)skb_push(new_skb,sizeof(api_rx_hdr_t)); + memset(buf, 0, sizeof(api_rx_hdr_t)); + buf->direction = 1; + + new_skb->protocol = htons(PVC_PROT); + new_skb->mac.raw = new_skb->data; + new_skb->dev = chan->common.dev; + new_skb->pkt_type = WAN_PACKET_DATA; + + if (wan_api_rx(chan,new_skb) != 0){ + /* Sock full cannot send, queue us for another + * try */ + dev_kfree_skb_any(new_skb); + wan_wakeup_api(chan); + } + + return; + +} + +static int bstrm_set_te_signaling_config (void* card_id, unsigned long ts_sig_map) +{ + sdla_t* card = (sdla_t*)card_id; + wan_mbox_t* mb = &card->wan_mbox; + char* data = mb->wan_data; + int channel_range = (IS_T1_CARD(card)) ? + NUM_OF_T1_CHANNELS : NUM_OF_E1_CHANNELS; + int err, i; + + DEBUG_TEST("%s: Set signalling config...\n", + card->devname); + + memset((char *)&((te_signaling_cfg_t*)data)->sig_perm.time_slot[0], + TE_SIG_DISABLED, + sizeof(te_signaling_perm_t)); + + for(i = 0; i < channel_range; i ++) { + if (test_bit(i, (void*)&ts_sig_map)){ + ((te_signaling_cfg_t*)data)->sig_perm.time_slot[i] + = (TE_RX_SIG_ENABLED | TE_TX_SIG_ENABLED); + //= TE_RX_SIG_ENABLED; + } + } + + ((te_signaling_cfg_t *)data)->sig_processing_counter = 1; + + mb->wan_data_len = sizeof(te_signaling_cfg_t); + mb->wan_command = SET_TE1_SIGNALING_CFG; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + + if(err != OK){ + DEBUG_EVENT("%s: Error: Failed Robbit SetCfg (map=0x%lX) (rc=0x%X)\n", + card->devname,ts_sig_map,err); + bstrm_error(card,err,mb); + } + return (err); +} + +static int bstrm_disable_te_signaling (void* card_id, unsigned long ts_map) +{ + sdla_t* card = (sdla_t*)card_id; + unsigned char ts_sig_perm[32]; + int channel_range = GET_TE_CHANNEL_RANGE(&card->fe); + int i; + + memset(ts_sig_perm, 0, sizeof(ts_sig_perm)); + + DEBUG_EVENT("%s: Disableing Robbit Signalling\n", card->devname); + + for(i = 0; i < channel_range; i++){ + if (test_bit(i, &ts_map)){ + ts_sig_perm[i] = TE_SIG_DISABLED; + } + } + if (card->fe.te_param.ptr_te_sig_perm_off){ + card->hw_iface.poke(card->hw, card->fe.te_param.ptr_te_sig_perm_off, + ts_sig_perm, channel_range); + } + // REMOVE it later!! + //if (card->u_fe.te_iface.ptr_te_sig_perm_off){ + // card->hw_iface.poke(card->hw, card->u_fe.te_iface.ptr_te_sig_perm_off, + // ts_sig_perm, channel_range); + //} + + return 0; +} + + +static int bstrm_read_te_signaling_config (void* card_id) +{ + sdla_t* card = (sdla_t*)card_id; + wan_mbox_t* mb = &card->wan_mbox; + char* data = mb->wan_data; + int err; + + DEBUG_CFG("%s: Read TE Signalling config...\n", card->devname); + ((te_signaling_cfg_t *)data)->sig_processing_counter = 1; + + mb->wan_data_len = 0; + mb->wan_command = READ_TE1_SIGNALING_CFG; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + + if(err != OK) { + DEBUG_EVENT("%s: Failed to Read Robbit Signalling! (rc=0x%X)\n", + card->devname,err); + bstrm_error(card,err,mb); + }else{ + //card->u_fe.te_iface.ptr_te_sig_perm_off = + card->fe.te_param.ptr_te_sig_perm_off = + ((te_signaling_cfg_t *)data)->ptr_te_sig_perm_struct; + //card->u_fe.te_iface.ptr_te_Rx_sig_off = + card->fe.te_param.ptr_te_Rx_sig_off = + ((te_signaling_cfg_t *)data)->ptr_te_Rx_sig_struct; + //card->u_fe.te_iface.ptr_te_Tx_sig_off = + card->fe.te_param.ptr_te_Tx_sig_off = + ((te_signaling_cfg_t *)data)->ptr_te_Tx_sig_struct; + } + + return (err); +} + +/*=============================================================== + * send_rbs_oob_msg + * + * Construct an OOB Robbit Signalling Message and pass it + * up the connected sock. If the sock is not bounded discard + * the NEM. + * + *===============================================================*/ + +static int send_rbs_oob_msg (sdla_t *card, bitstrm_private_area_t *chan) +{ + unsigned char *buf; + api_rx_hdr_t *api_rx_el; + struct sk_buff *skb; + int err=0, len=5; + + if (chan->common.usedby != API){ + return -ENODEV; + } + + if (!chan->common.sk){ + return -ENODEV; + } + + skb=wan_skb_alloc(sizeof(api_rx_hdr_t)+len); + if (!skb){ + return -ENOMEM; + } + + api_rx_el=(api_rx_hdr_t *)skb_put(skb,sizeof(api_rx_hdr_t)); + memset(api_rx_el,0,sizeof(api_rx_hdr_t)); + + api_rx_el->channel=chan->rbs_chan; + + buf = skb_put(skb,1); + if (!buf){ + wan_skb_free(skb); + return -ENOMEM; + } + + buf[0]=chan->rbs_sig; + + skb->pkt_type = WAN_PACKET_ERR; + skb->protocol=htons(PVC_PROT); + skb->dev=chan->common.dev; + + DEBUG_TEST("%s: Sending OOB message len=%i\n", + chan->if_name,skb->len); + + if (wan_api_rx(chan,skb)!=0){ + err=-ENODEV; + wan_skb_free(skb); + } + + return err; +} + diff -Nur linux.org/drivers/net/wan/sdla_bsc.c linux-2.6.17/drivers/net/wan/sdla_bsc.c --- linux.org/drivers/net/wan/sdla_bsc.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/drivers/net/wan/sdla_bsc.c 2006-08-30 10:07:16.000000000 +0000 @@ -0,0 +1,1165 @@ +/***************************************************************************** +* sdla_bsc.c WANPIPE(tm) Multiprotocol WAN Link Driver. +* BiSync module. +* +* Author: Nenad Corbic +* +* Copyright: (c) 1995-2001 Sangoma Technologies Inc. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version +* 2 of the License, or (at your option) any later version. +* ============================================================================ +* Sep 20, 2001 Nenad Corbic The min() function has changed for 2.4.9 +* kernel. Thus using the wp_min() defined in +* wanpipe.h +* Aug 14, 2001 Nenad Corbic Inital version, based on Chdlc module. +* Using Gideons new bitstreaming firmware. +*****************************************************************************/ + +#include +#include +#include /* WAN router definitions */ +#include /* WANPIPE common user API definitions */ +#include +#include /* BSTRM firmware API definitions */ +#include /* Socket Driver common area */ +#include + + +/****** Defines & Macros ****************************************************/ + +#define bsc_lock(a,b) spin_lock_irqsave(a,b) +#define bsc_unlock(a,b) spin_unlock_irqrestore(a,b) + + +/* reasons for enabling the timer interrupt on the adapter */ +#define TMR_INT_ENABLED_UDP 0x01 +#define TMR_INT_ENABLED_UPDATE 0x02 +#define TMR_INT_ENABLED_CONFIG 0x10 + +#define MAX_IP_ERRORS 10 + +#define BSTRM_DFLT_DATA_LEN 1500 /* default MTU */ +#define BSTRM_HDR_LEN 1 + +#define BSTRM_API 0x01 + +#define PORT(x) (x == 0 ? "PRIMARY" : "SECONDARY" ) +#define MAX_BH_BUFF 10 + +//#define PRINT_DEBUG +#ifdef PRINT_DEBUG +#define dbg_printk(format, a...) printk(format, ## a) +#else +#define dbg_printk(format, a...) +#endif + +#define _INB(port) (inb(port)) +#define _OUTB(port, byte) (outb((byte),(port))) + +#define POLL_WAIT (HZ/100) + +#define OK 0 +#define MAX_ACTIVE_CHAN 200 +#define MAX_POLL_CNT 20 + +#define _BSC_DEBUG_ 1 +/******Data Structures*****************************************************/ + +/* This structure is placed in the private data area of the device structure. + * The card structure used to occupy the private area but now the following + * structure will incorporate the card structure along with BSTRM specific data + */ + +typedef struct bscmp_private_area +{ + wanpipe_common_t common; + sdla_t *card; + unsigned long router_start_time; + unsigned long tick_counter; /* For 5s timeout counter */ + unsigned long router_up_time; + u8 config_bstrm; + u8 config_bscmp_timeout; + struct timer_list poll_timer; + u8 true_if_encoding; + unsigned long station_change; + unsigned char active_chan[MAX_ACTIVE_CHAN]; + unsigned char cur_dev; + unsigned long dev_stop_timeout; +} bscmp_private_area_t; + +/* Route Status options */ +#define NO_ROUTE 0x00 +#define ADD_ROUTE 0x01 +#define ROUTE_ADDED 0x02 +#define REMOVE_ROUTE 0x03 + + +/* variable for tracking how many interfaces to open for WANPIPE on the + two ports */ + + +/****** Function Prototypes *************************************************/ +/* WAN link driver entry points. These are called by the WAN router module. */ +static int update (wan_device_t* wandev); +static int new_if (wan_device_t* wandev, netdevice_t* dev, + wanif_conf_t* conf); + +/* Network device interface */ +static int if_init (netdevice_t* dev); +static int if_open (netdevice_t* dev); +static int if_close (netdevice_t* dev); +static int if_ioctl (netdevice_t *dev, struct ifreq *ifr, int cmd); +static struct net_device_stats* if_stats (netdevice_t* dev); + +static int if_send (struct sk_buff* skb, netdevice_t* dev); + +/* BSTRM Firmware interface functions */ +static int bscmp_comm_disable (sdla_t* card); +static int bscmp_send (sdla_t* card, + unsigned char station, + unsigned char misc_tx_rx_bits, + void* data, unsigned len); +static int bscmp_error (sdla_t *card, int err, wan_mbox_t *mb); +static int bscmp_read_link_stats (sdla_t* card); +static int bscmp_read_code_version (sdla_t* card); +static int bscmp_configure (sdla_t* card, BSC_CONFIG_STRUCT *cfg); +static int bscmp_read_config (sdla_t* card); +static int bscmp_list_stations (sdla_t* card); +static int bscmp_read (sdla_t* card, int station); + +static void event_poll (unsigned long dev_ptr); +static void port_set_state (sdla_t *card, int state); +static int find_active_chan(bscmp_private_area_t* bscmp_priv_area, int start_chan); + + +/****** Public Functions ****************************************************/ + +/*============================================================================ + * Cisco HDLC protocol initialization routine. + * + * This routine is called by the main WANPIPE module during setup. At this + * point adapter is completely initialized and firmware is running. + * o read firmware version (to make sure it's alive) + * o configure adapter + * o initialize protocol-specific fields of the adapter data space. + * + * Return: 0 o.k. + * < 0 failure. + */ +int wpbsc_init (sdla_t* card, wandev_conf_t* conf) +{ + int err; + unsigned long timeout; + volatile wan_mbox_t* mbox; + + BSC_CONFIG_STRUCT cfg = { 3, //line_speed_number + 500, //max_data_frame_size + 1, //secondary_station + 5, //num_consec_PAD_eof + 2, //num_add_lead_SYN + 0, //1 //conversational_mode + 0, //pp_dial_up_operation + 0, //switched_CTS_RTS + 1, //EBCDIC_encoding + 1, //auto_open + 0, //misc_bits + 1, //0 //protocol_options1 + 0, //protocol_options2 + 0, //reserved_pp + 10, //max_retransmissions + 10, //fast_poll_retries + 3, //TTD_retries + 10, //restart_timer + 1000, //pp_slow_restart_timer + 50, //TTD_timer + 100, //pp_delay_between_EOT_ENQ + 50, //response_timer + 100, //rx_data_timer + 40, //NAK_retrans_delay_timer + 50, //wait_CTS_timer + 5, //mp_max_consec_ETX + 0x7f, //mp_general_poll_address + 2000, //sec_poll_timeout + 20, //pri_poll_skips_inactive + 3, //sec_additional_stn_send_gpoll + 10, //pri_select_retries + 0, //mp_multipoint_options + 0 //reserved 0=RS232 1=V35 + }; + + + /* Verify configuration ID */ + if (conf->config_id != WANCONFIG_BSC) { + printk(KERN_INFO "%s: invalid configuration ID %u!\n", + card->devname, conf->config_id); + return -EINVAL; + } + + /* Find out which Port to use */ + conf->comm_port = WANOPT_PRI; + + /* Initialize protocol-specific fields */ + if(card->type != SDLA_S514){ + unsigned char tmp=0; + + //FIXME: CHECK THAT MBOX IS RIGHT !!!! + /* Alex Apr 8 2004 Sangoma ISA card -> card->mbox_off = 0; */ + card->mbox_off = BSC_SENDBOX; + + + card->hw_iface.isa_write_1(card->hw, 0, 0); + if (card->hw_iface.mapmem){ + err = card->hw_iface.mapmem(card->hw, 0); + }else{ + err = -EINVAL; + } + if (err) return err; + + card->hw_iface.poke(card->hw,0x10,&cfg,sizeof(cfg)); + + card->hw_iface.bus_write_1(card->hw, 0x00, 0xC3); /* Z80: 'jp' opcode */ + card->hw_iface.bus_write_2(card->hw, 0x01, 0x100); + + card->hw_iface.isa_read_1(card->hw, 0, &tmp); + card->hw_iface.isa_write_1(card->hw, 0, tmp | 0x02); + + timeout=jiffies; + while((jiffies-timeout) < (HZ/10)) + schedule(); + + + card->hw_iface.isa_read_1(card->hw, 1, &tmp); + if (!(tmp & 0x02)){ /* verify */ + return -EIO; + } + err = (card->hw_iface.mapmem) ? + card->hw_iface.mapmem(card->hw, BSC_SENDBOX) : -EINVAL; + if (err) return err; + + }else{ + card->mbox_off = BSC_SENDBOX; + + card->hw_iface.io_write_1(card->hw, 0x00, S514_CPU_HALT); + + card->hw_iface.poke(card->hw,0x10,&cfg,sizeof(cfg)); + + card->hw_iface.bus_write_1(card->hw, 0x00, 0xC3); /* Z80: 'jp' opcode */ + card->hw_iface.bus_write_2(card->hw, 0x01, 0x100); + card->hw_iface.io_write_1(card->hw, 0x00, S514_CPU_START); + + } + + mbox = &card->wan_mbox; + + timeout=jiffies; + while((jiffies-timeout) < (HZ)) + schedule(); + + /* Read firmware version. Note that when adapter initializes, it + * clears the mailbox, so it may appear that the first command was + * executed successfully when in fact it was merely erased. To work + * around this, we execute the first command twice. + */ + + if (bscmp_read_code_version(card)){ + return -EIO; + } + + printk(KERN_INFO "%s: Running Bisync firmware v%s\n", + card->devname, mbox->wan_data); + + card->isr = NULL; + card->poll = NULL; + card->exec = NULL; + card->wandev.update = &update; + card->wandev.new_if = &new_if; + card->wandev.del_if = NULL; + card->wandev.udp_port = conf->udp_port; + card->disable_comm = NULL; + card->wandev.new_if_cnt = 0; + + card->wandev.ttl = conf->ttl; + card->wandev.interface = conf->interface; + + card->wandev.clocking = conf->clocking; + card->wandev.mtu = cfg.max_data_frame_size; + + + printk(KERN_INFO "%s: Configuring Bisync!\n",card->devname); + bscmp_configure (card,&cfg); + + + /* This is for the ports link state */ + card->wandev.state = WAN_DISCONNECTED; + + bscmp_read_config (card); + + printk(KERN_INFO "\n"); + + return 0; +} + + +/******* WAN Device Driver Entry Points *************************************/ + +/*============================================================================ + * Update device status & statistics + * This procedure is called when updating the PROC file system and returns + * various communications statistics. These statistics are accumulated from 3 + * different locations: + * 1) The 'if_stats' recorded for the device. + * 2) Communication error statistics on the adapter. + * 3) BSTRM operational statistics on the adapter. + * The board level statistics are read during a timer interrupt. Note that we + * read the error and operational statistics during consecitive timer ticks so + * as to minimize the time that we are inside the interrupt handler. + * + */ +static int update (wan_device_t* wandev) +{ + sdla_t* card = wandev->private; + netdevice_t* dev; + volatile bscmp_private_area_t* bscmp_priv_area; + + /* sanity checks */ + if((wandev == NULL) || (wandev->private == NULL)) + return -EFAULT; + + if(wandev->state == WAN_UNCONFIGURED) + return -ENODEV; + + if(test_bit(PERI_CRIT, (void*)&card->wandev.critical)) + return -EAGAIN; + + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + if (dev == NULL) + return -ENODEV; + + if((bscmp_priv_area=dev->priv) == NULL) + return -ENODEV; + + + return 0; +} + + +/*============================================================================ + * Create new logical channel. + * This routine is called by the router when ROUTER_IFNEW IOCTL is being + * handled. + * o parse media- and hardware-specific configuration + * o make sure that a new channel can be created + * o allocate resources, if necessary + * o prepare network device structure for registaration. + * + * Return: 0 o.k. + * < 0 failure (channel will not be created) + */ +static int new_if (wan_device_t* wandev, netdevice_t* dev, wanif_conf_t* conf) +{ + sdla_t* card = wandev->private; + bscmp_private_area_t* bscmp_priv_area; + + + printk(KERN_INFO "%s: Configuring Interface: %s\n", + card->devname, conf->name); + + if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) { + printk(KERN_INFO "%s: Invalid interface name!\n", + card->devname); + return -EINVAL; + } + + /* allocate and initialize private data */ + bscmp_priv_area = kmalloc(sizeof(bscmp_private_area_t), GFP_KERNEL); + + if(bscmp_priv_area == NULL) + return -ENOMEM; + + memset(bscmp_priv_area, 0, sizeof(bscmp_private_area_t)); + + bscmp_priv_area->card = card; + + bscmp_priv_area->common.sk=NULL; + bscmp_priv_area->common.state = WAN_CONNECTING; + bscmp_priv_area->common.dev = dev; + + if(card->wandev.new_if_cnt > 0) { + kfree(bscmp_priv_area); + return -EEXIST; + } + + card->wandev.new_if_cnt++; + + /* Setup wanpipe as a router (WANPIPE) or as an API */ + if (strcmp(conf->usedby, "API") == 0) { + printk(KERN_INFO "%s: Running in API mode !\n", + wandev->name); + }else{ + printk(KERN_INFO "%s: Bisync protocol doesn't support WANPIPE mode! API only!\n", + wandev->name); + kfree(bscmp_priv_area); + return -EINVAL; + } + + /* prepare network device data space for registration */ + dev->init = &if_init; + dev->priv = bscmp_priv_area; + + return 0; +} + + +/****** Network Device Interface ********************************************/ + +/*============================================================================ + * Initialize Linux network interface. + * + * This routine is called only once for each interface, during Linux network + * interface registration. Returning anything but zero will fail interface + * registration. + */ +static int if_init (netdevice_t* dev) + { + bscmp_private_area_t* bscmp_priv_area = dev->priv; + sdla_t* card = bscmp_priv_area->card; + wan_device_t* wandev = &card->wandev; + + /* Initialize device driver entry points */ + dev->open = &if_open; + dev->stop = &if_close; + dev->hard_header = NULL; + dev->rebuild_header = NULL; + dev->hard_start_xmit = &if_send; + dev->get_stats = &if_stats; + dev->do_ioctl = &if_ioctl; +#if defined(LINUX_2_4)||defined(LINUX_2_6) + dev->tx_timeout = NULL; + dev->watchdog_timeo = TX_TIMEOUT; +#endif + + + /* Initialize media-specific parameters */ + dev->flags |= IFF_POINTOPOINT; + dev->flags |= IFF_NOARP; + + + if (bscmp_priv_area->true_if_encoding){ + dev->type = ARPHRD_HDLC; /* This breaks the tcpdump */ + }else{ + dev->type = ARPHRD_PPP; + } + + dev->mtu = card->wandev.mtu; + /* for API usage, add the API header size to the requested MTU size */ + dev->mtu += sizeof(api_tx_hdr_t); + + dev->hard_header_len = BSTRM_HDR_LEN; + + /* Initialize hardware parameters */ + dev->irq = wandev->irq; + dev->dma = wandev->dma; + dev->base_addr = wandev->ioport; + card->hw_iface.getcfg(card->hw, SDLA_MEMBASE, &dev->mem_start); //ALEX_TODAY wandev->maddr; + card->hw_iface.getcfg(card->hw, SDLA_MEMSIZE, &dev->mem_end); //ALEX_TODAY wandev->maddr + wandev->msize - 1; + + /* Set transmit buffer queue length + * If too low packets will not be retransmitted + * by stack. + */ + dev->tx_queue_len = 100; + + return 0; +} + +/*============================================================================ + * Open network interface. + * o enable communications and interrupts. + * o prevent module from unloading by incrementing use count + * + * Return 0 if O.k. or errno. + */ +static int if_open (netdevice_t* dev) +{ + bscmp_private_area_t* bscmp_priv_area = dev->priv; + sdla_t* card = bscmp_priv_area->card; + struct timeval tv; + int err = 0; + + /* Only one open per interface is allowed */ + if (open_dev_check(dev)) + return -EBUSY; + + do_gettimeofday(&tv); + bscmp_priv_area->router_start_time = tv.tv_sec; + + netif_start_queue(dev); + + init_timer(&bscmp_priv_area->poll_timer); + bscmp_priv_area->poll_timer.data = (unsigned long)dev; + bscmp_priv_area->poll_timer.function = event_poll; + bscmp_priv_area->poll_timer.expires=jiffies+POLL_WAIT; + add_timer(&bscmp_priv_area->poll_timer); + wanpipe_open(card); + + return err; +} + +/*============================================================================ + * Close network interface. + * o if this is the last close, then disable communications and interrupts. + * o reset flags. + */ +static int if_close (netdevice_t* dev) +{ + bscmp_private_area_t* bscmp_priv_area = dev->priv; + sdla_t* card = bscmp_priv_area->card; + + del_timer(&bscmp_priv_area->poll_timer); + + stop_net_queue(dev); +#if defined(LINUX_2_1) + dev->start=0; +#endif + wanpipe_close(card); + + bscmp_comm_disable(card); + card->wandev.state = WAN_DISCONNECTED; + return 0; +} + + + +/*============================================================================ + * Send a packet on a network interface. + * o set tbusy flag (marks start of the transmission) to block a timer-based + * transmit from overlapping. + * o check link state. If link is not up, then drop the packet. + * o execute adapter send command. + * o free socket buffer + * + * Return: 0 complete (socket buffer must be freed) + * non-0 packet may be re-transmitted (tbusy must be set) + * + * Notes: + * 1. This routine is called either by the protocol stack or by the "net + * bottom half" (with interrupts enabled). + * 2. Setting tbusy flag will inhibit further transmit requests from the + * protocol stack and can be used for flow control with protocol layer. + */ +static int if_send (struct sk_buff* skb, netdevice_t* dev) +{ + bscmp_private_area_t *bscmp_priv_area = dev->priv; + sdla_t *card = bscmp_priv_area->card; + unsigned long smp_flag; + int err=-EBUSY; + +#if defined(LINUX_2_4)||defined(LINUX_2_6) + netif_stop_queue(dev); +#endif + + if (skb == NULL){ + /* If we get here, some higher layer thinks we've missed an + * tx-done interrupt. + */ + printk(KERN_INFO "%s: interface %s got kicked!\n", + card->devname, dev->name); + + wake_net_dev(dev); + return 0; + } + +#if defined(LINUX_2_1) + if (dev->tbusy){ + + /* If our device stays busy for at least 5 seconds then we will + * kick start the device by making dev->tbusy = 0. We expect + * that our device never stays busy more than 5 seconds. So this + * is only used as a last resort. + */ + ++card->wandev.stats.collisions; + if((jiffies - bscmp_priv_area->tick_counter) < (5 * HZ)) { + return 1; + } + + printk (KERN_INFO "%s: Transmit timeout !\n", + card->devname); + + /* unbusy the interface */ + clear_bit(0,&dev->tbusy); + } +#endif + + bsc_lock(&card->wandev.lock,smp_flag); + if(test_and_set_bit(SEND_CRIT, (void*)&card->wandev.critical)) { + + printk(KERN_INFO "%s: Critical in if_send: %lx\n", + card->wandev.name,card->wandev.critical); + ++card->wandev.stats.tx_dropped; + start_net_queue(dev); + goto if_send_exit_crit; + } + + if(card->wandev.state != WAN_CONNECTED){ + ++card->wandev.stats.tx_dropped; + + }else if(!skb->protocol){ + ++card->wandev.stats.tx_errors; + + }else { + void* data = skb->data; + unsigned len = skb->len; + unsigned char station=0; + unsigned char misc_tx_rx_bits=0; + api_tx_hdr_t* api_tx_hdr; + + /* discard the frame if we are configured for */ + /* 'receive only' mode or if there is no data */ + if (len <= sizeof(api_tx_hdr_t)) { + ++card->wandev.stats.tx_dropped; + goto if_send_exit_crit; + } + + api_tx_hdr = (api_tx_hdr_t *)data; + station = api_tx_hdr->station; + misc_tx_rx_bits = api_tx_hdr->misc_tx_rx_bits; + data += sizeof(api_tx_hdr_t); + len -= sizeof(api_tx_hdr_t); + + err=bscmp_send(card, station, misc_tx_rx_bits, data, len); + if (err==0){ + ++card->wandev.stats.tx_packets; + card->wandev.stats.tx_bytes += len; + +#if defined(LINUX_2_4)||defined(LINUX_2_6) + dev->trans_start = jiffies; +#endif + } + } + + start_net_queue(dev); + +if_send_exit_crit: + + if (!err) { + wan_dev_kfree_skb(skb, FREE_WRITE); + }else{ + stop_net_queue(dev); + bscmp_priv_area->dev_stop_timeout=jiffies; + } + + clear_bit(SEND_CRIT, (void*)&card->wandev.critical); + bsc_unlock(&card->wandev.lock,smp_flag); + + return err; +} + +static int if_ioctl (netdevice_t *dev, struct ifreq *ifr, int cmd) +{ + bscmp_private_area_t *chan; + wan_mbox_t *mbox, *user_mbox; + sdla_t *card; + unsigned long smp_flag; + int err=0; + + if (!dev || !(dev->flags & IFF_UP)){ + return -ENODEV; + } + + if (!(chan = dev->priv)){ + return -ENODEV; + } + + if (!(card = chan->card)){ + return -ENODEV; + } + + + mbox = &card->wan_mbox; + + switch(cmd){ + + case SIOC_WANPIPE_BIND_SK: + if (!ifr){ + err= -EINVAL; + break; + } + + DEBUG_TEST("%s: SIOC_WANPIPE_BIND_SK \n",__FUNCTION__); + spin_lock_irqsave(&card->wandev.lock,smp_flag); + err=wan_bind_api_to_svc(chan,ifr->ifr_data); + spin_unlock_irqrestore(&card->wandev.lock,smp_flag); + break; + + case SIOC_WANPIPE_UNBIND_SK: + if (!ifr){ + err= -EINVAL; + break; + } + + DEBUG_TEST("%s: SIOC_WANPIPE_UNBIND_SK \n",__FUNCTION__); + + spin_lock_irqsave(&card->wandev.lock,smp_flag); + err=wan_unbind_api_from_svc(chan,ifr->ifr_data); + spin_unlock_irqrestore(&card->wandev.lock,smp_flag); + break; + + case SIOC_WANPIPE_CHECK_TX: + case SIOC_ANNEXG_CHECK_TX: + err=0; + break; + + case SIOC_WANPIPE_DEV_STATE: + err = chan->common.state; + break; + + case SIOC_ANNEXG_KICK: + err=0; + break; + + + case SIOC_WANPIPE_BSC_CMD: + + user_mbox= (wan_mbox_t*)ifr->ifr_data; + if (!user_mbox){ + err=-EINVAL; + break; + } + + + if (copy_from_user(&mbox->wan_command,&user_mbox->wan_command,MBOX_HEADER_SZ)){ + goto if_ioctl_err; + } + + if (mbox->wan_data_len){ + if (copy_from_user(mbox->wan_data,user_mbox->wan_data,mbox->wan_data_len)){ + goto if_ioctl_err; + } + } + + bsc_lock(&card->wandev.lock,smp_flag); + + err = card->hw_iface.cmd(card->hw, card->mbox_off, mbox); + + if (err != OK){ + bscmp_error(card, err, mbox); + bsc_unlock(&card->wandev.lock,smp_flag); + goto if_ioctl_err; + } + bsc_unlock(&card->wandev.lock,smp_flag); + + + if (copy_to_user(&user_mbox->wan_command,&mbox->wan_command,MBOX_HEADER_SZ)){ + goto if_ioctl_err; + } + + if (mbox->wan_data_len){ + if (copy_to_user(user_mbox->wan_data,mbox->wan_data,mbox->wan_data_len)){ + err=-EFAULT; + goto if_ioctl_err; + } + } + + switch (mbox->wan_command){ + + case ADD_STATION: + case DELETE_STATION: + case DELETE_ALL_STATIONS: + case SET_CONFIGURATION: + set_bit(0,&chan->station_change); + break; + } + +if_ioctl_err: + break; + + default: + err = -EOPNOTSUPP; + break; + } + + return err; +} + +void event_poll (unsigned long dev_ptr) +{ + netdevice_t *dev = (netdevice_t *)dev_ptr; + bscmp_private_area_t *bscmp_priv_area = dev->priv; + sdla_t *card = bscmp_priv_area->card; + wan_mbox_t* mbox = &card->wan_mbox; + struct sk_buff *skb; + int i, start_dev=0, cur_dev=0; + api_rx_element_t *rx_el; + void *buf; + unsigned long smp_flag; + + bsc_lock(&card->wandev.lock,smp_flag); + + set_bit(SEND_CRIT,&card->wandev.critical); + + if (is_queue_stopped(dev)){ + if ((jiffies-bscmp_priv_area->dev_stop_timeout) > (HZ/20)){ + start_net_queue(dev); + wan_wakeup_api(bscmp_priv_area); + } + } + + if (bscmp_read_link_stats (card) != 0){ + goto event_exit; + } + + if (mbox->wan_data[0] == 0){ + port_set_state (card, WAN_DISCONNECTED); + goto event_exit; + }else{ + port_set_state (card, WAN_CONNECTED); + } + + /* Data available for read */ + if (!mbox->wan_data[1]){ + goto event_exit; + } + + if (test_bit(0,&bscmp_priv_area->station_change)){ + + memset(bscmp_priv_area->active_chan, 0, + sizeof(bscmp_priv_area->active_chan)); + + if (bscmp_list_stations(card) != 0){ + goto event_exit; + } + clear_bit(0,&bscmp_priv_area->station_change); + + for (i=0;iwan_data_len;){ + bscmp_priv_area->active_chan[mbox->wan_data[i]]=1; + i+=10; + } + bscmp_priv_area->cur_dev=mbox->wan_data[0]; + } +#if _BSC_DEBUG_ + printk(KERN_INFO "Starting Rx with station %i\n",bscmp_priv_area->cur_dev); +#endif + start_dev=bscmp_priv_area->cur_dev; + + for (i=0;iwan_data_len); +#endif + + skb = dev_alloc_skb(mbox->wan_data_len+sizeof(api_rx_hdr_t)+5); + if (!skb){ + printk(KERN_INFO "%s: Failed to allocate skb!\n", + card->devname); + goto event_exit; + } + + rx_el=(api_rx_element_t*)skb_put(skb,sizeof(api_rx_hdr_t)); + memset(rx_el,0,sizeof(api_rx_hdr_t)); + rx_el->api_rx_hdr.station = cur_dev; + + buf=(api_rx_element_t*)skb_put(skb,mbox->wan_data_len); + memcpy(buf,mbox->wan_data,mbox->wan_data_len); + + skb->protocol = htons(PVC_PROT); + skb->mac.raw = skb->data; + skb->dev = dev; + skb->pkt_type = WAN_PACKET_DATA; + + if (wan_api_rx(bscmp_priv_area,skb) != 0){ + printk(KERN_INFO "%s: Failed to rx data via socket, socket full!\n", + card->devname); + dev_kfree_skb(skb); + ++card->wandev.stats.rx_dropped; + goto event_exit; + }else{ + ++card->wandev.stats.rx_packets; + card->wandev.stats.rx_bytes += mbox->wan_data_len; + } + skb=NULL; + } + } + +event_exit: + clear_bit(SEND_CRIT,&card->wandev.critical); + bscmp_priv_area->poll_timer.expires=jiffies+POLL_WAIT; + add_timer(&bscmp_priv_area->poll_timer); + + bsc_unlock(&card->wandev.lock,smp_flag); + return; +} + + +/*============================================================================ + * Get ethernet-style interface statistics. + * Return a pointer to struct enet_statistics. + */ +static struct net_device_stats* if_stats (netdevice_t* dev) +{ + sdla_t *my_card; + bscmp_private_area_t* bscmp_priv_area; + + if ((bscmp_priv_area=dev->priv) == NULL) + return NULL; + + my_card = bscmp_priv_area->card; + return &my_card->wandev.stats; +} + + + +/****** BiSync Firmware Interface Functions *******************************/ + + +static int bscmp_comm_disable (sdla_t* card) +{ + int err; + wan_mbox_t* mb = &card->wan_mbox; + + memset(mb,0,MBOX_HEADER_SZ); + + mb->wan_data_len = 0; + mb->wan_command = CLOSE_LINK; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != OK) + bscmp_error(card, err, mb); + + return err; +} + + + +static int bscmp_read (sdla_t* card, int station) +{ + int err; + wan_mbox_t* mb = &card->wan_mbox; + + memset(mb,0,MBOX_HEADER_SZ); + mb->wan_data_len = 0; + mb->wan_bsc_station = station; + mb->wan_command = BSC_READ; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != OK) + bscmp_error(card,err,mb); + return err; +} + + +static int bscmp_read_link_stats (sdla_t* card) +{ + int err; + wan_mbox_t* mb = &card->wan_mbox; + + memset(mb,0,MBOX_HEADER_SZ); + + mb->wan_data_len = 0; + mb->wan_command = LINK_STATUS; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != OK) + bscmp_error(card,err,mb); + return err; +} + +static int bscmp_read_code_version (sdla_t* card) +{ + int err; + wan_mbox_t* mb = &card->wan_mbox; + + memset(mb,0,MBOX_HEADER_SZ); + mb->wan_data_len = 0; + mb->wan_command = READ_CODE_VERSION; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != OK) + bscmp_error(card,err,mb); + return err; +} + +static int bscmp_configure (sdla_t* card, BSC_CONFIG_STRUCT *cfg) +{ + int err; + wan_mbox_t* mb = &card->wan_mbox; + + memset(mb,0,MBOX_HEADER_SZ); + + mb->wan_data_len = sizeof(BSC_CONFIG_STRUCT); + mb->wan_command = SET_CONFIGURATION; + memcpy(mb->wan_data,cfg,sizeof(BSC_CONFIG_STRUCT)); + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != OK) + bscmp_error(card,err,mb); + + return err; +} + +static int bscmp_read_config (sdla_t* card) +{ + int err; + wan_mbox_t* mb = &card->wan_mbox; + + memset(mb,0,MBOX_HEADER_SZ); + mb->wan_data_len = 0; + mb->wan_command = READ_CONFIGURATION; + + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != OK) + bscmp_error(card,err,mb); + + return err; +} + +static int bscmp_list_stations (sdla_t* card) +{ + int err; + wan_mbox_t* mb = &card->wan_mbox; + memset(mb,0,MBOX_HEADER_SZ); + mb->wan_data_len = 0; + mb->wan_command = LIST_STATIONS; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != OK) + bscmp_error(card,err,mb); + + return err; +} + + + + +/*============================================================================ + * Send packet. + * Return: 0 - o.k. + * 1 - no transmit buffers available + */ +static int bscmp_send (sdla_t* card, unsigned char station, + unsigned char misc_tx_rx_bits, + void* data, unsigned len) +{ + wan_mbox_t* mbox = &card->wan_mbox; + int err; + + memset(mbox,0,MBOX_HEADER_SZ); + mbox->wan_command = BSC_WRITE; + mbox->wan_data_len = len; + mbox->wan_bsc_station = station; + mbox->wan_bsc_misc_bits=misc_tx_rx_bits; + + memcpy(mbox->wan_data,data,len); + + err = card->hw_iface.cmd(card->hw, card->mbox_off, mbox); + if (err != OK && err != 0x02) + bscmp_error(card,err,mbox); + + return err; +} + +/****** Firmware Error Handler **********************************************/ + +/*============================================================================ + * Firmware error handler. + * This routine is called whenever firmware command returns non-zero + * return code. + * + * Return zero if previous command has to be cancelled. + */ +static int bscmp_error (sdla_t *card, int err, wan_mbox_t *mb) +{ + unsigned cmd = mb->wan_command; + + switch (err) { + + case CMD_TIMEOUT: + printk(KERN_INFO "%s: command 0x%02X timed out!\n", + card->devname, cmd); + break; + + default: + printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n", + card->devname, cmd, err); + } + + return 0; +} + +static void port_set_state (sdla_t *card, int state) +{ + netdevice_t *dev; + + if (card->wandev.state != state) + { + switch (state) + { + case WAN_CONNECTED: + printk (KERN_INFO "%s: Link connected!\n", + card->devname); + break; + + case WAN_CONNECTING: + printk (KERN_INFO "%s: Link connecting...\n", + card->devname); + break; + + case WAN_DISCONNECTED: + printk (KERN_INFO "%s: Link disconnected!\n", + card->devname); + break; + } + + card->wandev.state = state; + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + if (dev){ + bscmp_private_area_t* bscmp_priv_area = dev->priv; + bscmp_priv_area->common.state = state; + + wan_update_api_state(bscmp_priv_area); + } + } +} + +static int find_active_chan(bscmp_private_area_t* bscmp_priv_area, int start_chan) +{ + int i=bscmp_priv_area->cur_dev; + +#if _BSC_DEBUG_ + printk(KERN_INFO "\n"); + printk(KERN_INFO "Finding Station: Start=%i Curr=%i\n", + start_chan,i); +#endif + for (;;){ + if (bscmp_priv_area->active_chan[i]){ + bscmp_priv_area->cur_dev=i; + if (++bscmp_priv_area->cur_dev >= MAX_ACTIVE_CHAN){ + bscmp_priv_area->cur_dev=0; + } + return i; + } + + if (++i >= MAX_ACTIVE_CHAN){ + i=0; + } + + bscmp_priv_area->cur_dev=i; + + if (i==start_chan) + break; + } + return -ENODEV; +} + +/****** End ****************************************************************/ diff -Nur linux.org/drivers/net/wan/sdla_bscstrm.c linux-2.6.17/drivers/net/wan/sdla_bscstrm.c --- linux.org/drivers/net/wan/sdla_bscstrm.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/drivers/net/wan/sdla_bscstrm.c 2006-08-30 10:07:16.000000000 +0000 @@ -0,0 +1,1073 @@ +/***************************************************************************** +* sdla_bscstrm.c WANPIPE(tm) Multiprotocol WAN Link Driver. +* BiSync Streaming module. +* +* Author: Nenad Corbic +* +* Copyright: (c) 1995-2001 Sangoma Technologies Inc. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version +* 2 of the License, or (at your option) any later version. +* ============================================================================ +* Mar , 2001 Nenad Corbic Inital version, based on bsc module. +* Using Gideons new bisync streaming firmware. +*****************************************************************************/ + +#include +#include +#include /* WAN router definitions */ +#include /* WANPIPE common user API definitions */ +#include +#include /* BSTRM firmware API definitions */ +#include /* Socket Driver common area */ +#include + + + +/****** Defines & Macros ****************************************************/ + +#undef _BSC_DEBUG_ + +#if defined(LINUX_2_4)||defined(LINUX_2_6) + #define bsc_lock(a,b) {b=0;spin_lock_bh(a);} + #define bsc_unlock(a,b) {b=0;spin_unlock_bh(a);} +#elif defined (LINUX_2_1) + #define bsc_lock(a,b) spin_lock_irqsave(a,b) + #define bsc_unlock(a,b) spin_unlock_irqrestore(a,b) +#else + #define bsc_lock(a,b) + #define bsc_unlock(a,b) +#endif + + +/* reasons for enabling the timer interrupt on the adapter */ +#define TMR_INT_ENABLED_UDP 0x01 +#define TMR_INT_ENABLED_UPDATE 0x02 +#define TMR_INT_ENABLED_CONFIG 0x10 + +#define MAX_IP_ERRORS 10 + +#define BSTRM_DFLT_DATA_LEN 1500 /* default MTU */ +#define BSTRM_HDR_LEN 1 + +#define BSTRM_API 0x01 + +#define PORT(x) (x == 0 ? "PRIMARY" : "SECONDARY" ) +#define MAX_BH_BUFF 10 + +//#define PRINT_DEBUG +#ifdef PRINT_DEBUG +#define dbg_printk(format, a...) printk(format, ## a) +#else +#define dbg_printk(format, a...) +#endif + +#define _INB(port) (inb(port)) +#define _OUTB(port, byte) (outb((byte),(port))) + + +#define OK 0 +#define MAX_ACTIVE_CHAN 200 +#define MAX_POLL_CNT 20 +/******Data Structures*****************************************************/ + +/* This structure is placed in the private data area of the device structure. + * The card structure used to occupy the private area but now the following + * structure will incorporate the card structure along with BSTRM specific data + */ + +typedef struct bscstrm_private_area +{ + wanpipe_common_t common; + sdla_t *card; + unsigned long router_start_time; + unsigned long tick_counter; /* For 5s timeout counter */ + unsigned long router_up_time; + u8 config_bstrm; + u8 config_bscstrm_timeout; + u8 true_if_encoding; + unsigned char active_chan[MAX_ACTIVE_CHAN]; + unsigned char cur_dev; +} bscstrm_private_area_t; + +/* Route Status options */ +#define NO_ROUTE 0x00 +#define ADD_ROUTE 0x01 +#define ROUTE_ADDED 0x02 +#define REMOVE_ROUTE 0x03 + + +/* variable for tracking how many interfaces to open for WANPIPE on the + two ports */ + + +/****** Function Prototypes *************************************************/ +/* WAN link driver entry points. These are called by the WAN router module. */ +static int update (wan_device_t* wandev); +static int new_if (wan_device_t* wandev, netdevice_t* dev, + wanif_conf_t* conf); +static int del_if (wan_device_t* wandev, netdevice_t* dev); + +/* Network device interface */ +static int if_init (netdevice_t* dev); +static int if_open (netdevice_t* dev); +static int if_close (netdevice_t* dev); +static int if_ioctl (netdevice_t *dev, struct ifreq *ifr, int cmd); +static struct net_device_stats* if_stats (netdevice_t* dev); + +static int if_send (struct sk_buff* skb, netdevice_t* dev); + +/* BSTRM Firmware interface functions */ +static int bscstrm_comm_enable (sdla_t* card); +static int bscstrm_comm_disable (sdla_t* card); +static int bscstrm_error (sdla_t *card, int err, wan_mbox_t *mb); +static int bscstrm_read_code_version (sdla_t* card); +static int bscstrm_configure (sdla_t* card, CONFIGURATION_STRUCT *cfg); +static int bscstrm_read_config (sdla_t* card); +static int bscstrm_enable_rx_isr (sdla_t* card); + +static void wp_bscstrm_isr (sdla_t *card); +static void port_set_state (sdla_t *card, int state); + +/****** Public Functions ****************************************************/ + +/*============================================================================ + * Cisco HDLC protocol initialization routine. + * + * This routine is called by the main WANPIPE module during setup. At this + * point adapter is completely initialized and firmware is running. + * o read firmware version (to make sure it's alive) + * o configure adapter + * o initialize protocol-specific fields of the adapter data space. + * + * Return: 0 o.k. + * < 0 failure. + */ +#undef NASDAQ_BSC +int wp_bscstrm_init (sdla_t* card, wandev_conf_t* conf) +{ + int err; + unsigned long timeout; + wan_mbox_t* mbox; + +#ifdef NASDAQ_BSC + + CONFIGURATION_STRUCT cfg = { + 0, /* baud rate */ + 0, /* the adapter frequecy */ + 1000, /* the maximum length of a BSC data block */ + 0, /* EBCDIC/ASCII encoding */ + RX_BLOCK_TYPE_3,/* the type of BSC block to be received */ + 3, /* the number of consecutive PADs indicating + * the end of the block */ + 0, /* the number of additional leading transmit + * SYN characters */ + 8, /* the number of bits per character */ + ODD_PARITY, /* parity */ + 0, /* miscellaneous configuration options */ + (RX_STATISTICS| + RX_TIME_STAMP| + TX_STATISTICS), /* statistic options */ + 0 }; /* modem configuration options */ + + printk(KERN_INFO "%s: Configuring for NASDAQ BiSync streaming\n", + card->devname); + +#else + + CONFIGURATION_STRUCT cfg = { + 0, /* baud rate */ + 0, /* the adapter frequecy */ + 1000, /* the maximum length of a BSC data block */ + 1, /* EBCDIC/ASCII encoding */ + RX_BLOCK_TYPE_1,/* the type of BSC block to be received */ + 3, /* the number of consecutive PADs indicating + * the end of the block */ + 0, /* the number of additional leading transmit + * SYN characters */ + 8, /* the number of bits per character */ + NO_PARITY, /* parity */ + 0, /* miscellaneous configuration options */ + (RX_STATISTICS| + RX_TIME_STAMP| + TX_STATISTICS), /* statistic options */ + 0 }; /* modem configuration options */ + + printk(KERN_INFO "%s: Configuring for BiSync streaming\n", + card->devname); + +#endif + + + /* Verify configuration ID */ + if (conf->config_id != WANCONFIG_BSCSTRM) { + printk(KERN_INFO "%s: invalid configuration ID %u!\n", + card->devname, conf->config_id); + return -EINVAL; + } + + /* Find out which Port to use */ + card->wandev.comm_port = conf->comm_port; + + /* Initialize protocol-specific fields */ + if(card->type != SDLA_S514){ + + //FIXME: CHECK THAT MBOX IS RIGHT !!!! + /* Alex Apr 8 2004 Sangoma ISA card -> card->mbox_off = 0; */ + card->mbox_off = BASE_ADDR_SEND_MB; + if (card->hw_iface.mapmem){ + err = card->hw_iface.mapmem(card->hw, BASE_ADDR_SEND_MB); + }else{ + err = -EINVAL; + } + if (err){ + return err; + } + + }else{ + card->mbox_off = BASE_ADDR_SEND_MB; + } + + mbox=&card->wan_mbox; + + timeout=jiffies; + while((jiffies-timeout) < (HZ)){ + schedule(); + } + + /* Read firmware version. Note that when adapter initializes, it + * clears the mailbox, so it may appear that the first command was + * executed successfully when in fact it was merely erased. To work + * around this, we execute the first command twice. + */ + + if (bscstrm_read_code_version(card)){ + card->wandev.state = WAN_DISCONNECTED; + return -EIO; + } + + printk(KERN_INFO "%s: Running Bisync Streaming firmware v%s\n", + card->devname, mbox->wan_data); + + card->isr = &wp_bscstrm_isr; + card->poll = NULL; + card->exec = NULL; + card->wandev.update = &update; + card->wandev.new_if = &new_if; + card->wandev.del_if = &del_if; + card->wandev.udp_port = conf->udp_port; + card->disable_comm = NULL; + card->wandev.new_if_cnt = 0; + + card->wandev.ttl = conf->ttl; + card->wandev.interface = conf->interface; + + card->wandev.clocking = conf->clocking; + card->wandev.mtu = 1000; + + + if (card->wandev.clocking == WANOPT_EXTERNAL){ + card->wandev.bscstrm_cfg.baud_rate = 0; + }else{ + card->wandev.bscstrm_cfg.baud_rate = conf->bps; + } + + memcpy(&card->wandev.bscstrm_cfg, &conf->u.bscstrm, sizeof(wan_bscstrm_conf_t)); + + cfg.baud_rate = card->wandev.bscstrm_cfg.baud_rate; + cfg.adapter_frequency = card->wandev.bscstrm_cfg.adapter_frequency; + cfg.max_data_length = card->wandev.bscstrm_cfg.max_data_length; + cfg.EBCDIC_encoding = card->wandev.bscstrm_cfg.EBCDIC_encoding; + cfg.Rx_block_type = card->wandev.bscstrm_cfg.Rx_block_type; + cfg.no_consec_PADs_EOB = card->wandev.bscstrm_cfg.no_consec_PADs_EOB; + cfg.no_add_lead_Tx_SYN_chars = card->wandev.bscstrm_cfg.no_add_lead_Tx_SYN_chars; + cfg.no_bits_per_char = card->wandev.bscstrm_cfg.no_bits_per_char; + cfg.parity = card->wandev.bscstrm_cfg.parity; + cfg.misc_config_options = card->wandev.bscstrm_cfg.misc_config_options; + cfg.statistics_options = card->wandev.bscstrm_cfg.statistics_options; + cfg.modem_config_options = card->wandev.bscstrm_cfg.modem_config_options; + + printk(KERN_INFO "%s: Bisync Streaming Config: \n",card->devname); + printk(KERN_INFO "%s: Comm Port = %s\n", + card->devname,card->wandev.comm_port==0?"PRI":"SEC"); + printk(KERN_INFO "%s: Baud Rate = %lu\n", + card->devname,card->wandev.bscstrm_cfg.baud_rate); + printk(KERN_INFO "%s: Adapter Frequency = %lu\n", + card->devname,card->wandev.bscstrm_cfg.adapter_frequency); + printk(KERN_INFO "%s: Max Data Len = %u\n", + card->devname,card->wandev.bscstrm_cfg.max_data_length); + printk(KERN_INFO "%s: EBCDIC Encoding = %u\n", + card->devname,card->wandev.bscstrm_cfg.EBCDIC_encoding); + printk(KERN_INFO "%s: Rx Block Type = %u\n", + card->devname,card->wandev.bscstrm_cfg.Rx_block_type); + printk(KERN_INFO "%s: Num Cons PADs Eob = %u\n", + card->devname,card->wandev.bscstrm_cfg.no_consec_PADs_EOB); + printk(KERN_INFO "%s: Num Lead Tx Syn Ch= %u\n", + card->devname,card->wandev.bscstrm_cfg.no_add_lead_Tx_SYN_chars); + printk(KERN_INFO "%s: Num Bits Per Char = %u\n", + card->devname,card->wandev.bscstrm_cfg.no_bits_per_char); + printk(KERN_INFO "%s: Parity = %u\n", + card->devname,card->wandev.bscstrm_cfg.parity); + printk(KERN_INFO "%s: Misc Config Opt = 0x%X\n", + card->devname,card->wandev.bscstrm_cfg.misc_config_options); + printk(KERN_INFO "%s: Statistics Opt = 0x%X\n", + card->devname,card->wandev.bscstrm_cfg.statistics_options); + printk(KERN_INFO "%s: Modem Config Opt = 0x%X\n", + card->devname,card->wandev.bscstrm_cfg.modem_config_options); + + + printk(KERN_INFO "%s: Configuring Bisync Streaming!\n",card->devname); + if (bscstrm_configure (card,&cfg) != 0){ + printk(KERN_INFO "%s: Failed to configure BiSync Streaming\n", + card->devname); + return -EINVAL; + } + + /* This is for the ports link state */ + card->wandev.state = WAN_DISCONNECTED; + + bscstrm_read_config(card); + + printk(KERN_INFO "\n"); + + return 0; +} + + +/******* WAN Device Driver Entry Points *************************************/ + +/*============================================================================ + * Update device status & statistics + * This procedure is called when updating the PROC file system and returns + * various communications statistics. These statistics are accumulated from 3 + * different locations: + * 1) The 'if_stats' recorded for the device. + * 2) Communication error statistics on the adapter. + * 3) BSTRM operational statistics on the adapter. + * The board level statistics are read during a timer interrupt. Note that we + * read the error and operational statistics during consecitive timer ticks so + * as to minimize the time that we are inside the interrupt handler. + * + */ +static int update (wan_device_t* wandev) +{ + sdla_t* card = wandev->private; + netdevice_t* dev; + volatile bscstrm_private_area_t* bscstrm_priv_area; + + /* sanity checks */ + if((wandev == NULL) || (wandev->private == NULL)) + return -EFAULT; + + if(wandev->state == WAN_UNCONFIGURED) + return -ENODEV; + + if(test_bit(PERI_CRIT, (void*)&card->wandev.critical)) + return -EAGAIN; + + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + if(dev == NULL) + return -ENODEV; + + if((bscstrm_priv_area=dev->priv) == NULL) + return -ENODEV; + + + return 0; +} + +static void bscstrm_bh (unsigned long data) +{ + DEBUG_EVENT("%s: Not used!\n",__FUNCTION__); + return; +} + +/*============================================================================ + * Create new logical channel. + * This routine is called by the router when ROUTER_IFNEW IOCTL is being + * handled. + * o parse media- and hardware-specific configuration + * o make sure that a new channel can be created + * o allocate resources, if necessary + * o prepare network device structure for registaration. + * + * Return: 0 o.k. + * < 0 failure (channel will not be created) + */ +static int new_if (wan_device_t* wandev, netdevice_t* dev, wanif_conf_t* conf) +{ + sdla_t* card = wandev->private; + bscstrm_private_area_t* bscstrm_priv_area; + + + printk(KERN_INFO "%s: Configuring Interface: %s\n", + card->devname, conf->name); + + if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) { + printk(KERN_INFO "%s: Invalid interface name!\n", + card->devname); + return -EINVAL; + } + + if (card->wandev.new_if_cnt){ + return -EEXIST; + } + + /* allocate and initialize private data */ + bscstrm_priv_area = kmalloc(sizeof(bscstrm_private_area_t), GFP_KERNEL); + + if(bscstrm_priv_area == NULL) + return -ENOMEM; + + memset(bscstrm_priv_area, 0, sizeof(bscstrm_private_area_t)); + + bscstrm_priv_area->card = card; + + bscstrm_priv_area->common.sk = NULL; + bscstrm_priv_area->common.state = WAN_DISCONNECTED; + bscstrm_priv_area->common.dev = dev; + + if(card->wandev.new_if_cnt > 0) { + kfree(bscstrm_priv_area); + return -EEXIST; + } + + + /* Setup wanpipe as a router (WANPIPE) or as an API */ + if (strcmp(conf->usedby, "API") == 0) { + printk(KERN_INFO "%s: Running in API mode !\n", + wandev->name); + }else{ + printk(KERN_INFO "%s: Bisync protocol doesn't support WANPIPE mode! API only!\n", + wandev->name); + kfree(bscstrm_priv_area); + return -EINVAL; + } + + wan_reg_api(bscstrm_priv_area, dev, card->devname); + WAN_TASKLET_INIT((&bscstrm_priv_area->common.bh_task),0,bscstrm_bh,(unsigned long)bscstrm_priv_area); + + /* prepare network device data space for registration */ + card->rxmb_off = card->mbox_off + 0x1000; + + dev->init = &if_init; + dev->priv = bscstrm_priv_area; + + card->wandev.new_if_cnt++; + return 0; +} + +static int del_if (wan_device_t* wandev, netdevice_t* dev) +{ + bscstrm_private_area_t* chan = dev->priv; + sdla_t* card = chan->card; + + WAN_TASKLET_KILL(&chan->common.bh_task); + wan_unreg_api(chan, card->devname); + + return 0; +} + + +/****** Network Device Interface ********************************************/ + +/*============================================================================ + * Initialize Linux network interface. + * + * This routine is called only once for each interface, during Linux network + * interface registration. Returning anything but zero will fail interface + * registration. + */ +static int if_init (netdevice_t* dev) + { + bscstrm_private_area_t* bscstrm_priv_area = dev->priv; + sdla_t* card = bscstrm_priv_area->card; + wan_device_t* wandev = &card->wandev; + + /* Initialize device driver entry points */ + dev->open = &if_open; + dev->stop = &if_close; + dev->hard_header = NULL; + dev->rebuild_header = NULL; + dev->hard_start_xmit = &if_send; + dev->get_stats = &if_stats; + dev->do_ioctl = &if_ioctl; +#if defined(LINUX_2_4)||defined(LINUX_2_6) + dev->tx_timeout = NULL; + dev->watchdog_timeo = TX_TIMEOUT; +#endif + + + /* Initialize media-specific parameters */ + dev->flags |= IFF_POINTOPOINT; + dev->flags |= IFF_NOARP; + + + if (bscstrm_priv_area->true_if_encoding){ + dev->type = ARPHRD_HDLC; /* This breaks the tcpdump */ + }else{ + dev->type = ARPHRD_PPP; + } + + dev->mtu = card->wandev.mtu; + /* for API usage, add the API header size to the requested MTU size */ + dev->mtu += sizeof(api_tx_hdr_t); + + dev->hard_header_len = BSTRM_HDR_LEN; + + /* Initialize hardware parameters */ + dev->irq = wandev->irq; + dev->dma = wandev->dma; + dev->base_addr = wandev->ioport; + card->hw_iface.getcfg(card->hw, SDLA_MEMBASE, &dev->mem_start); //ALEX_TODAY wandev->maddr; + card->hw_iface.getcfg(card->hw, SDLA_MEMEND, &dev->mem_end); //ALEX_TODAY wandev->maddr + wandev->msize - 1; + + /* Set transmit buffer queue length + * If too low packets will not be retransmitted + * by stack. + */ + dev->tx_queue_len = 100; + + return 0; +} + +/*============================================================================ + * Open network interface. + * o enable communications and interrupts. + * o prevent module from unloading by incrementing use count + * + * Return 0 if O.k. or errno. + */ +static int if_open (netdevice_t* dev) +{ + bscstrm_private_area_t* bscstrm_priv_area = dev->priv; + sdla_t* card = bscstrm_priv_area->card; + struct timeval tv; + int err = 0; + + /* Only one open per interface is allowed */ + if (open_dev_check(dev)) + return -EBUSY; + + do_gettimeofday(&tv); + bscstrm_priv_area->router_start_time = tv.tv_sec; + + err=bscstrm_enable_rx_isr(card); + if (err){ + printk(KERN_INFO "%s: Failed to enable BiSync Streaming Rx ISR.\n", + card->devname); + return -EIO; + } + printk(KERN_INFO "%s: Enabling bscstrm rx isr\n",card->devname); + + + err=bscstrm_comm_enable (card); + if (err){ + printk(KERN_INFO "%s: Failed to enable BiSync Streaming Communications.\n", + card->devname); + return -EINVAL; + } + + printk(KERN_INFO "%s: Enabling bscstrm communication\n",card->devname); + + + netif_start_queue(dev); + + port_set_state(card,WAN_CONNECTED); + + wanpipe_open(card); + return 0; +} + +/*============================================================================ + * Close network interface. + * o if this is the last close, then disable communications and interrupts. + * o reset flags. + */ +static int if_close (netdevice_t* dev) +{ + bscstrm_private_area_t* bscstrm_priv_area = dev->priv; + sdla_t* card = bscstrm_priv_area->card; + + stop_net_queue(dev); +#if defined(LINUX_2_1) + dev->start=0; +#endif + wanpipe_close(card); + + bscstrm_comm_disable(card); + card->wandev.state = WAN_DISCONNECTED; + return 0; +} + + +/*============================================================================ + * Send a packet on a network interface. + * + * This routine is not being used + * since the bscstrmp protocol work with + * ioctl() calls. + * + * Furthermore, bscstrm driver is receive only. + */ +static int if_send (struct sk_buff* skb, netdevice_t* dev) +{ + bscstrm_private_area_t *chan = dev->priv; + sdla_t *card = chan->card; + wan_mbox_t *mbox = &card->wan_mbox; + unsigned long smp_flags; + api_tx_element_t *api_tx_el = (api_tx_element_t *)&skb->data[0]; + int err; + int len = skb->len-sizeof(api_tx_hdr_t); + + if (len <= 0){ + DEBUG_EVENT("%s: Error: Tx size (%i) <= tx element size (%i)\n", + card->devname,skb->len,sizeof(api_tx_hdr_t)); + start_net_queue(dev); + return 1; + } + + if (chan->common.state != WAN_CONNECTED){ + stop_net_queue(dev); + ++card->wandev.stats.tx_carrier_errors; + return 1; + } + + wan_spin_lock_irq(&card->wandev.lock, &smp_flags); + if (card->next){ + wan_spin_lock(&card->next->wandev.lock); + } + + mbox->wan_command=BSC_WRITE; + mbox->wan_data_len=len; + mbox->wan_bscstrm_port=card->wandev.comm_port; + mbox->wan_bscstrm_misc_bits=api_tx_el->api_tx_hdr.misc_tx_rx_bits; + memcpy(mbox->wan_data,api_tx_el->data,len); + + err = card->hw_iface.cmd(card->hw, card->mbox_off, mbox); + + if (card->next){ + wan_spin_unlock(&card->next->wandev.lock); + } + wan_spin_unlock_irq(&card->wandev.lock, &smp_flags); + + if (err != 0){ + + if (err != TX_BUFFERS_FULL){ + DEBUG_EVENT("%s: Bisync Tx error 0x%X\n", + card->devname,err); + } + + start_net_queue(dev); + return 1; + } + + ++card->wandev.stats.tx_packets; + card->wandev.stats.tx_bytes=len; + + start_net_queue(dev); + wan_dev_kfree_skb(skb, FREE_WRITE); + + return 0; +} + +static int if_ioctl (netdevice_t *dev, struct ifreq *ifr, int cmd) +{ + bscstrm_private_area_t *chan; + wan_mbox_t *mbox, *user_mbox; + sdla_t *card; + int err=0; + unsigned long smp_flags; + + if (!dev || !(dev->flags & IFF_UP)){ + return -ENODEV; + } + + if (!(chan = dev->priv)){ + return -ENODEV; + } + + if (!(card = chan->card)){ + return -ENODEV; + } + + mbox=&card->wan_mbox; + + switch(cmd){ + + case SIOC_WANPIPE_BIND_SK: + if (!ifr){ + err= -EINVAL; + break; + } + + DEBUG_TEST("%s: SIOC_WANPIPE_BIND_SK \n",__FUNCTION__); + wan_spin_lock_irq(&card->wandev.lock, &smp_flags); + err=wan_bind_api_to_svc(chan,ifr->ifr_data); + wan_spin_unlock_irq(&card->wandev.lock, &smp_flags); + break; + + case SIOC_WANPIPE_UNBIND_SK: + if (!ifr){ + err= -EINVAL; + break; + } + + DEBUG_TEST("%s: SIOC_WANPIPE_UNBIND_SK \n",__FUNCTION__); + wan_spin_lock_irq(&card->wandev.lock, &smp_flags); + err=wan_unbind_api_from_svc(chan, ifr->ifr_data); + wan_spin_unlock_irq(&card->wandev.lock, &smp_flags); + break; + + case SIOC_WANPIPE_CHECK_TX: + case SIOC_ANNEXG_CHECK_TX: + err=0; + break; + + case SIOC_WANPIPE_DEV_STATE: + err = chan->common.state; + break; + + case SIOC_ANNEXG_KICK: + err=0; + break; + + default: + + user_mbox= (wan_mbox_t*)ifr->ifr_data; + + if (!user_mbox){ + err=-EINVAL; + break; + } + + if (cmd != SIOC_WANPIPE_BSC_CMD){ + return -EOPNOTSUPP; + } + + memset(mbox,0,sizeof(wan_cmd_t)); + + if (copy_from_user(&mbox->wan_command,&user_mbox->wan_command,sizeof(wan_cmd_t))){ + return -EFAULT; + } + + if (mbox->wan_data_len){ + if (copy_from_user(mbox->wan_data,user_mbox->wan_data,mbox->wan_data_len)){ + return -EFAULT; + } + } + + wan_spin_lock_irq(&card->wandev.lock, &smp_flags); + err = card->hw_iface.cmd(card->hw, card->mbox_off, mbox); + wan_spin_unlock_irq(&card->wandev.lock, &smp_flags); + + if (err != OK){ + bscstrm_error(card, err, mbox); + return -EINVAL; + } + + if (copy_to_user(&user_mbox->wan_command,&mbox->wan_command,sizeof(wan_cmd_t))){ + return -EFAULT; + } + + if (mbox->wan_data_len){ + if (copy_to_user(user_mbox->wan_data,mbox->wan_data,mbox->wan_data_len)){ + return -EFAULT; + } + } + break; + } + + return err; +} + + + +static void wp_bscstrm_isr (sdla_t *card) +{ + netdevice_t *dev; + bscstrm_private_area_t *bscstrm_priv_area; + wan_mbox_t *mbox = &card->wan_mbox; + struct sk_buff *skb; + api_rx_element_t *rx_el; + unsigned char reset_byte=0; + void *buf; + + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + if (!dev){ + return; + } + + if ((bscstrm_priv_area = dev->priv) == NULL){ + return; + } + + card->hw_iface.peek(card->hw, card->rxmb_off, mbox, sizeof(wan_cmd_t)); + if (mbox->wan_data_len){ + card->hw_iface.peek(card->hw, + card->rxmb_off+offsetof(wan_mbox_t, wan_data), + mbox->wan_data, mbox->wan_data_len); + } + + DEBUG_TEST("%s: RX Intr: Flag=0x%X, Port=%d, Sk=%p\n", + card->devname, + mbox->wan_opp_flag,mbox->wan_bscstrm_port, + bscstrm_priv_area->common.sk); + + set_bit(0,&card->wandev.critical); + + if (!bscstrm_priv_area->common.sk){ + ++card->wandev.stats.rx_dropped; + goto event_exit; + } + + if (mbox->wan_opp_flag && mbox->wan_bscstrm_port == card->wandev.comm_port){ + +#ifdef _BSC_DEBUG_ + printk(KERN_INFO "Rx Pkt : Size %i: Gcnt %i\n", + mbox->wan_data_len,++gcount); +#endif + + skb = dev_alloc_skb(mbox->wan_data_len+sizeof(api_rx_hdr_t)+5); + if (!skb){ + printk(KERN_INFO "%s: Failed to allocate skb!\n", + card->devname); + mbox->wan_opp_flag=0; + card->hw_iface.poke(card->hw, card->rxmb_off, mbox, sizeof(wan_cmd_t)); + card->hw_iface.poke(card->hw,0xFFF0,&reset_byte,sizeof(reset_byte)); + ++card->wandev.stats.rx_dropped; + goto event_exit; + } + + rx_el=(api_rx_element_t*)skb_put(skb,sizeof(api_rx_hdr_t)); + memset(rx_el,0,sizeof(api_rx_hdr_t)); + + buf=(api_rx_element_t*)skb_put(skb,mbox->wan_data_len); + memcpy(buf,mbox->wan_data,mbox->wan_data_len); + skb->protocol = htons(PVC_PROT); + skb->mac.raw = skb->data; + skb->dev = dev; + skb->pkt_type = WAN_PACKET_DATA; + + if (wan_api_rx(bscstrm_priv_area,skb) != 0){ + dev_kfree_skb(skb); + ++card->wandev.stats.rx_dropped; + mbox->wan_opp_flag=0; + card->hw_iface.poke(card->hw, card->rxmb_off, mbox, sizeof(wan_cmd_t)); + card->hw_iface.poke(card->hw,0xFFF0,&reset_byte,sizeof(reset_byte)); + goto event_exit; + }else{ + ++card->wandev.stats.rx_packets; + card->wandev.stats.rx_bytes += mbox->wan_data_len; + } + + mbox->wan_opp_flag=0; + card->hw_iface.poke(card->hw, card->rxmb_off, mbox, sizeof(wan_cmd_t)); + card->hw_iface.poke(card->hw,0xFFF0,&reset_byte,sizeof(reset_byte)); + } + +event_exit: + if (mbox->wan_opp_flag && mbox->wan_bscstrm_port == card->wandev.comm_port){ + mbox->wan_opp_flag=0; + card->hw_iface.poke(card->hw, card->rxmb_off, mbox, sizeof(wan_cmd_t)); + card->hw_iface.poke(card->hw,0xFFF0,&reset_byte,sizeof(reset_byte)); + } + + clear_bit(0,&card->wandev.critical); + return; +} + + +/*============================================================================ + * Get ethernet-style interface statistics. + * Return a pointer to struct enet_statistics. + */ +static struct net_device_stats* if_stats (netdevice_t* dev) +{ + sdla_t *my_card; + bscstrm_private_area_t* bscstrm_priv_area; + + if ((bscstrm_priv_area=dev->priv) == NULL) + return NULL; + + my_card = bscstrm_priv_area->card; + return &my_card->wandev.stats; +} + + + +/****** BiSync Firmware Interface Functions *******************************/ + +static int bscstrm_comm_disable (sdla_t* card) +{ + int err; + wan_mbox_t* mb = &card->wan_mbox; + + memset(mb,0,MBOX_HEADER_SZ); + + mb->wan_data_len = 0; + mb->wan_command = DISABLE_COMMUNICATIONS; + mb->wan_bscstrm_port=card->wandev.comm_port; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != OK) + bscstrm_error(card, err, mb); + + return err; +} + +static int bscstrm_comm_enable (sdla_t* card) +{ + int err; + wan_mbox_t* mb = &card->wan_mbox; + memset(mb,0,MBOX_HEADER_SZ); + + mb->wan_data_len = 0; + mb->wan_command = ENABLE_COMMUNICATIONS; + mb->wan_bscstrm_port=card->wandev.comm_port; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != OK) + bscstrm_error(card, err, mb); + + return err; +} + + + +static int bscstrm_read_code_version (sdla_t* card) +{ + int err; + wan_mbox_t* mb = &card->wan_mbox; + + memset(mb,0,MBOX_HEADER_SZ); + + mb->wan_data_len = 0; + mb->wan_command = READ_CODE_VERSION; + mb->wan_bscstrm_port=card->wandev.comm_port; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != OK) + bscstrm_error(card,err,mb); + return err; +} + +static int bscstrm_configure (sdla_t* card, CONFIGURATION_STRUCT *cfg) +{ + int err; + wan_mbox_t* mb = &card->wan_mbox; + + memset(mb,0,MBOX_HEADER_SZ); + mb->wan_data_len = sizeof(CONFIGURATION_STRUCT); + mb->wan_command = SET_CONFIGURATION; + mb->wan_bscstrm_port=card->wandev.comm_port; + memcpy(mb->wan_data,cfg,sizeof(CONFIGURATION_STRUCT)); + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != OK) + bscstrm_error(card,err,mb); + + return err; +} + +static int bscstrm_read_config (sdla_t* card) +{ + int err; + wan_mbox_t* mb = &card->wan_mbox; + + memset(mb,0,MBOX_HEADER_SZ); + + mb->wan_data_len = 0; + mb->wan_command = READ_CONFIGURATION; + mb->wan_bscstrm_port=card->wandev.comm_port; + + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != OK) + bscstrm_error(card,err,mb); + + return err; +} + +static int bscstrm_enable_rx_isr (sdla_t* card) +{ + int err; + wan_mbox_t* mb = &card->wan_mbox; + + memset(mb,0,MBOX_HEADER_SZ); + mb->wan_data_len = 4; + mb->wan_command = SET_INTERRUPT_TRIGGERS; + mb->wan_bscstrm_port=card->wandev.comm_port; + + mb->wan_data[0]=0x01; + mb->wan_data[1]=0x00; + mb->wan_data[2]=0x00; + mb->wan_data[3]=card->wandev.irq; + + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != OK) + bscstrm_error(card,err,mb); + + return err; +} + + +/****** Firmware Error Handler **********************************************/ + +/*============================================================================ + * Firmware error handler. + * This routine is called whenever firmware command returns non-zero + * return code. + * + * Return zero if previous command has to be cancelled. + */ +static int bscstrm_error (sdla_t *card, int err, wan_mbox_t *mb) +{ + unsigned cmd = mb->wan_command; + + switch (err) { + + case CMD_TIMEOUT: + printk(KERN_INFO "%s: command 0x%02X timed out!\n", + card->devname, cmd); + break; + + default: + printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n", + card->devname, cmd, err); + } + + return 0; +} + +static void port_set_state (sdla_t *card, int state) +{ + netdevice_t *dev; + if (card->wandev.state != state) + { + switch (state) + { + case WAN_CONNECTED: + printk (KERN_INFO "%s: Link connected!\n", + card->devname); + break; + + case WAN_CONNECTING: + printk (KERN_INFO "%s: Link connecting...\n", + card->devname); + break; + + case WAN_DISCONNECTED: + printk (KERN_INFO "%s: Link disconnected!\n", + card->devname); + break; + } + + card->wandev.state = state; + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + if (dev && wan_netif_priv(dev)){ + bscstrm_private_area_t *bscstrm_priv_area = wan_netif_priv(dev); + bscstrm_priv_area->common.state = state; + wan_update_api_state(bscstrm_priv_area); + } + } +} + +/****** End ****************************************************************/ diff -Nur linux.org/drivers/net/wan/sdla_chdlc.c linux-2.6.17/drivers/net/wan/sdla_chdlc.c --- linux.org/drivers/net/wan/sdla_chdlc.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/drivers/net/wan/sdla_chdlc.c 2006-08-30 10:07:16.000000000 +0000 @@ -0,0 +1,5995 @@ +/***************************************************************************** +* sdla_chdlc.c WANPIPE(tm) Multiprotocol WAN Link Driver. Cisco HDLC module. +* +* Authors: Nenad Corbic +* Gideon Hack +* +* Copyright: (c) 1995-2004 Sangoma Technologies Inc. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version +* 2 of the License, or (at your option) any later version. +* ============================================================================ +* Jan 03, 2002 Nenad Corbic Memory leak bug fix under Bridge Mode. +* If not an ethernet frame skb buffer was +* not deallocated. +* Oct 18, 2002 Nenad Corbic Added BRIDGE support +* Jan 14, 2002 Nenad Corbic Removed the 2.0.X kernel support and added +* front end state handling. +* Dec 12, 2001 Nenad Corbic Re-wrote the tty receive algorithm, using +* task queues, because ISA cards cannot call +* receive_buf() from the rx interrupt. +* Dec 03, 2001 Gideon Hack Updated for S514-5 56K adapter. +* Sep 20, 2001 Nenad Corbic The min() function has changed for 2.4.9 +* kernel. Thus using the wp_min() defined in +* wanpipe.h +* Sept 6, 2001 Alex Feldman Add SNMP support. +* Aug 23, 2001 Nenad Corbic Removed the if_header and set the hard_header +* length to zero. Caused problems with Checkpoint +* firewall. +* May 13, 2001 Alex Feldman Added T1/E1 support (TE1). +* Feb 28, 2001 Nenad Corbic Updated if_tx_timeout() routine for +* 2.4.X kernels. +* Jan 25, 2001 Nenad Corbic Added a TTY Sync serial driver over the +* HDLC streaming protocol +* Added a TTY Async serial driver over the +* Async protocol. +* Dec 15, 2000 Nenad Corbic Updated for 2.4.X Kernel support +* Nov 13, 2000 Nenad Corbic Added true interface type encoding option. +* Tcpdump doesn't support CHDLC inteface +* types, to fix this "true type" option will set +* the interface type to RAW IP mode. +* Nov 07, 2000 Nenad Corbic Added security features for UDP debugging: +* Deny all and specify allowed requests. +* Jun 20, 2000 Nenad Corbic Fixed the API IP ERROR bug. Caused by the +* latest update. +* May 09, 2000 Nenad Corbic Option to bring down an interface +* upon disconnect. +* Mar 23, 2000 Nenad Corbic Improved task queue, bh handling. +* Mar 16, 2000 Nenad Corbic Fixed the SLARP Dynamic IP addressing. +* Mar 06, 2000 Nenad Corbic Bug Fix: corrupted mbox recovery. +* Feb 10, 2000 Gideon Hack Added ASYNC support. +* Feb 09, 2000 Nenad Corbic Fixed two shutdown bugs in update() and +* if_stats() functions. +* Jan 24, 2000 Nenad Corbic Fixed a startup wanpipe state racing, +* condition between if_open and isr. +* Jan 10, 2000 Nenad Corbic Added new socket API support. +* Dev 15, 1999 Nenad Corbic Fixed up header files for 2.0.X kernels +* Nov 20, 1999 Nenad Corbic Fixed zero length API bug. +* Sep 30, 1999 Nenad Corbic Fixed dynamic IP and route setup. +* Sep 23, 1999 Nenad Corbic Added SMP support, fixed tracing +* Sep 13, 1999 Nenad Corbic Split up Port 0 and 1 into separate devices. +* Jun 02, 1999 Gideon Hack Added support for the S514 adapter. +* Oct 30, 1998 Jaspreet Singh Added Support for CHDLC API (HDLC STREAMING). +* Oct 28, 1998 Jaspreet Singh Added Support for Dual Port CHDLC. +* Aug 07, 1998 David Fong Initial version. +*****************************************************************************/ + +#include +#include +#include /* WANPIPE common user API definitions */ +#include +#include +#include /* CHDLC firmware API definitions */ +#include /* CHDLC (async) API definitions */ +#include /* Socket Driver common area */ +#include +#include + +/****** Defines & Macros ****************************************************/ + +/* Private critical flags */ +enum { + POLL_CRIT = PRIV_CRIT, + TX_INTR, + TASK_POLL, + TTY_HANGUP +}; + + +/* reasons for enabling the timer interrupt on the adapter */ +#define TMR_INT_ENABLED_UDP 0x01 +#define TMR_INT_ENABLED_UPDATE 0x02 +#define TMR_INT_ENABLED_CONFIG 0x10 +#define TMR_INT_ENABLED_TE 0x20 + +#define MAX_IP_ERRORS 10 + +#define TTY_CHDLC_MAX_MTU 2000 +#define CHDLC_DFLT_DATA_LEN 1500 /* default MTU */ +#define CHDLC_HDR_LEN 1 + +#define CHDLC_API 0x01 + +#define PORT(x) (x == 0 ? "PRIMARY" : "SECONDARY" ) +#define MAX_BH_BUFF 10 + + +/******Data Structures*****************************************************/ + +/* This structure is placed in the private data area of the device structure. + * The card structure used to occupy the private area but now the following + * structure will incorporate the card structure along with CHDLC specific data + */ + +typedef struct chdlc_private_area +{ + wanpipe_common_t common; + sdla_t *card; + int TracingEnabled; /* For enabling Tracing */ + unsigned long curr_trace_addr; /* Used for Tracing */ + unsigned long start_trace_addr; + unsigned long end_trace_addr; + unsigned long base_addr_trace_buffer; + unsigned long end_addr_trace_buffer; + unsigned short number_trace_elements; + unsigned available_buffer_space; + unsigned long router_start_time; + unsigned char route_status; + unsigned char route_removed; + unsigned long tick_counter; /* For 5s timeout counter */ + unsigned long router_up_time; + u32 IP_address; /* IP addressing */ + u32 IP_netmask; + u32 ip_local; + u32 ip_remote; + u32 ip_local_tmp; + u32 ip_remote_tmp; + u8 ip_error; + unsigned long config_chdlc; + u8 config_chdlc_timeout; + unsigned char mc; /* Mulitcast support on/off */ + unsigned char udp_pkt_src; /* udp packet processing */ + unsigned short timer_int_enabled; + unsigned long update_comms_stats; /* updating comms stats */ + + unsigned long interface_down; + + /* Polling task queue. Each interface + * has its own task queue, which is used + * to defer events from the interrupt */ + struct tq_struct poll_task; + struct timer_list poll_delay_timer; + + u8 gateway; + u8 true_if_encoding; + //FIXME: add driver stats as per frame relay! + + /* Entry in proc fs per each interface */ + struct proc_dir_entry* dent; + + unsigned char udp_pkt_data[sizeof(wan_udp_pkt_t)+10]; + atomic_t udp_pkt_len; + + char if_name[WAN_IFNAME_SZ+1]; + + netdevice_t *annexg_dev; + unsigned char label[WAN_IF_LABEL_SZ+1]; + +} chdlc_private_area_t; + +/* Route Status options */ +#define NO_ROUTE 0x00 +#define ADD_ROUTE 0x01 +#define ROUTE_ADDED 0x02 +#define REMOVE_ROUTE 0x03 + + +/* variable for keeping track of enabling/disabling FT1 monitor status */ +static int rCount = 0; + +/* variable for tracking how many interfaces to open for WANPIPE on the + two ports */ + +extern void disable_irq(unsigned int); +extern void enable_irq(unsigned int); + + +/****** Function Prototypes *************************************************/ +/* WAN link driver entry points. These are called by the WAN router module. */ +static int update (wan_device_t* wandev); +static int new_if (wan_device_t* wandev, netdevice_t* dev, + wanif_conf_t* conf); +static int del_if(wan_device_t *wandev, netdevice_t *dev); + +/* Network device interface */ +static int if_init (netdevice_t* dev); +static int if_open (netdevice_t* dev); +static int if_close (netdevice_t* dev); +static int if_do_ioctl(netdevice_t *dev, struct ifreq *ifr, int cmd); + + +static struct net_device_stats* if_stats (netdevice_t* dev); + +static int if_send (struct sk_buff* skb, netdevice_t* dev); + +/* CHDLC Firmware interface functions */ +static int chdlc_configure (sdla_t* card, void* data); +static int chdlc_comm_enable (sdla_t* card); +static int chdlc_comm_disable (sdla_t* card); +static int chdlc_read_version (sdla_t* card, char* str, int str_size); +static int chdlc_set_intr_mode (sdla_t* card, unsigned mode); +static int set_adapter_config (sdla_t* card); +static int chdlc_send (sdla_t* card, void* data, unsigned len, unsigned char tx_bits); +static int chdlc_read_comm_err_stats (sdla_t* card); +static int chdlc_read_op_stats (sdla_t* card); +static int chdlc_error (sdla_t *card, int err, wan_mbox_t *mb); + + +static int chdlc_disable_comm_shutdown (sdla_t *card); +static void if_tx_timeout (netdevice_t *dev); + + +/* Miscellaneous CHDLC Functions */ +static int set_chdlc_config (sdla_t* card); +static void init_chdlc_tx_rx_buff( sdla_t* card); +static int process_chdlc_exception(sdla_t *card); +static int process_global_exception(sdla_t *card); +static int update_comms_stats(sdla_t* card, + chdlc_private_area_t* chdlc_priv_area); +static int configure_ip (sdla_t* card, netdevice_t *dev); +static int unconfigure_ip (sdla_t* card, netdevice_t *dev); +static void process_route(sdla_t *card); +static void port_set_state (sdla_t *card, int); +static int config_chdlc (sdla_t *card, netdevice_t *dev); +static void disable_comm (sdla_t *card); + +static void trigger_chdlc_poll (netdevice_t *); +static void chdlc_poll (void *); +static void chdlc_poll_delay (unsigned long dev_ptr); +static int chdlc_calibrate_baud (sdla_t *card); +static int chdlc_read_baud_calibration (sdla_t *card); + + + + +/* Miscellaneous asynchronous interface Functions */ +static int set_asy_config (sdla_t* card); +static int asy_comm_enable (sdla_t* card); + +/* Interrupt handlers */ +static void wpc_isr (sdla_t* card); +static void rx_intr (sdla_t* card); +static void timer_intr(sdla_t *); + +/* Bottom half handlers */ +static void chdlc_bh (unsigned long data); + +/* Miscellaneous functions */ +static int chk_bcast_mcast_addr(sdla_t* card, netdevice_t* dev, + struct sk_buff *skb); +static int reply_udp( unsigned char *data, unsigned int mbox_len ); +static int intr_test( sdla_t* card); +static int udp_pkt_type( struct sk_buff *skb , sdla_t* card); +static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, + struct sk_buff *skb, netdevice_t* dev, + chdlc_private_area_t* chdlc_priv_area); +static int process_udp_mgmt_pkt(sdla_t* card, netdevice_t* dev, + chdlc_private_area_t* chdlc_priv_area, + int local_dev); +static unsigned short calc_checksum (char *, int); +static void s508_lock (sdla_t *card, unsigned long *smp_flags); +static void s508_unlock (sdla_t *card, unsigned long *smp_flags); + +/* TTY Global Definitions */ + +#define NR_PORTS 4 +#define WAN_TTY_MAJOR 240 +#define WAN_TTY_MINOR 0 + +#define WAN_CARD(port) (tty_card_map[port]) +#define MIN_PORT 0 +#define MAX_PORT NR_PORTS-1 + +#define CRC_LENGTH 2 + +#define MAX_TTY_RX_BUF 30 + +#if 1 +//defined(LINUX_2_4) || defined(LINUX_2_1) +static int wanpipe_tty_init(sdla_t *card); +static void wanpipe_tty_receive(sdla_t *, unsigned, unsigned int); +static int wanpipe_tty_trigger_poll(sdla_t *card); + +static struct tty_driver serial_driver; +static int tty_init_cnt=0; + +static struct serial_state rs_table[NR_PORTS]; + +#ifndef LINUX_2_6 +static int serial_refcount=1; +static struct tty_struct *serial_table[NR_PORTS]; +static struct tty_driver callout_driver; +static struct termios *serial_termios[NR_PORTS]; +static struct termios *serial_termios_locked[NR_PORTS]; +#endif + +static char tty_driver_mode=WANOPT_TTY_SYNC; +#endif + +#if 1 +//defined(LINUX_2_4) || defined(LINUX_2_1) +static char *opt_decode[] = {"NONE","CRTSCTS","XONXOFF-RX", + "CRTSCTS XONXOFF-RX","XONXOFF-TX", + "CRTSCTS XONXOFF-TX","CRTSCTS XONXOFF"}; +static char *p_decode[] = {"NONE","ODD","EVEN"}; + +static void* tty_card_map[NR_PORTS] = {NULL,NULL,NULL,NULL}; +#endif + +static int chdlc_get_config_info(void* priv, struct seq_file* m, int*); +static int chdlc_get_status_info(void* priv, struct seq_file* m, int*); +static int chdlc_set_dev_config(struct file*, const char*, unsigned long, void *); +static int chdlc_set_if_info(struct file*, const char*, unsigned long, void *); + +/* TE1 */ +static WRITE_FRONT_END_REG_T write_front_end_reg; +static READ_FRONT_END_REG_T read_front_end_reg; +static void chdlc_enable_timer(void* card_id); +static void chdlc_handle_front_end_state(void* card_id); + +/* Debugging */ +static int chdlc_debugging(sdla_t* card); +static unsigned long chdlc_crc_frames(sdla_t* card); +static unsigned long chdlc_abort_frames(sdla_t * card); +static unsigned long chdlc_tx_underun_frames(sdla_t* card); + +/****** Public Functions ****************************************************/ + +/*============================================================================ + * wpc_init - Cisco HDLC protocol initialization routine. + * + * @card: Wanpipe card pointer + * @conf: User hardware/firmware/general protocol configuration + * pointer. + * + * This routine is called by the main WANPIPE module + * during setup: ROUTER_SETUP ioctl(). + * + * At this point adapter is completely initialized + * and firmware is running. + * o read firmware version (to make sure it's alive) + * o configure adapter + * o initialize protocol-specific fields of the adapter data space. + * + * Return: 0 o.k. + * < 0 failure. + */ +int wpc_init (sdla_t* card, wandev_conf_t* conf) +{ + unsigned char port_num; + int err; + unsigned long max_permitted_baud = 0; + + char str[80]; + volatile wan_mbox_t* mb; + wan_mbox_t* mb1; + unsigned long timeout; + + /* Verify configuration ID */ + if (conf->config_id != WANCONFIG_CHDLC) { + printk(KERN_INFO "%s: invalid configuration ID %u!\n", + card->devname, conf->config_id); + return -EINVAL; + } + /* Find out which Port to use */ + if ((conf->comm_port == WANOPT_PRI) || (conf->comm_port == WANOPT_SEC)){ + if (card->next){ + + if (conf->comm_port != card->next->u.c.comm_port){ + card->u.c.comm_port = conf->comm_port; + }else{ + printk(KERN_INFO "%s: ERROR - %s port used!\n", + card->wandev.name, PORT(conf->comm_port)); + return -EINVAL; + } + }else{ + card->u.c.comm_port = conf->comm_port; + } + }else{ + printk(KERN_INFO "%s: ERROR - Invalid Port Selected!\n", + card->wandev.name); + return -EINVAL; + } + + + /* Initialize protocol-specific fields */ + /* ALEX: Apr 8 2004 SANGOMA ISA CARD */ + /* for a PCI/ISA adapters, set a pointer to the actual mailbox in the */ + /* allocated virtual memory area */ + if (card->u.c.comm_port == WANOPT_PRI){ + card->mbox_off = PRI_BASE_ADDR_MB_STRUCT; + }else{ + card->mbox_off = SEC_BASE_ADDR_MB_STRUCT; + } + + mb = &card->wan_mbox; + mb1 = &card->wan_mbox; + + if (!card->configured){ + unsigned char return_code = 0x00; + /* The board will place an 'I' in the return code to indicate that it is + ready to accept commands. We expect this to be completed in less + than 1 second. */ + + timeout = jiffies; + do { + return_code = 0x00; + card->hw_iface.peek(card->hw, + card->mbox_off+offsetof(wan_mbox_t, wan_return_code), + &return_code, + sizeof(unsigned char)); + if ((jiffies - timeout) > 1*HZ) break; + }while(return_code != 'I'); + if (return_code != 'I') { + printk(KERN_INFO + "%s: Initialization not completed by adapter\n", + card->devname); + printk(KERN_INFO "Please contact Sangoma representative.\n"); + return -EIO; + } + } + + card->wandev.clocking = conf->clocking; + card->wandev.ignore_front_end_status = conf->ignore_front_end_status; + + card->wandev.line_idle = conf->line_idle; + card->wandev.line_coding = conf->line_coding; + card->wandev.connection = conf->connection; + + err = (card->hw_iface.check_mismatch) ? + card->hw_iface.check_mismatch(card->hw,conf->fe_cfg.media) : -EINVAL; + if (err){ + return err; + } + + /* TE1 Make special hardware initialization for T1/E1 board */ + if (IS_TE1_MEDIA(&conf->fe_cfg)){ + + memcpy(&card->fe.fe_cfg, &conf->fe_cfg, sizeof(sdla_fe_cfg_t)); + sdla_te_iface_init(&card->wandev.fe_iface); + card->fe.name = card->devname; + card->fe.card = card; + card->fe.write_fe_reg = write_front_end_reg; + card->fe.read_fe_reg = read_front_end_reg; + + card->wandev.fe_enable_timer = chdlc_enable_timer; + card->wandev.te_link_state = chdlc_handle_front_end_state; + conf->interface = + (IS_T1_CARD(card)) ? WANOPT_V35 : WANOPT_RS232; + + if (card->u.c.comm_port == WANOPT_PRI){ + conf->clocking = WANOPT_EXTERNAL; + } + + }else if (IS_56K_MEDIA(&conf->fe_cfg)){ + + memcpy(&card->fe.fe_cfg, &conf->fe_cfg, sizeof(sdla_fe_cfg_t)); + sdla_56k_iface_init(&card->wandev.fe_iface); + card->fe.name = card->devname; + card->fe.card = card; + card->fe.write_fe_reg = write_front_end_reg; + card->fe.read_fe_reg = read_front_end_reg; + + if (card->u.c.comm_port == WANOPT_PRI){ + conf->clocking = WANOPT_EXTERNAL; + } + + }else{ + card->fe.fe_status = FE_CONNECTED; + } + + if (card->wandev.ignore_front_end_status == WANOPT_NO){ + printk(KERN_INFO + "%s: Enabling front end link monitor\n", + card->devname); + }else{ + printk(KERN_INFO + "%s: Disabling front end link monitor\n", + card->devname); + } + + + /* Read firmware version. Note that when adapter initializes, it + * clears the mailbox, so it may appear that the first command was + * executed successfully when in fact it was merely erased. To work + * around this, we execute the first command twice. + */ + + if (chdlc_read_version(card, str, sizeof(str))) + return -EIO; + + printk(KERN_INFO "%s: Running Cisco HDLC firmware v%s\n", + card->devname, str); + + if (set_adapter_config(card)) { + return -EIO; + } + + card->isr = &wpc_isr; + card->poll = NULL; + card->exec = NULL; + card->wandev.update = &update; + card->wandev.new_if = &new_if; + card->wandev.del_if = &del_if; + + card->wandev.udp_port = conf->udp_port; + card->wandev.new_if_cnt = 0; + atomic_set(&card->wandev.if_cnt,0); + + // Proc fs functions + card->wandev.get_config_info = &chdlc_get_config_info; + card->wandev.get_status_info = &chdlc_get_status_info; + card->wandev.set_dev_config = &chdlc_set_dev_config; + card->wandev.set_if_info = &chdlc_set_if_info; + + // Debugging + card->wan_debugging = &chdlc_debugging; + card->get_crc_frames = &chdlc_crc_frames; + card->get_abort_frames = &chdlc_abort_frames; + card->get_tx_underun_frames = &chdlc_tx_underun_frames; + + /* reset the number of times the 'update()' proc has been called */ + card->u.c.update_call_count = 0; + + card->wandev.ttl = conf->ttl; + card->wandev.interface = conf->interface; + + if ((card->u.c.comm_port == WANOPT_SEC && conf->interface == WANOPT_V35)&& + card->type != SDLA_S514){ + printk(KERN_INFO "%s: ERROR - V35 Interface not supported on S508 %s port \n", + card->devname, PORT(card->u.c.comm_port)); + return -EIO; + } + + + port_num = card->u.c.comm_port; + + /* in API mode, we can configure for "receive only" buffering */ + if(card->type == SDLA_S514) { + card->u.c.receive_only = conf->receive_only; + if(conf->receive_only) { + printk(KERN_INFO + "%s: Configured for 'receive only' mode\n", + card->devname); + } + } + + /* Setup Port Bps */ + + if(card->wandev.clocking) { + if((port_num == WANOPT_PRI) || card->u.c.receive_only) { + /* For Primary Port 0 */ + max_permitted_baud = + (card->type == SDLA_S514) ? + PRI_MAX_BAUD_RATE_S514 : + PRI_MAX_BAUD_RATE_S508; + + }else if(port_num == WANOPT_SEC) { + /* For Secondary Port 1 */ + max_permitted_baud = + (card->type == SDLA_S514) ? + SEC_MAX_BAUD_RATE_S514 : + SEC_MAX_BAUD_RATE_S508; + } + + if(conf->bps > max_permitted_baud) { + conf->bps = max_permitted_baud; + printk(KERN_INFO "%s: Baud too high!\n", + card->wandev.name); + printk(KERN_INFO "%s: Baud rate set to %lu bps\n", + card->wandev.name, max_permitted_baud); + } + card->wandev.bps = conf->bps; + }else{ + card->wandev.bps = 0; + } + + /* Setup the Port MTU */ + if((port_num == WANOPT_PRI) || card->u.c.receive_only) { + /* For Primary Port 0 */ + card->wandev.mtu = + (conf->mtu >= MIN_LGTH_CHDLC_DATA_CFG) ? + wp_min(conf->mtu, PRI_MAX_NO_DATA_BYTES_IN_FRAME) : + CHDLC_DFLT_DATA_LEN; + } else if(port_num == WANOPT_SEC) { + /* For Secondary Port 1 */ + card->wandev.mtu = + (conf->mtu >= MIN_LGTH_CHDLC_DATA_CFG) ? + wp_min(conf->mtu, SEC_MAX_NO_DATA_BYTES_IN_FRAME) : + CHDLC_DFLT_DATA_LEN; + } + + + if (conf->u.chdlc.fast_isr == WANOPT_YES){ + DEBUG_EVENT("%s: Configuring Fast Interrupt Handlers\n", + card->devname); + card->u.c.protocol_options|=INSTALL_FAST_INT_HANDLERS; + } + + + /* Set up the interrupt status area */ + /* Read the CHDLC Configuration and obtain: + * Ptr to shared memory infor struct + * Use this pointer to calculate the value of card->u.c.flags ! + */ + mb1->wan_data_len = 0; + mb1->wan_command = READ_CHDLC_CONFIGURATION; + + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb1); + if(err != COMMAND_OK) { + + if(card->type != SDLA_S514) + enable_irq(card->wandev.irq); + + chdlc_error(card, err, mb1); + return -EIO; + } + + /* ALEX: Apr 8 2004 SANGOMA ISA CARD */ + card->flags_off = + ((CHDLC_CONFIGURATION_STRUCT *)mb1->wan_data)-> + ptr_shared_mem_info_struct; + + card->intr_type_off = + card->flags_off + + offsetof(SHARED_MEMORY_INFO_STRUCT, interrupt_info_struct) + + offsetof(INTERRUPT_INFORMATION_STRUCT, interrupt_type); + card->intr_perm_off = + card->flags_off + + offsetof(SHARED_MEMORY_INFO_STRUCT, interrupt_info_struct) + + offsetof(INTERRUPT_INFORMATION_STRUCT, interrupt_permission); + card->fe_status_off = + card->flags_off + + offsetof(SHARED_MEMORY_INFO_STRUCT, FT1_info_struct) + + offsetof(FT1_INFORMATION_STRUCT, parallel_port_A_input); + + /* This is for the ports link state */ + card->wandev.state = WAN_DUALPORT; + card->u.c.state = WAN_DISCONNECTED; + + + if (!card->wandev.piggyback){ + int err; + + /* Perform interrupt testing */ + err = intr_test(card); + + if(err || (card->timer_int_enabled < 1)) { + printk(KERN_INFO "%s: Interrupt test failed (%i)\n", + card->devname, card->timer_int_enabled); + printk(KERN_INFO "%s: Please choose another interrupt\n", + card->devname); + return -EIO; + } + printk(KERN_INFO "%s: Interrupt test passed (%i)\n", + card->devname, card->timer_int_enabled); + card->configured = 1; + } + + if ((card->tty_opt=conf->tty) == WANOPT_YES){ +#if 1 +//defined(LINUX_2_4) || defined(LINUX_2_1) + int err; + card->tty_minor = conf->tty_minor; + + /* On ASYNC connections internal clocking + * is mandatory */ + if ((card->u.c.async_mode = conf->tty_mode)){ + card->wandev.clocking = 1; + } + err=wanpipe_tty_init(card); + if (err){ + return err; + } +#else + printk (KERN_INFO "%s: Driver doesn support tty for 2.6.X kernel!\n", + card->devname); + return -EINVAL; +#endif + }else{ + + if (chdlc_set_intr_mode(card, APP_INT_ON_TIMER)){ + printk (KERN_INFO "%s: Failed to set interrupt triggers!\n", + card->devname); + return -EIO; + } + + /* Mask the Timer interrupt */ + card->hw_iface.clear_bit(card->hw, card->intr_perm_off, APP_INT_ON_TIMER); + } + + /* If we are using CHDLC in backup mode, this flag will + * indicate not to look for IP addresses in config_chdlc()*/ + card->u.c.backup = conf->backup; + card->disable_comm = &disable_comm; + + printk(KERN_INFO "\n"); + + return 0; +} + +/******* WAN Device Driver Entry Points *************************************/ + +/*============================================================================ + * update - Update wanpipe device status & statistics + * + * @wandev: Wanpipe device pointer + * + * This procedure is called when updating the PROC file system. + * It returns various communications statistics. + * + * cat /proc/net/wanrouter/wanpipe# (where #=1,2,3...) + * + * These statistics are accumulated from 3 + * different locations: + * 1) The 'if_stats' recorded for the device. + * 2) Communication error statistics on the adapter. + * 3) CHDLC operational statistics on the adapter. + * + * The board level statistics are read during a timer interrupt. + * Note that we read the error and operational statistics + * during consecitive timer ticks so as to minimize the time + * that we are inside the interrupt handler. + * + */ +static int update (wan_device_t* wandev) +{ + sdla_t* card = wandev->private; + netdevice_t *dev; + chdlc_private_area_t* chdlc_priv_area; + unsigned long smp_flags; +#if 0 + SHARED_MEMORY_INFO_STRUCT *flags; + unsigned long timeout; +#endif + + /* sanity checks */ + if((wandev == NULL) || (wandev->private == NULL)) + return -EFAULT; + + if(wandev->state == WAN_UNCONFIGURED) + return -ENODEV; + + /* more sanity checks */ + if(test_bit(PERI_CRIT, (void*)&card->wandev.critical)) + return -EAGAIN; + + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + if (dev == NULL) + return -ENODEV; + + if((chdlc_priv_area = wan_netif_priv(dev)) == NULL) + return -ENODEV; + +#if 0 + flags = card->u.c.flags; +#endif + + if(test_and_set_bit(0,&chdlc_priv_area->update_comms_stats)){ + return -EAGAIN; + } + + /* TE1 Change the update_comms_stats variable to 3, + * only for T1/E1 card, otherwise 2 for regular + * S514/S508 card. + * Each timer interrupt will update only one type + * of statistics. + */ + + +#if 0 + chdlc_priv_area->update_comms_stats = + (IS_TE1_CARD(card) || IS_56K_CARD(card)) ? 3 : 2; + flags->interrupt_info_struct.interrupt_permission |= APP_INT_ON_TIMER; + card->u.c.timer_int_enabled = TMR_INT_ENABLED_UPDATE; + + /* wait a maximum of 1 second for the statistics to be updated */ + timeout = jiffies; + for(;;) { + if(chdlc_priv_area->update_comms_stats == 0) + break; + if ((jiffies - timeout) > (1 * HZ)){ + chdlc_priv_area->update_comms_stats = 0; + card->u.c.timer_int_enabled &= + ~TMR_INT_ENABLED_UPDATE; + return -EAGAIN; + } + } +#else + spin_lock_irqsave(&card->wandev.lock, smp_flags); + update_comms_stats(card, chdlc_priv_area); + chdlc_priv_area->update_comms_stats=0; + spin_unlock_irqrestore(&card->wandev.lock, smp_flags); +#endif + return 0; +} + + +/*============================================================================ + * new_if - Create new logical channel. + * + * &wandev: Wanpipe device pointer + * &dev: Network device pointer + * &conf: User configuration options pointer + * + * This routine is called by the ROUTER_IFNEW ioctl, + * in wanmain.c. The ioctl passes us the user configuration + * options which we use to configure the driver and + * firmware. + * + * This functions main purpose is to allocate the + * private structure for CHDLC protocol and bind it + * to dev->priv pointer. + * + * Also the dev->init pointer should also be initialized + * to the if_init() function. + * + * Any allocation necessary for the private strucutre + * should be done here, as well as proc/ file initializetion + * for the network interface. + * + * o parse media- and hardware-specific configuration + * o make sure that a new channel can be created + * o allocate resources, if necessary + * o prepare network device structure for registaration. + * o add network interface to the /proc/net/wanrouter + * + * The opposite of this function is del_if() + * + * Return: 0 o.k. + * < 0 failure (channel will not be created) + */ +static int new_if (wan_device_t* wandev, netdevice_t* dev, wanif_conf_t* conf) +{ + sdla_t* card = wandev->private; + chdlc_private_area_t* chdlc_priv_area; + int err = 0; + + printk(KERN_INFO "%s: Configuring Interface: %s\n", + card->devname, conf->name); + + if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) { + printk(KERN_INFO "%s: Invalid interface name!\n", + card->devname); + return -EINVAL; + } + + /* allocate and initialize private data */ + chdlc_priv_area = kmalloc(sizeof(chdlc_private_area_t), GFP_KERNEL); + + if(chdlc_priv_area == NULL){ + WAN_MEM_ASSERT(card->devname); + return -ENOMEM; + } + + memset(chdlc_priv_area, 0, sizeof(chdlc_private_area_t)); + + chdlc_priv_area->card = card; + strcpy(chdlc_priv_area->if_name, conf->name); + + WAN_TASKLET_INIT((&chdlc_priv_area->common.bh_task),0,chdlc_bh,(unsigned long)chdlc_priv_area); + if (atomic_read(&card->wandev.if_cnt) > 0){ + err=-EEXIST; + goto new_if_error; + } + + chdlc_priv_area->TracingEnabled = 0; + chdlc_priv_area->route_status = NO_ROUTE; + chdlc_priv_area->route_removed = 0; + + card->u.c.async_mode = conf->async_mode; + + /* setup for asynchronous mode */ + if(conf->async_mode) { + printk(KERN_INFO "%s: Configuring for asynchronous mode\n", + wandev->name); + + if(card->u.c.comm_port == WANOPT_PRI) { + printk(KERN_INFO + "%s:Asynchronous mode on secondary port only\n", + wandev->name); + + err=-EINVAL; + goto new_if_error; + } + + if(strcmp(conf->usedby, "WANPIPE") == 0) { + printk(KERN_INFO "%s: Running in WANIPE Async Mode\n", + wandev->name); + chdlc_priv_area->common.usedby = WANPIPE; + }else{ + chdlc_priv_area->common.usedby = API; + wan_reg_api(chdlc_priv_area, dev, card->devname); + } + + if(!card->wandev.clocking) { + printk(KERN_INFO + "%s: Asynch. clocking must be 'Internal'\n", + wandev->name); + + err=-EINVAL; + goto new_if_error; + } + + if((card->wandev.bps < MIN_ASY_BAUD_RATE) || + (card->wandev.bps > MAX_ASY_BAUD_RATE)) { + printk(KERN_INFO "%s: Selected baud rate is invalid.\n", + wandev->name); + printk(KERN_INFO "Must be between %u and %u bps.\n", + MIN_ASY_BAUD_RATE, MAX_ASY_BAUD_RATE); + + err=-EINVAL; + goto new_if_error; + } + + card->u.c.api_options = 0; + if (conf->asy_data_trans == WANOPT_YES) { + card->u.c.api_options |= ASY_RX_DATA_TRANSPARENT; + } + + card->u.c.protocol_options = 0; + if (conf->rts_hs_for_receive == WANOPT_YES) { + card->u.c.protocol_options |= ASY_RTS_HS_FOR_RX; + } + if (conf->xon_xoff_hs_for_receive == WANOPT_YES) { + card->u.c.protocol_options |= ASY_XON_XOFF_HS_FOR_RX; + } + if (conf->xon_xoff_hs_for_transmit == WANOPT_YES) { + card->u.c.protocol_options |= ASY_XON_XOFF_HS_FOR_TX; + } + if (conf->dcd_hs_for_transmit == WANOPT_YES) { + card->u.c.protocol_options |= ASY_DCD_HS_FOR_TX; + } + if (conf->cts_hs_for_transmit == WANOPT_YES) { + card->u.c.protocol_options |= ASY_CTS_HS_FOR_TX; + } + + card->u.c.tx_bits_per_char = conf->tx_bits_per_char; + card->u.c.rx_bits_per_char = conf->rx_bits_per_char; + card->u.c.stop_bits = conf->stop_bits; + card->u.c.parity = conf->parity; + card->u.c.break_timer = conf->break_timer; + card->u.c.inter_char_timer = conf->inter_char_timer; + card->u.c.rx_complete_length = conf->rx_complete_length; + card->u.c.xon_char = conf->xon_char; + + } else { /* setup for synchronous mode */ + + if (conf->ignore_dcd == WANOPT_YES){ + card->u.c.protocol_options |= IGNORE_DCD_FOR_LINK_STAT; + } + if (conf->ignore_cts == WANOPT_YES){ + card->u.c.protocol_options |= IGNORE_CTS_FOR_LINK_STAT; + } + + if (conf->ignore_keepalive == WANOPT_YES) { + card->u.c.protocol_options |= + IGNORE_KPALV_FOR_LINK_STAT; + card->u.c.kpalv_tx = MIN_Tx_KPALV_TIMER; + card->u.c.kpalv_rx = MIN_Rx_KPALV_TIMER; + card->u.c.kpalv_err = MIN_KPALV_ERR_TOL; + + } else { /* Do not ignore keepalives */ + card->u.c.kpalv_tx = + ((conf->keepalive_tx_tmr - MIN_Tx_KPALV_TIMER) + >= 0) ? + wp_min(conf->keepalive_tx_tmr,MAX_Tx_KPALV_TIMER) : + DEFAULT_Tx_KPALV_TIMER; + + card->u.c.kpalv_rx = + ((conf->keepalive_rx_tmr - MIN_Rx_KPALV_TIMER) + >= 0) ? + wp_min(conf->keepalive_rx_tmr,MAX_Rx_KPALV_TIMER) : + DEFAULT_Rx_KPALV_TIMER; + + card->u.c.kpalv_err = + ((conf->keepalive_err_margin-MIN_KPALV_ERR_TOL) + >= 0) ? + wp_min(conf->keepalive_err_margin, + MAX_KPALV_ERR_TOL) : + DEFAULT_KPALV_ERR_TOL; + } + + /* Setup slarp timer to control delay between slarps */ + card->u.c.slarp_timer = + ((conf->slarp_timer - MIN_SLARP_REQ_TIMER) >= 0) ? + wp_min(conf->slarp_timer, MAX_SLARP_REQ_TIMER) : + DEFAULT_SLARP_REQ_TIMER; + + if (conf->hdlc_streaming == WANOPT_YES) { + printk(KERN_INFO "%s: Enabling HDLC STREAMING Mode\n", + wandev->name); + card->u.c.protocol_options |= HDLC_STREAMING_MODE; + } + + if ((chdlc_priv_area->true_if_encoding = conf->true_if_encoding) == WANOPT_YES){ + printk(KERN_INFO + "%s: Enabling, true interface type encoding.\n", + card->devname); + } + + /* Setup wanpipe as a router (WANPIPE) or as an API */ + if( strcmp(conf->usedby, "WANPIPE") == 0) { + + printk(KERN_INFO "%s: Running in WANPIPE mode!\n", + wandev->name); + chdlc_priv_area->common.usedby = WANPIPE; + + /* Option to bring down the interface when + * the link goes down */ + if (conf->if_down){ + set_bit(DYN_OPT_ON,&chdlc_priv_area->interface_down); + printk(KERN_INFO + "%s:%s: Dynamic interface configuration enabled\n", + card->devname,chdlc_priv_area->if_name); + } + + } else if( strcmp(conf->usedby, "API") == 0) { + chdlc_priv_area->common.usedby = API; + printk(KERN_INFO "%s:%s: Running in API mode !\n", + wandev->name,chdlc_priv_area->if_name); + wan_reg_api(chdlc_priv_area, dev, card->devname); + + }else if (strcmp(conf->usedby, "BRIDGE") == 0) { + chdlc_priv_area->common.usedby = BRIDGE; + printk(KERN_INFO "%s:%s: Running in WANPIPE (BRIDGE) mode.\n", + card->devname,chdlc_priv_area->if_name); + + }else if (strcmp(conf->usedby, "BRIDGE_N") == 0) { + chdlc_priv_area->common.usedby = BRIDGE_NODE; + printk(KERN_INFO "%s:%s: Running in WANPIPE (BRIDGE_NODE) mode.\n", + card->devname,chdlc_priv_area->if_name); + + }else{ + printk(KERN_INFO "%s:%s: Error: Invalid operation mode [WANPIPE|API|BRIDGE|BRIDGE_N]\n", + card->devname,chdlc_priv_area->if_name); + err=-EINVAL; + goto new_if_error; + } + } + + /* Tells us that if this interface is a + * gateway or not */ + if ((chdlc_priv_area->gateway = conf->gateway) == WANOPT_YES){ + printk(KERN_INFO "%s: Interface %s is set as a gateway.\n", + card->devname,chdlc_priv_area->if_name); + } + + /* Get Multicast Information */ + chdlc_priv_area->mc = conf->mc; + + /* prepare network device data space for registration */ + /* Initialize the polling task routine */ + + INIT_WORK((&chdlc_priv_area->poll_task),chdlc_poll,dev); + + /* Initialize the polling delay timer */ + init_timer(&chdlc_priv_area->poll_delay_timer); + chdlc_priv_area->poll_delay_timer.data = (unsigned long)dev; + chdlc_priv_area->poll_delay_timer.function = chdlc_poll_delay; + + /* + * Create interface file in proc fs. + * Once the proc file system is created, the new_if() function + * should exit successfuly. + * + * DO NOT place code under this function that can return + * anything else but 0. + */ + err = wanrouter_proc_add_interface(wandev, + &chdlc_priv_area->dent, + chdlc_priv_area->if_name, + dev); + if (err){ + printk(KERN_INFO + "%s: can't create /proc/net/router/fr/%s entry!\n", + card->devname, chdlc_priv_area->if_name); + goto new_if_error; + } + + /* Only setup the dev pointer once the new_if function has + * finished successfully. DO NOT place any code below that + * can return an error */ + + dev->init = &if_init; + dev->priv = chdlc_priv_area; + + set_bit(0,&chdlc_priv_area->config_chdlc); + + atomic_inc(&card->wandev.if_cnt); + + printk(KERN_INFO "\n"); + + return 0; + +new_if_error: + + WAN_TASKLET_KILL(&chdlc_priv_area->common.bh_task); + wan_unreg_api(chdlc_priv_area, card->devname); + + kfree(chdlc_priv_area); + + dev->priv=NULL; + + return err; +} + +/*============================================================================ + * del_if - Delete logical channel. + * + * @wandev: Wanpipe private device pointer + * @dev: Netowrk interface pointer + * + * This function is called by ROUTER_DELIF ioctl call + * to deallocate the network interface. + * + * The network interface and the private structure are + * about to be deallocated by the upper layer. + * We have to clean and deallocate any allocated memory. + * + */ +static int del_if (wan_device_t* wandev, netdevice_t* dev) +{ + chdlc_private_area_t* chdlc_priv_area = dev->priv; + sdla_t* card = chdlc_priv_area->card; + + WAN_TASKLET_KILL(&chdlc_priv_area->common.bh_task); + wan_unreg_api(chdlc_priv_area, card->devname); + + /* Delete interface name from proc fs. */ + wanrouter_proc_delete_interface(wandev, chdlc_priv_area->if_name); + + atomic_dec(&card->wandev.if_cnt); + return 0; +} + +/****** Network Device Interface ********************************************/ + +/*============================================================================ + * if_init - Initialize Linux network interface. + * + * @dev: Network interface pointer + * + * During "ifconfig up" the upper layer calls this function + * to initialize dev access pointers. Such as transmit, + * stats and header. + * + * It is called only once for each interface, + * during Linux network interface registration. + * + * Returning anything but zero will fail interface + * registration. + */ +static int if_init (netdevice_t* dev) +{ + chdlc_private_area_t* chdlc_priv_area = dev->priv; + sdla_t* card = chdlc_priv_area->card; + wan_device_t* wandev = &card->wandev; + + /* Initialize device driver entry points */ + dev->open = &if_open; + dev->stop = &if_close; + dev->hard_header = NULL; + dev->rebuild_header = NULL; + dev->hard_start_xmit = &if_send; + dev->get_stats = &if_stats; +#if defined(LINUX_2_4)||defined(LINUX_2_6) + dev->tx_timeout = &if_tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; +#endif + dev->do_ioctl = if_do_ioctl; + + if (chdlc_priv_area->common.usedby == BRIDGE || + chdlc_priv_area->common.usedby == BRIDGE_NODE){ + + /* Setup the interface for Bridging */ + int hw_addr=0; + ether_setup(dev); + + /* Use a random number to generate the MAC address */ + memcpy(dev->dev_addr, "\xFE\xFC\x00\x00\x00\x00", 6); + get_random_bytes(&hw_addr, sizeof(hw_addr)); + *(int *)(dev->dev_addr + 2) += hw_addr; + + }else{ + /* Initialize media-specific parameters */ + dev->flags |= IFF_POINTOPOINT; + dev->flags |= IFF_NOARP; + + /* Enable Mulitcasting if user selected */ + if (chdlc_priv_area->mc == WANOPT_YES){ + dev->flags |= (IFF_MULTICAST|IFF_ALLMULTI); + } + + if (chdlc_priv_area->true_if_encoding){ + dev->type = ARPHRD_HDLC; /* This breaks the tcpdump */ + }else{ + dev->type = ARPHRD_PPP; + } + + dev->mtu = card->wandev.mtu; + /* for API usage, add the API header size to the requested MTU size */ + if(chdlc_priv_area->common.usedby == API) { + dev->mtu += sizeof(api_tx_hdr_t); + } + + dev->hard_header_len = 0; + } + + /* Initialize hardware parameters */ + dev->irq = wandev->irq; + dev->dma = wandev->dma; + dev->base_addr = wandev->ioport; + card->hw_iface.getcfg(card->hw, SDLA_MEMBASE, &dev->mem_start); + card->hw_iface.getcfg(card->hw, SDLA_MEMEND, &dev->mem_end); + + /* Set transmit buffer queue length + * If too low packets will not be retransmitted + * by stack. + */ + dev->tx_queue_len = 100; + + return 0; +} + +/*============================================================================ + * if_open - Open network interface. + * + * @dev: Network device pointer + * + * On ifconfig up, this function gets called in order + * to initialize and configure the private area. + * Driver should be configured to send and receive data. + * + * This functions starts a timer that will call + * chdlc_config() function. This function must be called + * because the IP addresses could have been changed + * for this interface. + * + * Return 0 if O.k. or errno. + */ +static int if_open (netdevice_t* dev) +{ + chdlc_private_area_t* chdlc_priv_area = dev->priv; + sdla_t* card = chdlc_priv_area->card; + struct timeval tv; + int err = 0; + + /* Only one open per interface is allowed */ + if (open_dev_check(dev)) + return -EBUSY; + + do_gettimeofday(&tv); + chdlc_priv_area->router_start_time = tv.tv_sec; + + netif_start_queue(dev); + + /* Increment the module usage count */ + wanpipe_open(card); + + /* TTY is configured during wanpipe_set_termios + * call, not here */ + if (card->tty_opt) + return err; + + /* Each time we bring the interface up we must + * run chdlc_config() because the ip addresses might + * have changed and we must report those to + * firmware. Thus, we delay the config until the + * interface starts up and all ip information has + * been setup */ + + set_bit(0,&chdlc_priv_area->config_chdlc); + chdlc_priv_area->config_chdlc_timeout=jiffies; + del_timer(&chdlc_priv_area->poll_delay_timer); + + /* Start the CHDLC configuration after 1sec delay. + * This will give the interface initilization time + * to finish its configuration */ + chdlc_priv_area->poll_delay_timer.expires=jiffies+HZ; + add_timer(&chdlc_priv_area->poll_delay_timer); + return err; +} + +/*============================================================================ + * if_close - Close network interface. + * + * @dev: Network device pointer + * + * On ifconfig down, this function gets called in order + * to cleanup interace private area. + * + * IMPORTANT: + * + * No deallocation or unconfiguration should ever occur in this + * function, because the interface can come back up + * (via ifconfig up). + * + * Furthermore, in dynamic interfacace configuration mode, the + * interface will come up and down to reflect the protocol state. + * + * Any private deallocation and cleanup can occur in del_if() + * function. That function is called before the dev interface + * itself is deallocated. + * + * Thus, we should only stop the net queue and decrement + * the wanpipe usage counter via wanpipe_close() function. + */ + +static int if_close (netdevice_t* dev) +{ + chdlc_private_area_t* chdlc_priv_area = dev->priv; + sdla_t* card = chdlc_priv_area->card; + + stop_net_queue(dev); + +#if defined(LINUX_2_1) + dev->start=0; +#endif + wanpipe_close(card); + del_timer(&chdlc_priv_area->poll_delay_timer); + + if (chdlc_priv_area->common.usedby == API){ + unsigned long smp_flags; + spin_lock_irqsave(&card->wandev.lock,smp_flags); + wan_unbind_api_from_svc(chdlc_priv_area, + chdlc_priv_area->common.sk); + spin_unlock_irqrestore(&card->wandev.lock,smp_flags); + } + + return 0; +} + + +/*============================================================= + * disable_comm - Main shutdown function + * + * @card: Wanpipe device pointer + * + * The command 'wanrouter stop' has been called + * and the whole wanpipe device is going down. + * This is the last function called to disable + * all comunications and deallocate any memory + * that is still allocated. + * + * o Disable communications, turn off interrupts + * o Deallocate memory used + * o Unconfigure TE1 card + */ + +static void disable_comm (sdla_t *card) +{ + unsigned long smp_flags; + struct serial_state * state; + + wan_spin_lock_irq(&card->wandev.lock,&smp_flags); + if (card->u.c.comm_enabled){ + chdlc_disable_comm_shutdown (card); + }else{ + card->hw_iface.poke_byte(card->hw, card->intr_perm_off, 0x00); + } + wan_spin_unlock_irq(&card->wandev.lock,&smp_flags); + + /* TE1 - Unconfiging, only on shutdown */ + if (IS_TE1_CARD(card)) { + if (card->wandev.fe_iface.unconfig){ + card->wandev.fe_iface.unconfig(&card->fe); + } + } + +#if 1 +//defined(LINUX_2_4) || defined(LINUX_2_1) + if (card->tty_opt){ + + if (!tty_init_cnt){ + return; + } + + if (!(--tty_init_cnt)){ + int e1; +#ifndef LINUX_2_6 + *serial_driver.refcount=0; +#endif + if ((e1 = tty_unregister_driver(&serial_driver))) + printk(KERN_INFO "SERIAL: failed to unregister serial driver (%d)\n", + e1); +#ifndef LINUX_2_6 + if ((e1 = tty_unregister_driver(&callout_driver))) + printk(KERN_INFO "SERIAL: failed to unregister callout driver (%d)\n", + e1); +#endif + printk(KERN_INFO "%s: Unregistering TTY Driver, Major %i\n", + card->devname,WAN_TTY_MAJOR); + + } + wan_spin_lock_irq(&card->wandev.lock,&smp_flags); + card->tty=NULL; + tty_card_map[card->tty_minor]=NULL; + state = &rs_table[card->tty_minor]; + memset(state,0,sizeof(*state)); + wan_spin_unlock_irq(&card->wandev.lock,&smp_flags); + } +#endif + return; +} + + + +/*============================================================================ + * Handle transmit timeout event from netif watchdog + */ +static void if_tx_timeout (netdevice_t *dev) +{ + chdlc_private_area_t* chan = dev->priv; + sdla_t *card = chan->card; + + /* If our device stays busy for at least 5 seconds then we will + * kick start the device by making dev->tbusy = 0. We expect + * that our device never stays busy more than 5 seconds. So this + * is only used as a last resort. + */ + + ++card->wandev.stats.collisions; + + printk (KERN_INFO "%s: Transmit timed out on %s\n", card->devname,dev->name); + netif_wake_queue (dev); +} + + +/*============================================================================ + * if_send - Send a packet on a network interface. + * + * @dev: Network interface pointer + * @skb: Packet obtained from the stack or API + * that should be sent out the port. + * + * o set tbusy flag (marks start of the transmission) to + * block a timer-based transmit from overlapping. + * o check link state. If link is not up, then drop the packet. + * o execute adapter send command. + * o free socket buffer if the send is successful, otherwise + * return non zero value and push the packet back into + * the stack. Also set the tx interrupt to wake up the + * stack when the firmware is able to send. + * + * Return: 0 complete (socket buffer must be freed) + * non-0 packet may be re-transmitted (tbusy must be set) + * + * Notes: + * 1. This routine is called either by the protocol stack or by the "net + * bottom half" (with interrupts enabled). + * 2. Setting tbusy flag will inhibit further transmit requests from the + * protocol stack and can be used for flow control with protocol layer. + */ +static int if_send (struct sk_buff* skb, netdevice_t* dev) +{ + chdlc_private_area_t *chdlc_priv_area = dev->priv; + sdla_t *card = chdlc_priv_area->card; + int udp_type = 0; + unsigned long smp_flags; + int err=0; + unsigned char misc_Tx_bits = 0; + +#if defined(LINUX_2_4)||defined(LINUX_2_6) + netif_stop_queue(dev); +#endif + + if (skb == NULL){ + /* If we get here, some higher layer thinks we've missed an + * tx-done interrupt. + */ + printk(KERN_INFO "%s: interface %s got kicked!\n", + card->devname, dev->name); + + wake_net_dev(dev); + return 0; + } + +#if defined(LINUX_2_1) + if (dev->tbusy){ + ++card->wandev.stats.collisions; + if((jiffies - chdlc_priv_area->tick_counter) < (5 * HZ)) { + return 1; + } + + if_tx_timeout (dev); + } +#endif + + if (chdlc_priv_area->common.usedby != ANNEXG && + skb->protocol != htons(PVC_PROT)){ + + /* check the udp packet type */ + + udp_type = udp_pkt_type(skb, card); + + if (udp_type == UDP_CPIPE_TYPE){ + if(store_udp_mgmt_pkt(UDP_PKT_FRM_STACK, card, skb, dev, + chdlc_priv_area)){ + card->hw_iface.set_bit(card->hw, card->intr_perm_off, APP_INT_ON_TIMER); + } + start_net_queue(dev); + return 0; + } + + /* check to see if the source IP address is a broadcast or */ + /* multicast IP address */ + if(chdlc_priv_area->common.usedby == WANPIPE && chk_bcast_mcast_addr(card, dev, skb)){ + ++card->wandev.stats.tx_dropped; + wan_skb_free(skb); + start_net_queue(dev); + return 0; + } + } + + /* Lock the 508 Card: SMP is supported */ + if(card->type != SDLA_S514){ + s508_lock(card,&smp_flags); + } + + if(test_and_set_bit(SEND_CRIT, (void*)&card->wandev.critical)) { + + printk(KERN_INFO "%s: Critical in if_send: %lx\n", + card->wandev.name,card->wandev.critical); + ++card->wandev.stats.tx_dropped; + goto if_send_exit_crit; + } + + if(card->wandev.state != WAN_CONNECTED){ + ++card->wandev.stats.tx_dropped; + + }else if(!skb->protocol){ + ++card->wandev.stats.tx_errors; + + }else { + void* data = skb->data; + unsigned len = skb->len; + unsigned char attr; + + /* If it's an API packet pull off the API + * header. Also check that the packet size + * is larger than the API header + */ + if (chdlc_priv_area->common.usedby == API){ + api_tx_hdr_t* api_tx_hdr; + + /* discard the frame if we are configured for */ + /* 'receive only' mode or if there is no data */ + if (card->u.c.receive_only || + (len <= sizeof(api_tx_hdr_t))) { + + ++card->wandev.stats.tx_dropped; + goto if_send_exit_crit; + } + + api_tx_hdr = (api_tx_hdr_t *)data; + attr = api_tx_hdr->attr; + misc_Tx_bits = api_tx_hdr->misc_Tx_bits; + data += sizeof(api_tx_hdr_t); + len -= sizeof(api_tx_hdr_t); + } + + err=chdlc_send(card, data, len, misc_Tx_bits); + + if(err) { + err=-1; + }else{ + ++card->wandev.stats.tx_packets; + card->wandev.stats.tx_bytes += len; +#if defined(LINUX_2_4)||defined(LINUX_2_6) + dev->trans_start = jiffies; +#endif + } + } + +if_send_exit_crit: + + if (err==0){ + wan_skb_free(skb); + start_net_queue(dev); + }else{ + stop_net_queue(dev); + chdlc_priv_area->tick_counter = jiffies; + card->hw_iface.set_bit(card->hw, card->intr_perm_off, APP_INT_ON_TX_FRAME); + } + + clear_bit(SEND_CRIT, (void*)&card->wandev.critical); + if(card->type != SDLA_S514){ + s508_unlock(card,&smp_flags); + } + + return err; +} + + +/*============================================================================ + * chk_bcast_mcast_addr - Check for source broadcast addresses + * + * Check to see if the packet to be transmitted contains a broadcast or + * multicast source IP address. + */ + +static int chk_bcast_mcast_addr(sdla_t *card, netdevice_t* dev, + struct sk_buff *skb) +{ + u32 src_ip_addr; + u32 broadcast_ip_addr = 0; + chdlc_private_area_t *chdlc_priv_area=dev->priv; + struct in_device *in_dev; + /* read the IP source address from the outgoing packet */ + src_ip_addr = *(u32 *)(skb->data + 12); + + if (chdlc_priv_area->common.usedby != WANPIPE){ + return 0; + } + + /* read the IP broadcast address for the device */ + in_dev = dev->ip_ptr; + if(in_dev != NULL) { + struct in_ifaddr *ifa= in_dev->ifa_list; + if(ifa != NULL) + broadcast_ip_addr = ifa->ifa_broadcast; + else + return 0; + } + + /* check if the IP Source Address is a Broadcast address */ + if((dev->flags & IFF_BROADCAST) && (src_ip_addr == broadcast_ip_addr)) { + printk(KERN_INFO "%s: Broadcast Source Address silently discarded\n", + card->devname); + return 1; + } + + /* check if the IP Source Address is a Multicast address */ + if((ntohl(src_ip_addr) >= 0xE0000001) && + (ntohl(src_ip_addr) <= 0xFFFFFFFE)) { + printk(KERN_INFO "%s: Multicast Source Address silently discarded\n", + card->devname); + return 1; + } + + return 0; +} + + +/*============================================================================ + * Reply to UDP Management system. + * Return length of reply. + */ +static int reply_udp( unsigned char *data, unsigned int mbox_len ) +{ + + unsigned short len, udp_length, temp, ip_length; + unsigned long ip_temp; + int even_bound = 0; + wan_udp_pkt_t *c_udp_pkt = (wan_udp_pkt_t *)data; + + /* Set length of packet */ + len = sizeof(struct iphdr)+ + sizeof(struct udphdr)+ + sizeof(wan_mgmt_t)+ + sizeof(wan_cmd_t)+ + sizeof(wan_trace_info_t)+ + mbox_len; + + /* fill in UDP reply */ + c_udp_pkt->wan_udp_request_reply = UDPMGMT_REPLY; + + /* fill in UDP length */ + udp_length = sizeof(struct udphdr)+ + sizeof(wan_mgmt_t)+ + sizeof(wan_cmd_t)+ + sizeof(wan_trace_info_t)+ + mbox_len; + + /* put it on an even boundary */ + if ( udp_length & 0x0001 ) { + udp_length += 1; + len += 1; + even_bound = 1; + } + + temp = (udp_length<<8)|(udp_length>>8); + c_udp_pkt->wan_udp_len = temp; + + /* swap UDP ports */ + temp = c_udp_pkt->wan_udp_sport; + c_udp_pkt->wan_udp_sport = + c_udp_pkt->wan_udp_dport; + c_udp_pkt->wan_udp_dport = temp; + + /* add UDP pseudo header */ + temp = 0x1100; + *((unsigned short *)(c_udp_pkt->wan_udp_data+mbox_len+even_bound)) = temp; + temp = (udp_length<<8)|(udp_length>>8); + *((unsigned short *)(c_udp_pkt->wan_udp_data+mbox_len+even_bound+2)) = temp; + + + /* calculate UDP checksum */ + c_udp_pkt->wan_udp_sum = 0; + c_udp_pkt->wan_udp_sum = calc_checksum(&data[UDP_OFFSET],udp_length+UDP_OFFSET); + + /* fill in IP length */ + ip_length = len; + temp = (ip_length<<8)|(ip_length>>8); + c_udp_pkt->wan_ip_len = temp; + + /* swap IP addresses */ + ip_temp = c_udp_pkt->wan_ip_src; + c_udp_pkt->wan_ip_src = c_udp_pkt->wan_ip_dst; + c_udp_pkt->wan_ip_dst = ip_temp; + + /* fill in IP checksum */ + c_udp_pkt->wan_ip_sum = 0; + c_udp_pkt->wan_ip_sum = calc_checksum(data,sizeof(struct iphdr)); + + return len; + +} /* reply_udp */ + +unsigned short calc_checksum (char *data, int len) +{ + unsigned short temp; + unsigned long sum=0; + int i; + + for( i = 0; i > 16 ) { + sum = (sum & 0xffffUL) + (sum >> 16); + } + + temp = (unsigned short)sum; + temp = ~temp; + + if( temp == 0 ) + temp = 0xffff; + + return temp; +} + + +/*============================================================================ + * Get ethernet-style interface statistics. + * Return a pointer to struct enet_statistics. + */ +static struct net_device_stats* if_stats (netdevice_t* dev) +{ + sdla_t *my_card; + chdlc_private_area_t* chdlc_priv_area; + + if ((chdlc_priv_area=dev->priv) == NULL) + return NULL; + + my_card = chdlc_priv_area->card; + return &my_card->wandev.stats; +} + +/****** Cisco HDLC Firmware Interface Functions *******************************/ + +/*============================================================================ + * Read firmware code version. + * Put code version as ASCII string in str. + */ +static int chdlc_read_version (sdla_t* card, char* str, int str_size) +{ + wan_mbox_t* mb = &card->wan_mbox; + int len; + char err; + + mb->wan_data_len = 0; + mb->wan_command = READ_CHDLC_CODE_VERSION; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + + if(err != COMMAND_OK) { + chdlc_error(card,err,mb); + }else if (str) { /* is not null */ + len = mb->wan_data_len; + if (len < str_size){ + memcpy(str, mb->wan_data, len); + str[len] = '\0'; + }else{ + DEBUG_EVENT("%s: Error: Version Length greater than max %i>%i!\n", + card->devname,len,str_size); + } + } + return (err); +} + +/*----------------------------------------------------------------------------- + * Configure CHDLC firmware. + */ +static int chdlc_configure (sdla_t* card, void* data) +{ + int err; + wan_mbox_t *mb = &card->wan_mbox; + int data_length = sizeof(CHDLC_CONFIGURATION_STRUCT); + + mb->wan_data_len = data_length; + memcpy(mb->wan_data, data, data_length); + mb->wan_command = SET_CHDLC_CONFIGURATION; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + + if (err != COMMAND_OK) chdlc_error (card, err, mb); + + return err; +} + + +/*============================================================================ + * Set interrupt mode -- HDLC Version. + */ + +static int chdlc_set_intr_mode (sdla_t* card, unsigned mode) +{ + wan_mbox_t* mb = &card->wan_mbox; + CHDLC_INT_TRIGGERS_STRUCT* int_data = + (CHDLC_INT_TRIGGERS_STRUCT *)mb->wan_data; + int err; + + int_data->CHDLC_interrupt_triggers = mode; + int_data->IRQ = card->wandev.irq; + int_data->interrupt_timer = 1; + + mb->wan_data_len = sizeof(CHDLC_INT_TRIGGERS_STRUCT); + mb->wan_command = SET_CHDLC_INTERRUPT_TRIGGERS; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != COMMAND_OK) + chdlc_error (card, err, mb); + return err; +} + + +/*=========================================================== + * chdlc_disable_comm_shutdown + * + * Shutdown() disables the communications. We must + * have a sparate functions, because we must not + * call chdlc_error() hander since the private + * area has already been replaced */ + +static int chdlc_disable_comm_shutdown (sdla_t *card) +{ + wan_mbox_t* mb = &card->wan_mbox; + int err; + + CHDLC_INT_TRIGGERS_STRUCT* int_data = + (CHDLC_INT_TRIGGERS_STRUCT *)mb->wan_data; + + /* Disable Interrutps */ + int_data->CHDLC_interrupt_triggers = 0; + int_data->IRQ = card->wandev.irq; + int_data->interrupt_timer = 1; + + mb->wan_data_len = sizeof(CHDLC_INT_TRIGGERS_STRUCT); + mb->wan_command = SET_CHDLC_INTERRUPT_TRIGGERS; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + + /* Disable Communications */ + if (card->u.c.async_mode) { + mb->wan_command = DISABLE_ASY_COMMUNICATIONS; + }else{ + mb->wan_command = DISABLE_CHDLC_COMMUNICATIONS; + } + + mb->wan_data_len = 0; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + + card->u.c.comm_enabled = 0; + + /* TE1 - Unconfiging, only on shutdown */ + if (IS_TE1_CARD(card)) { + if (card->wandev.fe_iface.unconfig){ + card->wandev.fe_iface.unconfig(&card->fe); + } + } + + return 0; +} + +/*============================================================================ + * Enable communications. + */ + +static int chdlc_comm_enable (sdla_t* card) +{ + int err; + wan_mbox_t* mb = &card->wan_mbox; + + mb->wan_data_len = 0; + mb->wan_command = ENABLE_CHDLC_COMMUNICATIONS; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != COMMAND_OK) + chdlc_error(card, err, mb); + else + card->u.c.comm_enabled = 1; + + return err; +} + +/*============================================================================ + * Enable communications. + */ + +static int chdlc_comm_disable (sdla_t* card) +{ + int err; + wan_mbox_t* mb = &card->wan_mbox; + + mb->wan_data_len = 0; + mb->wan_command = DISABLE_CHDLC_COMMUNICATIONS; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != COMMAND_OK) + chdlc_error(card, err, mb); + else + card->u.c.comm_enabled = 0; + + return err; +} + + +/*============================================================================ + * Read communication error statistics. + */ +static int chdlc_read_comm_err_stats (sdla_t* card) +{ + int err; + wan_mbox_t* mb = &card->wan_mbox; + + mb->wan_data_len = 0; + mb->wan_command = READ_COMMS_ERROR_STATS; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != COMMAND_OK) + chdlc_error(card,err,mb); + return err; +} + + +/*============================================================================ + * Read CHDLC operational statistics. + */ +static int chdlc_read_op_stats (sdla_t* card) +{ + int err; + wan_mbox_t* mb = &card->wan_mbox; + + mb->wan_data_len = 0; + mb->wan_command = READ_CHDLC_OPERATIONAL_STATS; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != COMMAND_OK) + chdlc_error(card,err,mb); + return err; +} + + +/*============================================================================ + * Update communications error and general packet statistics. + */ +static int update_comms_stats(sdla_t* card, + chdlc_private_area_t* chdlc_priv_area) +{ + wan_mbox_t* mb = &card->wan_mbox; + COMMS_ERROR_STATS_STRUCT* err_stats; + CHDLC_OPERATIONAL_STATS_STRUCT *op_stats; + + /* 1. On the first timer interrupt, update T1/E1 alarms + * and PMON counters (only for T1/E1 card) (TE1) + */ + /* TE1 Update T1/E1 alarms */ + if (IS_TE1_CARD(card)) { + card->wandev.fe_iface.read_alarm(&card->fe, 0); + /* TE1 Update T1/E1 perfomance counters */ + card->wandev.fe_iface.read_pmon(&card->fe, 0); + }else if (IS_56K_CARD(card)) { + /* 56K Update CSU/DSU alarms */ + card->wandev.fe_iface.read_alarm(&card->fe, 1); + } + + if(chdlc_read_comm_err_stats(card)) + return 1; + + err_stats = (COMMS_ERROR_STATS_STRUCT *)mb->wan_data; + card->wandev.stats.rx_over_errors = + err_stats->Rx_overrun_err_count; + card->wandev.stats.rx_crc_errors = + err_stats->CRC_err_count; + card->wandev.stats.rx_frame_errors = + err_stats->Rx_abort_count; + card->wandev.stats.rx_fifo_errors = + err_stats->Rx_dis_pri_bfrs_full_count; + card->wandev.stats.rx_missed_errors = + card->wandev.stats.rx_fifo_errors; + card->wandev.stats.tx_aborted_errors = + err_stats->sec_Tx_abort_count; + + /* on the third timer interrupt, read the operational + * statistics + */ + if(chdlc_read_op_stats(card)) + return 1; + + op_stats = (CHDLC_OPERATIONAL_STATS_STRUCT *)mb->wan_data; + card->wandev.stats.rx_length_errors = + (op_stats->Rx_Data_discard_short_count + + op_stats->Rx_Data_discard_long_count); + + return 0; +} + +/*============================================================================ + * Send packet. + * Return: 0 - o.k. + * 1 - no transmit buffers available + */ +static int chdlc_send (sdla_t* card, void* data, unsigned len, unsigned char tx_bits) +{ + CHDLC_DATA_TX_STATUS_EL_STRUCT txbuf; + + card->hw_iface.peek(card->hw, card->u.c.txbuf_off, &txbuf, sizeof(txbuf)); + if (txbuf.opp_flag){ + return 1; + } + + card->hw_iface.poke(card->hw, txbuf.ptr_data_bfr, data, len); + + txbuf.frame_length = len; + txbuf.misc_Tx_bits = tx_bits; + card->hw_iface.poke(card->hw, + card->u.c.txbuf_off, + &txbuf, + sizeof(txbuf)); + txbuf.opp_flag = 1; /* start transmission */ + card->hw_iface.poke_byte(card->hw, + card->u.c.txbuf_off+ + offsetof(CHDLC_DATA_TX_STATUS_EL_STRUCT, opp_flag), + txbuf.opp_flag); + + /* Update transmit buffer control fields */ + card->u.c.txbuf_off += sizeof(txbuf); + if (card->u.c.txbuf_off > card->u.c.txbuf_last_off){ + card->u.c.txbuf_off = card->u.c.txbuf_base_off; + } + + return 0; +} + +/*============================================================================ + * Read TE1/56K Front end registers + */ +//static unsigned char read_front_end_reg (void* card1, unsigned short reg) +static unsigned char read_front_end_reg (void* card1, ...) +{ + va_list args; + sdla_t *card = (sdla_t*)card1; + wan_mbox_t *mb = &card->wan_mbox; + char *data = mb->wan_data; + u16 reg; + int err; + + va_start(args, card1); + reg = (u16)va_arg(args, int); + va_end(args); + + ((FRONT_END_REG_STRUCT *)data)->register_number = (unsigned short)reg; + mb->wan_data_len = sizeof(FRONT_END_REG_STRUCT); + mb->wan_command = READ_FRONT_END_REGISTER; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != COMMAND_OK){ + chdlc_error(card,err,mb); + } + + return(((FRONT_END_REG_STRUCT *)data)->register_value); +} + +/*============================================================================ + * Write to TE1/56K Front end registers + */ +//static unsigned char write_front_end_reg (void* card1, unsigned short reg, unsigned char value) +static int write_front_end_reg (void* card1, ...) +{ + va_list args; + sdla_t *card = (sdla_t*)card1; + wan_mbox_t *mb = &card->wan_mbox; + char *data = mb->wan_data; + u16 reg; + u8 value; + int err; + int retry=15; + + va_start(args, card1); + reg = (u16)va_arg(args, int); + value = (u8)va_arg(args, int); + va_end(args); + + do { + ((FRONT_END_REG_STRUCT *)data)->register_number = (unsigned short)reg; + ((FRONT_END_REG_STRUCT *)data)->register_value = value; + mb->wan_data_len = sizeof(FRONT_END_REG_STRUCT); + mb->wan_command = WRITE_FRONT_END_REGISTER; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != COMMAND_OK){ + chdlc_error(card,err,mb); + } + }while(err && --retry); + + return err; +} + +/*============================================================================ + * Enable timer interrupt + */ +static void chdlc_enable_timer (void* card_id) +{ + sdla_t *card = (sdla_t*)card_id; + netdevice_t *dev; + + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + DEBUG_TEST("%s: Chdlc enabling timer %s\n",card->devname, + dev ? wan_netif_name(dev) : "No DEV"); + + card->u.c.timer_int_enabled |= TMR_INT_ENABLED_TE; + card->hw_iface.set_bit(card->hw, card->intr_perm_off, APP_INT_ON_TIMER); + return; +} + +/****** Firmware Error Handler **********************************************/ + +/*============================================================================ + * Firmware error handler. + * This routine is called whenever firmware command returns non-zero + * return code. + * + * Return zero if previous command has to be cancelled. + */ +static int chdlc_error (sdla_t *card, int err, wan_mbox_t *mb) +{ + unsigned cmd = mb->wan_command; + + switch (err) { + + case CMD_TIMEOUT: + printk(KERN_INFO "%s: command 0x%02X timed out!\n", + card->devname, cmd); + break; + + case S514_BOTH_PORTS_SAME_CLK_MODE: + if(cmd == SET_CHDLC_CONFIGURATION) { + printk(KERN_INFO + "%s: Configure both ports for the same clock source\n", + card->devname); + break; + } + + default: + printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n", + card->devname, cmd, err); + } + + return 0; +} + +/********** Bottom Half Handlers ********************************************/ + +/* NOTE: There is no API, BH support for Kernels lower than 2.2.X. + * DO NOT INSERT ANY CODE HERE, NOTICE THE + * PREPROCESSOR STATEMENT ABOVE, UNLESS YOU KNOW WHAT YOU ARE + * DOING */ + +static void chdlc_bh (unsigned long data) +{ + chdlc_private_area_t* chan = (chdlc_private_area_t*)data; + sdla_t *card = chan->card; + struct sk_buff *skb; + int len=0; + + while ((skb=wan_api_dequeue_skb(chan)) != NULL){ + + len=skb->len; + if (chan->common.usedby == API){ + if (wan_api_rx(chan,skb) == 0){ + card->wandev.stats.rx_packets++; + card->wandev.stats.rx_bytes += len; + }else{ + ++card->wandev.stats.rx_dropped; + wan_skb_free(skb); + } + }else{ + wan_skb_free(skb); + ++card->wandev.stats.rx_dropped; + } + } + + WAN_TASKLET_END((&chan->common.bh_task)); + + return; +} + +/* END OF API BH Support */ + + +/****** Interrupt Handlers **************************************************/ + +/*============================================================================ + * Cisco HDLC interrupt service routine. + */ +static void wpc_isr (sdla_t* card) +{ + netdevice_t* dev; + SHARED_MEMORY_INFO_STRUCT flags; + int i; + + /* Check for which port the interrupt has been generated + * Since Secondary Port is piggybacking on the Primary + * the check must be done here. + */ + + if (!card->hw){ + return; + } + + card->hw_iface.peek(card->hw, card->flags_off, + &flags, sizeof(flags)); + + /* Start card isr critical area */ + set_bit(0,&card->in_isr); + + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + + /* If we get an interrupt with no network device, stop the interrupts + * and issue an error */ + if (!card->tty_opt && !dev && + flags.interrupt_info_struct.interrupt_type != + COMMAND_COMPLETE_APP_INT_PEND){ + goto isr_done; + } + + /* if critical due to peripheral operations + * ie. update() or getstats() then reset the interrupt and + * wait for the board to retrigger. + */ + if(test_bit(PERI_CRIT, (void*)&card->wandev.critical)) { + printk(KERN_INFO "%s: Chdlc ISR: Critical with PERI_CRIT!\n", + card->devname); + goto isr_done; + } + + /* On a 508 Card, if critical due to if_send + * Major Error !!! */ + if(card->type != SDLA_S514) { + if(test_bit(SEND_CRIT, (void*)&card->wandev.critical)) { + printk(KERN_INFO "%s: Chdlc ISR: Critical with SEND_CRIT!\n", + card->devname); + card->in_isr = 0; + card->hw_iface.poke_byte(card->hw, card->intr_type_off, 0x00); + return; + } + } + + + + switch(flags.interrupt_info_struct.interrupt_type){ + + case RX_APP_INT_PEND: /* 0x01: receive interrupt */ + rx_intr(card); + break; + + case TX_APP_INT_PEND: /* 0x02: transmit interrupt */ + card->hw_iface.clear_bit(card->hw, card->intr_perm_off, APP_INT_ON_TX_FRAME); + if (card->tty_opt){ + set_bit(TX_INTR,(void*)&card->wandev.critical); + + /* If we fail to trigger the task, try the + * interrupt */ +#if 1 +//defined(LINUX_2_4) || defined(LINUX_2_1) + if (wanpipe_tty_trigger_poll(card) != 0){ + card->hw_iface.set_bit(card->hw, card->intr_perm_off, APP_INT_ON_TX_FRAME); + } +#endif + break; + } + + if (dev && is_queue_stopped(dev)){ + chdlc_private_area_t* chdlc_priv_area=dev->priv; + + if (chdlc_priv_area->common.usedby == API){ + start_net_queue(dev); + wan_wakeup_api(chdlc_priv_area); + }else{ + wake_net_dev(dev); + } + } + break; + + case COMMAND_COMPLETE_APP_INT_PEND:/* 0x04: cmd cplt */ + ++ card->timer_int_enabled; + break; + + case CHDLC_EXCEP_COND_APP_INT_PEND: /* 0x20 */ + process_chdlc_exception(card); + break; + + case GLOBAL_EXCEP_COND_APP_INT_PEND: + process_global_exception(card); + + /* Reset the 56k or T1/E1 front end exception condition */ + if(IS_56K_CARD(card) || IS_TE1_CARD(card)) { + FRONT_END_STATUS_STRUCT FE_status; + + card->hw_iface.peek(card->hw, + card->fe_status_off, + &FE_status, + sizeof(FE_status)); + FE_status.opp_flag = 0x01; + card->hw_iface.poke(card->hw, + card->fe_status_off, + &FE_status, + sizeof(FE_status)); + } + break; + + case TIMER_APP_INT_PEND: + timer_intr(card); + break; + + default: + + if (card->next){ + set_bit(0,&card->spurious); + }else{ + printk(KERN_INFO "%s: spurious interrupt 0x%02X!\n", + card->devname, + flags.interrupt_info_struct.interrupt_type); + printk(KERN_INFO "Code name: "); + for(i = 0; i < 4; i ++){ + printk("%c", + flags.global_info_struct.codename[i]); + } + printk("\n"); + printk(KERN_INFO "Code version: "); + for(i = 0; i < 4; i ++){ + printk("%c", + flags.global_info_struct.codeversion[i]); + } + printk("\n"); + } + break; + } + +isr_done: + + card->in_isr = 0; + card->hw_iface.poke_byte(card->hw, card->intr_type_off, 0x00); + return; +} + +/*============================================================================ + * Receive interrupt handler. + */ +static void rx_intr (sdla_t* card) +{ + netdevice_t *dev; + chdlc_private_area_t *chdlc_priv_area; + SHARED_MEMORY_INFO_STRUCT flags; + CHDLC_DATA_RX_STATUS_EL_STRUCT rxbuf; + struct sk_buff *skb; + unsigned addr; + unsigned len; + void *buf; + int i,udp_type; + + card->hw_iface.peek(card->hw, card->flags_off, &flags, sizeof(flags)); + card->hw_iface.peek(card->hw, card->u.c.rxmb_off, &rxbuf, sizeof(rxbuf)); + addr = rxbuf.ptr_data_bfr; + if (rxbuf.opp_flag != 0x01) { + printk(KERN_INFO + "%s: corrupted Rx buffer @ 0x%X, flag = 0x%02X!\n", + card->devname, (unsigned)card->u.c.rxmb_off, rxbuf.opp_flag); + printk(KERN_INFO "Code name: "); + for(i = 0; i < 4; i ++) + printk(KERN_INFO "%c", + flags.global_info_struct.codename[i]); + printk(KERN_INFO "\n"); + printk(KERN_INFO "Code version: "); + for(i = 0; i < 4; i ++) + printk(KERN_INFO "%c", + flags.global_info_struct.codeversion[i]); + printk(KERN_INFO "\n"); + + /* Bug Fix: Mar 6 2000 + * If we get a corrupted mailbox, it measn that driver + * is out of sync with the firmware. There is no recovery. + * If we don't turn off all interrupts for this card + * the machine will crash. + */ + printk(KERN_INFO "%s: Critical router failure ...!!!\n", card->devname); + printk(KERN_INFO "Please contact Sangoma Technologies !\n"); + chdlc_set_intr_mode(card,0); + return; + } + + len = rxbuf.frame_length; + +#if 1 +//defined(LINUX_2_4) || defined(LINUX_2_1) + if (card->tty_opt){ + + if (rxbuf.error_flag){ + goto rx_exit; + } + + if (len <= CRC_LENGTH){ + goto rx_exit; + } + + if (!card->u.c.async_mode){ + len -= CRC_LENGTH; + } + + wanpipe_tty_receive(card,addr,len); + goto rx_exit; + } +#endif + + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + if (!dev || !wan_netif_priv(dev)) + goto rx_exit; + + if (!is_dev_running(dev)) + goto rx_exit; + + chdlc_priv_area = wan_netif_priv(dev); + + if (chdlc_priv_area->common.usedby == ANNEXG){ + + if (rxbuf.error_flag){ + printk(KERN_INFO "Bad Rx Frame\n"); + goto rx_exit; + } + + /* Take off two CRC bytes */ + if (rxbuf.frame_length <= 2 || rxbuf.frame_length > 1506 ){ + printk(KERN_INFO "Bad Rx Frame Length %i\n", + rxbuf.frame_length); + goto rx_exit; + } + len = rxbuf.frame_length - CRC_LENGTH; + } + + /* Allocate socket buffer */ + skb = dev_alloc_skb(len+2); + + if (skb == NULL) { + printk(KERN_INFO "%s: no socket buffers available!\n", + card->devname); + ++card->wandev.stats.rx_dropped; + goto rx_exit; + } + + /* Align IP on 16 byte */ + skb_reserve(skb,2); + + /* Copy data to the socket buffer */ + if((addr + len) > card->u.c.rx_top_off + 1) { + unsigned tmp = card->u.c.rx_top_off - addr + 1; + buf = skb_put(skb, tmp); + card->hw_iface.peek(card->hw, addr, buf, tmp); + addr = card->u.c.rx_base_off; + len -= tmp; + } + + buf = skb_put(skb, len); + card->hw_iface.peek(card->hw, addr, buf, len); + + skb->protocol = htons(ETH_P_IP); + + udp_type = udp_pkt_type( skb, card ); + + if(udp_type == UDP_CPIPE_TYPE) { + if(store_udp_mgmt_pkt(UDP_PKT_FRM_NETWORK, + card, skb, dev, chdlc_priv_area)) { + card->hw_iface.set_bit(card->hw, card->intr_perm_off, APP_INT_ON_TIMER); + } + + } else if(chdlc_priv_area->common.usedby == API) { + + api_rx_hdr_t* api_rx_hdr; + struct timeval tv; + skb_push(skb, sizeof(api_rx_hdr_t)); + api_rx_hdr = (api_rx_hdr_t*)&skb->data[0x00]; + api_rx_hdr->error_flag = rxbuf.error_flag; + api_rx_hdr->time_stamp = rxbuf.time_stamp; + + do_gettimeofday(&tv); + api_rx_hdr->sec=tv.tv_sec; + api_rx_hdr->usec=tv.tv_usec; + + skb->protocol = htons(WP_PVC_PROT); + skb->mac.raw = skb->data; + skb->dev = dev; + skb->pkt_type = WAN_PACKET_DATA; + + if (wan_api_enqueue_skb(chdlc_priv_area,skb) < 0){ + wan_skb_free(skb); + ++card->wandev.stats.rx_dropped; + goto rx_exit; + } + + WAN_TASKLET_SCHEDULE(&chdlc_priv_area->common.bh_task); + + } else if (chdlc_priv_area->common.usedby == ANNEXG){ + + if (chdlc_priv_area->annexg_dev){ + skb->protocol = htons(ETH_P_X25); + skb->dev = chdlc_priv_area->annexg_dev; + skb->mac.raw = skb->data; + + if (wan_api_enqueue_skb(chdlc_priv_area,skb) < 0){ + wan_skb_free(skb); + ++card->wandev.stats.rx_dropped; + goto rx_exit; + } + + WAN_TASKLET_SCHEDULE(&chdlc_priv_area->common.bh_task); + + }else{ + wan_skb_free(skb); + ++card->wandev.stats.rx_errors; + } + + }else if (chdlc_priv_area->common.usedby == BRIDGE || + chdlc_priv_area->common.usedby == BRIDGE_NODE){ + + /* Make sure it's an Ethernet frame, otherwise drop it */ + if (skb->len <= ETH_ALEN) { + wan_skb_free(skb); + ++card->wandev.stats.rx_errors; + goto rx_exit; + } + + card->wandev.stats.rx_packets ++; + card->wandev.stats.rx_bytes += skb->len; + + skb->dev = dev; + skb->protocol=eth_type_trans(skb,dev); + netif_rx(skb); + }else{ + /* FIXME: we should check to see if the received packet is a + multicast packet so that we can increment the multicast + statistic + ++ chdlc_priv_area->if_stats.multicast; + */ + /* Pass it up the protocol stack */ + + card->wandev.stats.rx_packets ++; + card->wandev.stats.rx_bytes += skb->len; + + skb->protocol = htons(ETH_P_IP); + skb->dev = dev; + skb->mac.raw = skb->data; + netif_rx(skb); + } + +rx_exit: + /* Release buffer element and calculate a pointer to the next one */ + rxbuf.opp_flag = 0x00; + card->hw_iface.poke_byte(card->hw, + card->u.c.rxmb_off+offsetof(CHDLC_DATA_RX_STATUS_EL_STRUCT, opp_flag), + rxbuf.opp_flag); + card->u.c.rxmb_off += sizeof(rxbuf); + if (card->u.c.rxmb_off > card->u.c.rxbuf_last_off){ + card->u.c.rxmb_off = card->u.c.rxbuf_base_off; + } +} + +/*============================================================================ + * Timer interrupt handler. + * The timer interrupt is used for two purposes: + * 1) Processing udp calls from 'cpipemon'. + * 2) Reading board-level statistics for updating the proc file system. + */ +void timer_intr(sdla_t *card) +{ + netdevice_t* dev=NULL; + chdlc_private_area_t* chdlc_priv_area = NULL; + /* TE timer interrupt */ + if (card->u.c.timer_int_enabled & TMR_INT_ENABLED_TE) { + card->wandev.fe_iface.polling(&card->fe); + card->u.c.timer_int_enabled &= ~TMR_INT_ENABLED_TE; + } + + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + if (!dev || !wan_netif_priv(dev)){ + goto timer_isr_exit; + } + + chdlc_priv_area = dev->priv; + + /* Configure hardware */ + if (card->u.c.timer_int_enabled & TMR_INT_ENABLED_CONFIG) { + config_chdlc(card, dev); + card->u.c.timer_int_enabled &= ~TMR_INT_ENABLED_CONFIG; + } + + /* process a udp call if pending */ + if(card->u.c.timer_int_enabled & TMR_INT_ENABLED_UDP) { + process_udp_mgmt_pkt(card, dev, + chdlc_priv_area,0); + card->u.c.timer_int_enabled &= ~TMR_INT_ENABLED_UDP; + } + + /* read the communications statistics if required */ + if(card->u.c.timer_int_enabled & TMR_INT_ENABLED_UPDATE) { + update_comms_stats(card, chdlc_priv_area); + if(!(-- chdlc_priv_area->update_comms_stats)) { + card->u.c.timer_int_enabled &= + ~TMR_INT_ENABLED_UPDATE; + } + } + +timer_isr_exit: + + /* only disable the timer interrupt if there are no udp or statistic */ + /* updates pending */ + if(!card->u.c.timer_int_enabled) { + card->hw_iface.clear_bit(card->hw, card->intr_perm_off, APP_INT_ON_TIMER); + } +} + +/*------------------------------------------------------------------------------ + Miscellaneous Functions + - set_chdlc_config() used to set configuration options on the board +------------------------------------------------------------------------------*/ + +static int set_chdlc_config(sdla_t* card) +{ + netdevice_t *dev; + CHDLC_CONFIGURATION_STRUCT cfg; + + memset(&cfg, 0, sizeof(CHDLC_CONFIGURATION_STRUCT)); + + if(card->wandev.clocking){ + cfg.baud_rate = card->wandev.bps; + } + + cfg.line_config_options = (card->wandev.interface == WANOPT_RS232) ? + INTERFACE_LEVEL_RS232 : INTERFACE_LEVEL_V35; + + + if (card->wandev.line_coding == WANOPT_NRZI){ + printk(KERN_INFO "%s: Configuring for NRZI encoding\n", card->devname); + cfg.line_config_options |= NRZI_ENCODING; + } + + if (card->wandev.line_idle == WANOPT_IDLE_MARK){ + printk(KERN_INFO "%s: Configuring for Idle Mark\n", card->devname); + cfg.line_config_options |= IDLE_MARK; + } + + if (card->wandev.connection == WANOPT_SWITCHED){ + printk(KERN_INFO "%s: Configuring for Switched CTS/RTS\n", card->devname); + cfg.modem_config_options = SWITCHED_CTS_RTS; + }else{ + cfg.modem_config_options = 0; + } + + cfg.modem_status_timer = 100; + + cfg.CHDLC_protocol_options = card->u.c.protocol_options; + + if (card->tty_opt){ + cfg.CHDLC_API_options = DISCARD_RX_ERROR_FRAMES; + } + + cfg.percent_data_buffer_for_Tx = (card->u.c.receive_only) ? 0 : 50; + cfg.CHDLC_statistics_options = (CHDLC_TX_DATA_BYTE_COUNT_STAT | + CHDLC_RX_DATA_BYTE_COUNT_STAT); + + if (card->tty_opt){ + card->wandev.mtu = TTY_CHDLC_MAX_MTU; + } + cfg.max_CHDLC_data_field_length = card->wandev.mtu; + cfg.transmit_keepalive_timer = card->u.c.kpalv_tx; + cfg.receive_keepalive_timer = card->u.c.kpalv_rx; + cfg.keepalive_error_tolerance = card->u.c.kpalv_err; + cfg.SLARP_request_timer = card->u.c.slarp_timer; + + if (cfg.SLARP_request_timer) { + cfg.IP_address = 0; + cfg.IP_netmask = 0; + + } + + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + if (dev){ + chdlc_private_area_t *chdlc_priv_area = wan_netif_priv(dev); + + struct in_device *in_dev = dev->ip_ptr; + + if(in_dev != NULL) { + struct in_ifaddr *ifa = in_dev->ifa_list; + + if (ifa != NULL ) { + cfg.IP_address = ntohl(ifa->ifa_local); + cfg.IP_netmask = ntohl(ifa->ifa_mask); + chdlc_priv_area->IP_address = ntohl(ifa->ifa_local); + chdlc_priv_area->IP_netmask = ntohl(ifa->ifa_mask); + } + } + + /* FIXME: We must re-think this message in next release + if((cfg.IP_address & 0x000000FF) > 2) { + printk(KERN_WARNING "\n"); + printk(KERN_WARNING " WARNING:%s configured with an\n", + card->devname); + printk(KERN_WARNING " invalid local IP address.\n"); + printk(KERN_WARNING " Slarp pragmatics will fail.\n"); + printk(KERN_WARNING " IP address should be of the\n"); + printk(KERN_WARNING " format A.B.C.1 or A.B.C.2.\n"); + } + */ + } + + return chdlc_configure(card, &cfg); +} + +static int chdlc_calibrate_baud (sdla_t *card) +{ + wan_mbox_t* mb = &card->wan_mbox; + int err; + + mb->wan_data_len = 0; + mb->wan_command = START_BAUD_CALIBRATION; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + + if (err != COMMAND_OK) + chdlc_error (card, err, mb); + + return err; +} + +static int chdlc_read_baud_calibration (sdla_t *card) +{ + wan_mbox_t* mb = &card->wan_mbox; + int err; + +read_baud_again: + + mb->wan_data_len = 0; + mb->wan_command = READ_BAUD_CALIBRATION_RESULT; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + + switch (err){ + + case COMMAND_OK: + mb->wan_data_len = 0; + mb->wan_command = READ_CHDLC_CONFIGURATION; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err == COMMAND_OK){ + card->wandev.bps = ((CHDLC_CONFIGURATION_STRUCT*)mb->wan_data)->baud_rate; + printk(KERN_INFO "%s: Baud Rate calibrated at: %i bps\n", + card->devname,card->wandev.bps); + } + break; + + case BAUD_CALIBRATION_NOT_DONE: + case BUSY_WITH_BAUD_CALIBRATION: + goto read_baud_again; + + case BAUD_CAL_FAILED_NO_TX_CLK: + printk(KERN_INFO "%s: Baud Rate calibration failed: No Tx Clock!\n", + card->devname); + return -EINVAL; + + case BAUD_CAL_FAILED_BAUD_HI: + printk(KERN_INFO "%s: Baud Rate calibration failed: Baud to High!\n", + card->devname); + return -EINVAL; + + case CANNOT_DO_BAUD_CAL: + printk(KERN_INFO "%s: Baud Rate calibration cannot be performed!\n", + card->devname); + return -EINVAL; + default: + chdlc_error(card,err,mb); + return -EINVAL; + } + return err; +} + + +/*----------------------------------------------------------------------------- + set_asy_config() used to set asynchronous configuration options on the board +------------------------------------------------------------------------------*/ + +static int set_asy_config(sdla_t* card) +{ + + ASY_CONFIGURATION_STRUCT cfg; + wan_mbox_t *mb = &card->wan_mbox; + int err; + + memset(&cfg, 0, sizeof(ASY_CONFIGURATION_STRUCT)); + + if(card->wandev.clocking) + cfg.baud_rate = card->wandev.bps; + + cfg.line_config_options = (card->wandev.interface == WANOPT_RS232) ? + INTERFACE_LEVEL_RS232 : INTERFACE_LEVEL_V35; + + cfg.modem_config_options = 0; + cfg.asy_API_options = card->u.c.api_options; + cfg.asy_protocol_options = card->u.c.protocol_options; + cfg.Tx_bits_per_char = card->u.c.tx_bits_per_char; + cfg.Rx_bits_per_char = card->u.c.rx_bits_per_char; + cfg.stop_bits = card->u.c.stop_bits; + cfg.parity = card->u.c.parity; + cfg.break_timer = card->u.c.break_timer; + cfg.asy_Rx_inter_char_timer = card->u.c.inter_char_timer; + cfg.asy_Rx_complete_length = card->u.c.rx_complete_length; + cfg.XON_char = card->u.c.xon_char; + cfg.XOFF_char = card->u.c.xoff_char; + cfg.asy_statistics_options = (CHDLC_TX_DATA_BYTE_COUNT_STAT | + CHDLC_RX_DATA_BYTE_COUNT_STAT); + + mb->wan_data_len = sizeof(ASY_CONFIGURATION_STRUCT); + memcpy(mb->wan_data, &cfg, mb->wan_data_len); + mb->wan_command = SET_ASY_CONFIGURATION; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != COMMAND_OK) + chdlc_error (card, err, mb); + return err; +} + +/*============================================================================ + * Enable asynchronous communications. + */ + +static int asy_comm_enable (sdla_t* card) +{ + netdevice_t *dev; + int err; + wan_mbox_t *mb = &card->wan_mbox; + + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + if (dev == NULL){ + return -EINVAL; + } + mb->wan_data_len = 0; + mb->wan_command = ENABLE_ASY_COMMUNICATIONS; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != COMMAND_OK && dev) + chdlc_error(card, err, mb); + + if (!err) + card->u.c.comm_enabled = 1; + + return err; +} + +/*============================================================================ + * Process global exception condition + */ +static int process_global_exception(sdla_t *card) +{ + wan_mbox_t* mb = &card->wan_mbox; + int err; + + mb->wan_data_len = 0; + mb->wan_command = READ_GLOBAL_EXCEPTION_CONDITION; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + + if(err != CMD_TIMEOUT ){ + + switch(mb->wan_return_code) { + + case EXCEP_MODEM_STATUS_CHANGE: + + if (IS_56K_CARD(card)) { + + FRONT_END_STATUS_STRUCT FE_status; + + card->hw_iface.peek(card->hw, + card->fe_status_off, + &FE_status, + sizeof(FE_status)); + + card->fe.fe_param.k56_param.RR8_reg_56k = + FE_status.FE_U.stat_56k.RR8_56k; + card->fe.fe_param.k56_param.RRA_reg_56k = + FE_status.FE_U.stat_56k.RRA_56k; + card->fe.fe_param.k56_param.RRC_reg_56k = + FE_status.FE_U.stat_56k.RRC_56k; + card->wandev.fe_iface.read_alarm(&card->fe, 0); + + chdlc_handle_front_end_state(card); + break; + + } + + if (IS_TE1_CARD(card)) { + /* TE1 T1/E1 interrupt */ + card->wandev.fe_iface.isr(&card->fe); + chdlc_handle_front_end_state(card); + break; + } + + if ((mb->wan_data[0] & (DCD_HIGH | CTS_HIGH)) == (DCD_HIGH | CTS_HIGH)){ + card->fe.fe_status = FE_CONNECTED; + }else{ + card->fe.fe_status = FE_DISCONNECTED; + } + + printk(KERN_INFO "%s: Modem status change\n", + card->devname); + + switch(mb->wan_data[0] & (DCD_HIGH | CTS_HIGH)) { + + case ((DCD_HIGH | CTS_HIGH)): + printk(KERN_INFO "%s: DCD high, CTS high\n",card->devname); + break; + + case (DCD_HIGH): + printk(KERN_INFO "%s: DCD high, CTS low\n",card->devname); + break; + + case (CTS_HIGH): + printk(KERN_INFO "%s: DCD low, CTS high\n",card->devname); + break; + + default: + printk(KERN_INFO "%s: DCD low, CTS low\n",card->devname); + break; + } + + chdlc_handle_front_end_state(card); + break; + + case EXCEP_TRC_DISABLED: + printk(KERN_INFO "%s: Line trace disabled\n", + card->devname); + break; + + case EXCEP_IRQ_TIMEOUT: + printk(KERN_INFO "%s: IRQ timeout occurred\n", + card->devname); + break; + + case EXCEP_CSU_DSU_STATE_CHANGE: +/* NC + * Ignore this for now + * because we don't know if the CSU/DSU + * state change. + printk(KERN_INFO "%s: CSU/DSU In Service alarm state change\n", + card->devname); + */ + break; + + case 0x17: + if (card->tty_opt){ + if (card->tty && card->tty_open){ + printk(KERN_INFO + "%s: Modem Hangup Exception: Hanging Up!\n", + card->devname); + tty_hangup(card->tty); + } + break; + } + + /* If TTY is not used just drop throught */ + + default: + printk(KERN_INFO "%s: Global exception %x\n", + card->devname, mb->wan_return_code); + break; + } + } + return 0; +} + + +/*============================================================================ + * Process chdlc exception condition + */ +static int process_chdlc_exception(sdla_t *card) +{ + netdevice_t *dev; + wan_mbox_t *mb = &card->wan_mbox; + int err; + + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + if (dev == NULL){ + return -EINVAL; + } + + mb->wan_data_len = 0; + mb->wan_command = READ_CHDLC_EXCEPTION_CONDITION; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + + if(err != CMD_TIMEOUT) { + + switch (err) { + + case EXCEP_LINK_ACTIVE: + card->u.c.state = WAN_CONNECTED; + if (card->wandev.ignore_front_end_status == WANOPT_YES || + card->fe.fe_status == FE_CONNECTED){ + port_set_state(card, WAN_CONNECTED); + trigger_chdlc_poll(dev); + } + break; + + case EXCEP_LINK_INACTIVE_MODEM: + card->u.c.state = WAN_DISCONNECTED; + port_set_state(card, WAN_DISCONNECTED); + unconfigure_ip(card, dev); + trigger_chdlc_poll(dev); + /* Start debugging */ + WAN_DEBUG_START(card); + break; + + case EXCEP_LINK_INACTIVE_KPALV: + card->u.c.state = WAN_DISCONNECTED; + port_set_state(card, WAN_DISCONNECTED); + printk(KERN_INFO "%s: Keepalive timer expired.\n", + card->devname); + unconfigure_ip(card, dev); + trigger_chdlc_poll(dev); + /* Start debugging */ + WAN_DEBUG_START(card); + break; + + case EXCEP_IP_ADDRESS_DISCOVERED: + if (configure_ip(card, dev)) + return -1; + break; + + case EXCEP_LOOPBACK_CONDITION: + printk(KERN_INFO "%s: Loopback Condition Detected.\n", + card->devname); + break; + + case NO_CHDLC_EXCEP_COND_TO_REPORT: + printk(KERN_INFO "%s: No exceptions reported.\n", + card->devname); + break; + } + } + return 0; +} + + +/*============================================================================ + * Configure IP from SLARP negotiation + * This adds dynamic routes when SLARP has provided valid addresses + */ + +static int configure_ip (sdla_t* card, netdevice_t* dev) +{ + chdlc_private_area_t *chdlc_priv_area; + char err; + + if (!dev) + return 0; + + chdlc_priv_area = dev->priv; + + + /* set to discover */ + if(card->u.c.slarp_timer != 0x00) { + wan_mbox_t* mb = &card->wan_mbox; + CHDLC_CONFIGURATION_STRUCT *cfg; + + mb->wan_data_len = 0; + mb->wan_command = READ_CHDLC_CONFIGURATION; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + + if(err != COMMAND_OK) { + chdlc_error(card,err,mb); + return -1; + } + + cfg = (CHDLC_CONFIGURATION_STRUCT *)mb->wan_data; + chdlc_priv_area->IP_address = cfg->IP_address; + chdlc_priv_area->IP_netmask = cfg->IP_netmask; + + /* Set flag to add route */ + chdlc_priv_area->route_status = ADD_ROUTE; + + /* The idea here is to add the route in the poll routine. + This way, we aren't in interrupt context when adding routes */ + trigger_chdlc_poll(dev); + } + + return 0; +} + + +/*============================================================================ + * Un-Configure IP negotiated by SLARP + * This removes dynamic routes when the link becomes inactive. + */ + +static int unconfigure_ip (sdla_t* card, netdevice_t *dev) +{ + chdlc_private_area_t *chdlc_priv_area; + + if (!dev) + return 0; + + chdlc_priv_area= dev->priv; + + if (chdlc_priv_area->route_status == ROUTE_ADDED) { + + /* Note: If this function is called, the + * port state has been DISCONNECTED. This state + * change will trigger a poll_disconnected + * function, that will check for this condition. + */ + chdlc_priv_area->route_status = REMOVE_ROUTE; + + } + return 0; +} + +/*============================================================================ + * Routine to add/remove routes + * Called like a polling routine when Routes are flagged to be added/removed. + */ + +static void process_route (sdla_t *card) +{ + netdevice_t *dev; + unsigned char port_num; + chdlc_private_area_t *chdlc_priv_area = NULL; + u32 local_IP_addr = 0; + u32 remote_IP_addr = 0; + u32 IP_netmask, IP_addr; + int err = 0; + struct in_device *in_dev; + mm_segment_t fs; + struct ifreq if_info; + struct sockaddr_in *if_data1, *if_data2; + + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + if (!dev || !wan_netif_priv(dev)){ + return; + } + + chdlc_priv_area = wan_netif_priv(dev); + port_num = card->u.c.comm_port; + + /* Bug Fix Mar 16 2000 + * AND the IP address to the Mask before checking + * the last two bits. */ + + if((chdlc_priv_area->route_status == ADD_ROUTE) && + ((chdlc_priv_area->IP_address & ~chdlc_priv_area->IP_netmask) > 2)) { + unsigned long tmp_ip; + printk(KERN_INFO "%s: Dynamic route failure.\n",card->devname); + + tmp_ip=ntohl(chdlc_priv_area->IP_address); + + if(card->u.c.slarp_timer) { + printk(KERN_INFO "%s: Bad IP address %u.%u.%u.%u received\n", + card->devname, + NIPQUAD(tmp_ip)); + printk(KERN_INFO "%s: from remote station.\n", + card->devname); + + }else{ + printk(KERN_INFO "%s: Bad IP address %u.%u.%u.%u issued\n", + card->devname, + NIPQUAD(tmp_ip)); + printk(KERN_INFO "%s: to remote station. Local\n", + card->devname); + printk(KERN_INFO "%s: IP address must be A.B.C.1\n", + card->devname); + printk(KERN_INFO "%s: or A.B.C.2.\n",card->devname); + } + + /* remove the route due to the IP address error condition */ + chdlc_priv_area->route_status = REMOVE_ROUTE; + err = 1; + } + + /* If we are removing a route with bad IP addressing, then use the */ + /* locally configured IP addresses */ + if((chdlc_priv_area->route_status == REMOVE_ROUTE) && err) { + + /* do not remove a bad route that has already been removed */ + if(chdlc_priv_area->route_removed) { + return; + } + + in_dev = dev->ip_ptr; + + if(in_dev != NULL) { + struct in_ifaddr *ifa = in_dev->ifa_list; + if (ifa != NULL ) { + local_IP_addr = ifa->ifa_local; + IP_netmask = ifa->ifa_mask; + } + } + }else{ + /* According to Cisco HDLC, if the point-to-point address is + A.B.C.1, then we are the opposite (A.B.C.2), and vice-versa. + */ + IP_netmask = ntohl(chdlc_priv_area->IP_netmask); + remote_IP_addr = ntohl(chdlc_priv_area->IP_address); + + + /* If Netmask is 255.255.255.255 the local address + * calculation will fail. Default it back to 255.255.255.0 */ + if (IP_netmask == 0xffffffff) + IP_netmask &= 0x00ffffff; + + /* Bug Fix Mar 16 2000 + * AND the Remote IP address with IP netmask, instead + * of static netmask of 255.255.255.0 */ + local_IP_addr = (remote_IP_addr & IP_netmask) + + (~remote_IP_addr & ntohl(0x0003)); + + if(!card->u.c.slarp_timer) { + IP_addr = local_IP_addr; + local_IP_addr = remote_IP_addr; + remote_IP_addr = IP_addr; + } + } + + fs = get_fs(); /* Save file system */ + set_fs(get_ds()); /* Get user space block */ + + /* Setup a structure for adding/removing routes */ + memset(&if_info, 0, sizeof(if_info)); + strcpy(if_info.ifr_name, dev->name); + + switch (chdlc_priv_area->route_status) { + + case ADD_ROUTE: + + if(!card->u.c.slarp_timer) { + if_data2 = (struct sockaddr_in *)&if_info.ifr_dstaddr; + if_data2->sin_addr.s_addr = remote_IP_addr; + if_data2->sin_family = AF_INET; + err = wp_devinet_ioctl(SIOCSIFDSTADDR, &if_info); + } else { + if_data1 = (struct sockaddr_in *)&if_info.ifr_addr; + if_data1->sin_addr.s_addr = local_IP_addr; + if_data1->sin_family = AF_INET; + if(!(err = wp_devinet_ioctl(SIOCSIFADDR, &if_info))){ + if_data2 = (struct sockaddr_in *)&if_info.ifr_dstaddr; + if_data2->sin_addr.s_addr = remote_IP_addr; + if_data2->sin_family = AF_INET; + err = wp_devinet_ioctl(SIOCSIFDSTADDR, &if_info); + } + } + + if(err) { + printk(KERN_INFO "%s: Add route %u.%u.%u.%u failed (%d)\n", + card->devname, NIPQUAD(remote_IP_addr), err); + } else { + ((chdlc_private_area_t *)dev->priv)->route_status = ROUTE_ADDED; + printk(KERN_INFO "%s: Dynamic route added.\n", + card->devname); + printk(KERN_INFO "%s: Local IP addr : %u.%u.%u.%u\n", + card->devname, NIPQUAD(local_IP_addr)); + printk(KERN_INFO "%s: Remote IP addr: %u.%u.%u.%u\n", + card->devname, NIPQUAD(remote_IP_addr)); + chdlc_priv_area->route_removed = 0; + } + break; + + + case REMOVE_ROUTE: + + /* Change the local ip address of the interface to 0. + * This will also delete the destination route. + */ + if(!card->u.c.slarp_timer) { + if_data2 = (struct sockaddr_in *)&if_info.ifr_dstaddr; + if_data2->sin_addr.s_addr = 0; + if_data2->sin_family = AF_INET; + err = wp_devinet_ioctl(SIOCSIFDSTADDR, &if_info); + } else { + if_data1 = (struct sockaddr_in *)&if_info.ifr_addr; + if_data1->sin_addr.s_addr = 0; + if_data1->sin_family = AF_INET; + err = wp_devinet_ioctl(SIOCSIFADDR,&if_info); + + } + if(err) { + printk(KERN_INFO + "%s: Remove route %u.%u.%u.%u failed, (err %d)\n", + card->devname, NIPQUAD(remote_IP_addr), + err); + } else { + ((chdlc_private_area_t *)dev->priv)->route_status = + NO_ROUTE; + printk(KERN_INFO "%s: Dynamic route removed: %u.%u.%u.%u\n", + card->devname, NIPQUAD(local_IP_addr)); + chdlc_priv_area->route_removed = 1; + } + break; + } + + set_fs(fs); /* Restore file system */ + +} + + +/** + * if_do_ioctl - Ioctl handler for fr + * @dev: Device subject to ioctl + * @ifr: Interface request block from the user + * @cmd: Command that is being issued + * + * This function handles the ioctls that may be issued by the user + * to control the settings of a FR. It does both busy + * and security checks. This function is intended to be wrapped by + * callers who wish to add additional ioctl calls of their own. + */ +/* SNMP */ +static int if_do_ioctl(netdevice_t *dev, struct ifreq *ifr, int cmd) +{ + chdlc_private_area_t* chan= (chdlc_private_area_t*)dev->priv; + unsigned long smp_flags; + sdla_t *card; + wan_udp_pkt_t *wan_udp_pkt; + int err=0; + + if (!chan){ + return -ENODEV; + } + card=chan->card; + + + switch(cmd) + { + + case SIOC_WANPIPE_BIND_SK: + if (!ifr){ + err= -EINVAL; + break; + } + + spin_lock_irqsave(&card->wandev.lock,smp_flags); + err=wan_bind_api_to_svc(chan,ifr->ifr_data); + spin_unlock_irqrestore(&card->wandev.lock,smp_flags); + break; + + case SIOC_WANPIPE_UNBIND_SK: + if (!ifr){ + err= -EINVAL; + break; + } + + spin_lock_irqsave(&card->wandev.lock,smp_flags); + err=wan_unbind_api_from_svc(chan,ifr->ifr_data); + spin_unlock_irqrestore(&card->wandev.lock,smp_flags); + break; + + case SIOC_WANPIPE_CHECK_TX: + case SIOC_ANNEXG_CHECK_TX: + err=0; + break; + + case SIOC_WANPIPE_DEV_STATE: + err = chan->common.state; + break; + + case SIOC_ANNEXG_KICK: + err=0; + break; + + case SIOC_WANPIPE_PIPEMON: + + NET_ADMIN_CHECK(); + + if (atomic_read(&chan->udp_pkt_len) != 0){ + return -EBUSY; + } + + atomic_set(&chan->udp_pkt_len,MAX_LGTH_UDP_MGNT_PKT); + + /* For performance reasons test the critical + * here before spin lock */ + if (test_bit(0,&card->in_isr)){ + atomic_set(&chan->udp_pkt_len,0); + return -EBUSY; + } + + + wan_udp_pkt=(wan_udp_pkt_t*)chan->udp_pkt_data; + if (copy_from_user(&wan_udp_pkt->wan_udp_hdr,ifr->ifr_data,sizeof(wan_udp_hdr_t))){ + atomic_set(&chan->udp_pkt_len,0); + return -EFAULT; + } + + spin_lock_irqsave(&card->wandev.lock, smp_flags); + + /* We have to check here again because we don't know + * what happened during spin_lock */ + if (test_bit(0,&card->in_isr)) { + printk(KERN_INFO "%s:%s Pipemon command failed, Driver busy: try again.\n", + card->devname,dev->name); + atomic_set(&chan->udp_pkt_len,0); + spin_unlock_irqrestore(&card->wandev.lock, smp_flags); + return -EBUSY; + } + + process_udp_mgmt_pkt(card,dev,chan,1); + + spin_unlock_irqrestore(&card->wandev.lock, smp_flags); + + /* This area will still be critical to other + * PIPEMON commands due to udp_pkt_len + * thus we can release the irq */ + + if (atomic_read(&chan->udp_pkt_len) > sizeof(wan_udp_pkt_t)){ + printk(KERN_INFO "%s: Error: Pipemon buf too bit on the way up! %i\n", + card->devname,atomic_read(&chan->udp_pkt_len)); + atomic_set(&chan->udp_pkt_len,0); + return -EINVAL; + } + + if (copy_to_user(ifr->ifr_data,&wan_udp_pkt->wan_udp_hdr,sizeof(wan_udp_hdr_t))){ + atomic_set(&chan->udp_pkt_len,0); + return -EFAULT; + } + + atomic_set(&chan->udp_pkt_len,0); + return 0; + + + default: + return -EOPNOTSUPP; + } + return err; +} + + + +/*============================================================================= + * Store a UDP management packet for later processing. + */ + +static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, + struct sk_buff *skb, netdevice_t* dev, + chdlc_private_area_t* chdlc_priv_area ) +{ + int udp_pkt_stored = 0; + + if(!atomic_read(&chdlc_priv_area->udp_pkt_len) && + (skb->len <= MAX_LGTH_UDP_MGNT_PKT)) { + atomic_set(&chdlc_priv_area->udp_pkt_len, skb->len); + chdlc_priv_area->udp_pkt_src = udp_pkt_src; + memcpy(chdlc_priv_area->udp_pkt_data, skb->data, skb->len); + card->u.c.timer_int_enabled = TMR_INT_ENABLED_UDP; + udp_pkt_stored = 1; + } + + wan_skb_free(skb); + + return(udp_pkt_stored); +} + + +/*============================================================================= + * Process UDP management packet. + */ + +static int process_udp_mgmt_pkt(sdla_t* card, netdevice_t* dev, + chdlc_private_area_t* chdlc_priv_area, int local_dev ) +{ + unsigned char *buf; + unsigned int frames, len; + struct sk_buff *new_skb; + unsigned short buffer_length, real_len; + volatile unsigned long data_ptr; + unsigned data_length; + int udp_mgmt_req_valid = 1; + SHARED_MEMORY_INFO_STRUCT flags; + wan_mbox_t *mb = &card->wan_mbox; + wan_udp_pkt_t *wan_udp_pkt; + struct timeval tv; + int err; + + wan_udp_pkt = (wan_udp_pkt_t *) chdlc_priv_area->udp_pkt_data; + + if (!local_dev){ + + if(chdlc_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK){ + + /* Only these commands are support for remote debugging. + * All others are not */ + switch(wan_udp_pkt->wan_udp_command) { + + case READ_GLOBAL_STATISTICS: + case READ_MODEM_STATUS: + case READ_CHDLC_LINK_STATUS: + case CPIPE_ROUTER_UP_TIME: + case READ_COMMS_ERROR_STATS: + case READ_CHDLC_OPERATIONAL_STATS: + /* These two commands are executed for + * each request */ + case READ_CHDLC_CONFIGURATION: + case READ_CHDLC_CODE_VERSION: + case WAN_GET_MEDIA_TYPE: + case WAN_FE_GET_CFG: + case WAN_FE_GET_STAT: + case WAN_GET_PROTOCOL: + case WAN_GET_PLATFORM: + udp_mgmt_req_valid = 1; + break; + default: + udp_mgmt_req_valid = 0; + break; + } + } + } + + if(!udp_mgmt_req_valid) { + + /* set length to 0 */ + wan_udp_pkt->wan_udp_data_len = 0; + + /* set return code */ + wan_udp_pkt->wan_udp_return_code = 0xCD; + + if (net_ratelimit()){ + printk(KERN_INFO + "%s: Warning, Illegal UDP command attempted from network: %x\n", + card->devname,wan_udp_pkt->wan_udp_command); + } + + } else { + unsigned long trace_status_cfg_addr = 0; + TRACE_STATUS_EL_CFG_STRUCT trace_cfg_struct; + TRACE_STATUS_ELEMENT_STRUCT trace_element_struct; + + wan_udp_pkt->wan_udp_opp_flag = 0; + + switch(wan_udp_pkt->wan_udp_command) { + + case CPIPE_ENABLE_TRACING: + if (!chdlc_priv_area->TracingEnabled) { + + /* OPERATE_DATALINE_MONITOR */ + mb->wan_data_len = sizeof(LINE_TRACE_CONFIG_STRUCT); + mb->wan_command = SET_TRACE_CONFIGURATION; + + ((LINE_TRACE_CONFIG_STRUCT *)mb->wan_data)-> + trace_config = TRACE_ACTIVE; + /* Trace delay mode is not used because it slows + down transfer and results in a standoff situation + when there is a lot of data */ + + /* Configure the Trace based on user inputs */ + ((LINE_TRACE_CONFIG_STRUCT *)mb->wan_data)->trace_config |= + wan_udp_pkt->wan_udp_data[0]; + + ((LINE_TRACE_CONFIG_STRUCT *)mb->wan_data)-> + trace_deactivation_timer = 4000; + + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != COMMAND_OK) { + chdlc_error(card,err,mb); + card->TracingEnabled = 0; + wan_udp_pkt->wan_udp_return_code = err; + mb->wan_data_len = 0; + break; + } + + /* Get the base address of the trace element list */ + mb->wan_data_len = 0; + mb->wan_command = READ_TRACE_CONFIGURATION; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + + if (err != COMMAND_OK) { + chdlc_error(card,err,mb); + chdlc_priv_area->TracingEnabled = 0; + wan_udp_pkt->wan_udp_return_code = err; + mb->wan_data_len = 0; + break; + } + + trace_status_cfg_addr =((LINE_TRACE_CONFIG_STRUCT *) + mb->wan_data) -> ptr_trace_stat_el_cfg_struct; + + card->hw_iface.peek(card->hw, trace_status_cfg_addr, + &trace_cfg_struct, sizeof(trace_cfg_struct)); + + chdlc_priv_area->start_trace_addr = trace_cfg_struct. + base_addr_trace_status_elements; + + chdlc_priv_area->number_trace_elements = + trace_cfg_struct.number_trace_status_elements; + + chdlc_priv_area->end_trace_addr = (unsigned long) + ((TRACE_STATUS_ELEMENT_STRUCT *) + chdlc_priv_area->start_trace_addr + + (chdlc_priv_area->number_trace_elements - 1)); + + chdlc_priv_area->base_addr_trace_buffer = + trace_cfg_struct.base_addr_trace_buffer; + + chdlc_priv_area->end_addr_trace_buffer = + trace_cfg_struct.end_addr_trace_buffer; + + chdlc_priv_area->curr_trace_addr = + trace_cfg_struct.next_trace_element_to_use; + + chdlc_priv_area->available_buffer_space = 2000 - + sizeof(struct iphdr) - + sizeof(struct udphdr) - + sizeof(wan_mgmt_t)- + sizeof(wan_cmd_t)- + sizeof(wan_trace_info_t); + } + + wan_udp_pkt->wan_udp_return_code = COMMAND_OK; + mb->wan_data_len = 0; + chdlc_priv_area->TracingEnabled = 1; + break; + + + case CPIPE_DISABLE_TRACING: + if (chdlc_priv_area->TracingEnabled) { + + /* OPERATE_DATALINE_MONITOR */ + mb->wan_data_len = sizeof(LINE_TRACE_CONFIG_STRUCT); + mb->wan_command = SET_TRACE_CONFIGURATION; + ((LINE_TRACE_CONFIG_STRUCT *)mb->wan_data)-> + trace_config = TRACE_INACTIVE; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + } + + chdlc_priv_area->TracingEnabled = 0; + wan_udp_pkt->wan_udp_return_code = COMMAND_OK; + mb->wan_data_len = 0; + break; + + + case CPIPE_GET_TRACE_INFO: + + if (!chdlc_priv_area->TracingEnabled) { + wan_udp_pkt->wan_udp_return_code = 1; + mb->wan_data_len = 0; + break; + } + + wan_udp_pkt->wan_udp_chdlc_ismoredata = 0x00; + buffer_length = 0; /* offset of packet already occupied */ + + for (frames=0; frames < chdlc_priv_area->number_trace_elements; frames++){ + + wan_trace_pkt_t *trace_pkt = (wan_trace_pkt_t *) + &wan_udp_pkt->wan_udp_data[buffer_length]; + + card->hw_iface.peek(card->hw, chdlc_priv_area->curr_trace_addr, + (unsigned char *)&trace_element_struct, + sizeof(TRACE_STATUS_ELEMENT_STRUCT)); + + if (trace_element_struct.opp_flag == 0x00) { + break; + } + + /* get pointer to real data */ + data_ptr = trace_element_struct.ptr_data_bfr; + + /* See if there is actual data on the trace buffer */ + if (data_ptr){ + data_length = trace_element_struct.trace_length; + }else{ + data_length = 0; + wan_udp_pkt->wan_udp_chdlc_ismoredata = 0x01; + } + + if( (chdlc_priv_area->available_buffer_space - buffer_length) + < ( sizeof(wan_trace_pkt_t) + data_length) ) { + + /* indicate there are more frames on board & exit */ + wan_udp_pkt->wan_udp_chdlc_ismoredata = 0x01; + break; + } + + trace_pkt->status = trace_element_struct.trace_type; + + trace_pkt->time_stamp = + trace_element_struct.trace_time_stamp; + + trace_pkt->real_length = + trace_element_struct.trace_length; + + do_gettimeofday(&tv); + trace_pkt->sec=tv.tv_sec; + trace_pkt->usec=tv.tv_usec; + + /* see if we can fit the frame into the user buffer */ + real_len = trace_pkt->real_length; + + if (data_ptr == 0) { + trace_pkt->data_avail = 0x00; + } else { + unsigned tmp = 0; + + /* get the data from circular buffer + must check for end of buffer */ + trace_pkt->data_avail = 0x01; + + if ((data_ptr + real_len) > + chdlc_priv_area->end_addr_trace_buffer + 1){ + + tmp = chdlc_priv_area->end_addr_trace_buffer - data_ptr + 1; + card->hw_iface.peek(card->hw, data_ptr, + trace_pkt->data,tmp); + data_ptr = chdlc_priv_area->base_addr_trace_buffer; + } + + card->hw_iface.peek(card->hw, data_ptr, + &trace_pkt->data[tmp], real_len - tmp); + } + + /* zero the opp flag to show we got the frame */ + card->hw_iface.poke_byte(card->hw, chdlc_priv_area->curr_trace_addr, 0x00); + + /* now move onto the next frame */ + chdlc_priv_area->curr_trace_addr += sizeof(TRACE_STATUS_ELEMENT_STRUCT); + + /* check if we went over the last address */ + if ( chdlc_priv_area->curr_trace_addr > chdlc_priv_area->end_trace_addr ) { + chdlc_priv_area->curr_trace_addr = chdlc_priv_area->start_trace_addr; + } + + if(trace_pkt->data_avail == 0x01) { + buffer_length += real_len; + } + + /* for the header */ + buffer_length += sizeof(wan_trace_pkt_t); + + } /* For Loop */ + + if (frames == chdlc_priv_area->number_trace_elements){ + wan_udp_pkt->wan_udp_chdlc_ismoredata = 0x01; + } + wan_udp_pkt->wan_udp_chdlc_num_frames = frames; + + mb->wan_data_len = buffer_length; + wan_udp_pkt->wan_udp_data_len = buffer_length; + + wan_udp_pkt->wan_udp_return_code = COMMAND_OK; + + break; + + + case CPIPE_FT1_READ_STATUS: + card->hw_iface.peek(card->hw, card->flags_off, &flags, sizeof(flags)); + ((unsigned char *)wan_udp_pkt->wan_udp_data )[0] = + flags.FT1_info_struct.parallel_port_A_input; + + ((unsigned char *)wan_udp_pkt->wan_udp_data )[1] = + flags.FT1_info_struct.parallel_port_B_input; + wan_udp_pkt->wan_udp_return_code = COMMAND_OK; + wan_udp_pkt->wan_udp_data_len = 2; + mb->wan_data_len = 2; + break; + + case CPIPE_ROUTER_UP_TIME: + do_gettimeofday( &tv ); + chdlc_priv_area->router_up_time = tv.tv_sec - + chdlc_priv_area->router_start_time; + *(unsigned long *)&wan_udp_pkt->wan_udp_data = + chdlc_priv_area->router_up_time; + mb->wan_data_len = sizeof(unsigned long); + wan_udp_pkt->wan_udp_data_len = sizeof(unsigned long); + wan_udp_pkt->wan_udp_return_code = COMMAND_OK; + break; + + case FT1_MONITOR_STATUS_CTRL: + /* Enable FT1 MONITOR STATUS */ + if ((wan_udp_pkt->wan_udp_data[0] & ENABLE_READ_FT1_STATUS) || + (wan_udp_pkt->wan_udp_data[0] & ENABLE_READ_FT1_OP_STATS)) { + + if( rCount++ != 0 ) { + wan_udp_pkt->wan_udp_return_code = COMMAND_OK; + mb->wan_data_len = 1; + break; + } + } + + /* Disable FT1 MONITOR STATUS */ + if( wan_udp_pkt->wan_udp_data[0] == 0) { + + if( --rCount != 0) { + wan_udp_pkt->wan_udp_return_code = COMMAND_OK; + mb->wan_data_len = 1; + break; + } + } + goto dflt_1; + + case WAN_GET_MEDIA_TYPE: + case WAN_FE_GET_STAT: + case WAN_FE_SET_LB_MODE: + case WAN_FE_FLUSH_PMON: + case WAN_FE_GET_CFG: + if (IS_TE1_CARD(card)){ + card->wandev.fe_iface.process_udp( + &card->fe, + &wan_udp_pkt->wan_udp_cmd, + &wan_udp_pkt->wan_udp_data[0]); + }else if (IS_56K_CARD(card)){ + card->wandev.fe_iface.process_udp( + &card->fe, + &wan_udp_pkt->wan_udp_cmd, + &wan_udp_pkt->wan_udp_data[0]); + }else{ + if (wan_udp_pkt->wan_udp_command == WAN_GET_MEDIA_TYPE){ + wan_udp_pkt->wan_udp_data_len = sizeof(unsigned char); + wan_udp_pkt->wan_udp_return_code = CMD_OK; + }else{ + wan_udp_pkt->wan_udp_return_code = WAN_UDP_INVALID_CMD; + } + } + mb->wan_data_len = wan_udp_pkt->wan_udp_data_len; + break; + + case WAN_GET_PROTOCOL: + wan_udp_pkt->wan_udp_chdlc_num_frames = card->wandev.config_id; + wan_udp_pkt->wan_udp_return_code = CMD_OK; + mb->wan_data_len = wan_udp_pkt->wan_udp_data_len = 1; + break; + + case WAN_GET_PLATFORM: + wan_udp_pkt->wan_udp_data[0] = WAN_LINUX_PLATFORM; + wan_udp_pkt->wan_udp_return_code = CMD_OK; + mb->wan_data_len = wan_udp_pkt->wan_udp_data_len = 1; + break; + + default: +dflt_1: + /* it's a board command */ + mb->wan_command = wan_udp_pkt->wan_udp_command; + mb->wan_data_len = wan_udp_pkt->wan_udp_data_len; + if (mb->wan_data_len) { + memcpy(&mb->wan_data, (unsigned char *) wan_udp_pkt-> + wan_udp_data, mb->wan_data_len); + } + + /* run the command on the board */ + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != COMMAND_OK) { + chdlc_error(card,err,mb); + wan_udp_pkt->wan_udp_return_code = mb->wan_return_code; + break; + } + + /* copy the result back to our buffer */ + memcpy(&wan_udp_pkt->wan_udp_hdr.wan_cmd, mb, sizeof(wan_cmd_t)); + + if (mb->wan_data_len) { + memcpy(&wan_udp_pkt->wan_udp_data, &mb->wan_data, + mb->wan_data_len); + } + + } /* end of switch */ + } /* end of else */ + + /* Fill UDP TTL */ + wan_udp_pkt->wan_ip_ttl= card->wandev.ttl; + + if (local_dev){ + wan_udp_pkt->wan_udp_request_reply = UDPMGMT_REPLY; + return 1; + } + + len = reply_udp(chdlc_priv_area->udp_pkt_data, mb->wan_data_len); + + if(chdlc_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK){ + + /* Must check if we interrupted if_send() routine. The + * tx buffers might be used. If so drop the packet */ + if (!test_bit(SEND_CRIT,&card->wandev.critical)) { + + if(!chdlc_send(card, chdlc_priv_area->udp_pkt_data, len, 0)) { + ++ card->wandev.stats.tx_packets; + card->wandev.stats.tx_bytes += len; + } + } + } else { + + /* Pass it up the stack + Allocate socket buffer */ + if ((new_skb = dev_alloc_skb(len)) != NULL) { + /* copy data into new_skb */ + + buf = skb_put(new_skb, len); + memcpy(buf, chdlc_priv_area->udp_pkt_data, len); + + /* Decapsulate pkt and pass it up the protocol stack */ + new_skb->protocol = htons(ETH_P_IP); + new_skb->dev = dev; + new_skb->mac.raw = new_skb->data; + + netif_rx(new_skb); + } else { + + printk(KERN_INFO "%s: no socket buffers available!\n", + card->devname); + } + } + + atomic_set(&chdlc_priv_area->udp_pkt_len,0); + + return 0; +} + +/*============================================================================ + * Initialize Receive and Transmit Buffers. + */ + +static void init_chdlc_tx_rx_buff( sdla_t* card) +{ + wan_mbox_t *mb = &card->wan_mbox; + unsigned long tx_config_off; + unsigned long rx_config_off; + CHDLC_TX_STATUS_EL_CFG_STRUCT tx_config; + CHDLC_RX_STATUS_EL_CFG_STRUCT rx_config; + char err; + + mb->wan_data_len = 0; + mb->wan_command = READ_CHDLC_CONFIGURATION; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + + if(err != COMMAND_OK) { + netdevice_t *dev; + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + if (dev){ + chdlc_error(card,err,mb); + } + return; + } + + /* ALEX: Apr 8 2004 SANGOMA ISA CARD */ + tx_config_off = + ((CHDLC_CONFIGURATION_STRUCT *)mb->wan_data)-> + ptr_CHDLC_Tx_stat_el_cfg_struct; + rx_config_off = + ((CHDLC_CONFIGURATION_STRUCT *)mb->wan_data)-> + ptr_CHDLC_Rx_stat_el_cfg_struct; + /* Setup Head and Tails for buffers */ + card->hw_iface.peek(card->hw, tx_config_off, &tx_config, sizeof(tx_config)); + card->u.c.txbuf_base_off = tx_config.base_addr_Tx_status_elements; + card->u.c.txbuf_last_off = + card->u.c.txbuf_base_off + + (tx_config.number_Tx_status_elements - 1) * + sizeof(CHDLC_DATA_TX_STATUS_EL_STRUCT); + card->hw_iface.peek(card->hw, rx_config_off, &rx_config, sizeof(rx_config)); + card->u.c.rxbuf_base_off = + rx_config.base_addr_Rx_status_elements; + card->u.c.rxbuf_last_off = + card->u.c.rxbuf_base_off + + (rx_config.number_Rx_status_elements - 1) * + sizeof(CHDLC_DATA_RX_STATUS_EL_STRUCT); + /* Set up next pointer to be used */ + card->u.c.txbuf_off = tx_config.next_Tx_status_element_to_use; + card->u.c.rxmb_off = + rx_config.next_Rx_status_element_to_use; + + /* Setup Actual Buffer Start and end addresses */ + card->u.c.rx_base_off = rx_config.base_addr_Rx_buffer; + card->u.c.rx_top_off = rx_config.end_addr_Rx_buffer; + +} + +/*============================================================================= + * Perform Interrupt Test by running READ_CHDLC_CODE_VERSION command MAX_INTR + * _TEST_COUNTER times. + */ +static int intr_test( sdla_t* card) +{ + wan_mbox_t* mb = &card->wan_mbox; + int err,i; + + card->timer_int_enabled = 0; + + err = chdlc_set_intr_mode(card, APP_INT_ON_COMMAND_COMPLETE); + + if (err == CMD_OK) { + for (i = 0; i < MAX_INTR_TEST_COUNTER; i ++) { + + mb->wan_data_len = 0; + mb->wan_command = READ_CHDLC_CODE_VERSION; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != CMD_OK) + chdlc_error(card, err, mb); + } + }else{ + return err; + } + +// udelay(2000); +// schedule(); +// udelay(2000); + + card->hw_iface.poke_byte(card->hw, card->intr_type_off, 0x00); + err = chdlc_set_intr_mode(card, 0); + + if (err != CMD_OK) + return err; + + return 0; +} + +/*============================================================================== + * Determine what type of UDP call it is. CPIPEAB ? + */ +static int udp_pkt_type(struct sk_buff *skb, sdla_t* card) +{ + wan_udp_pkt_t *wan_udp_pkt = (wan_udp_pkt_t *)skb->data; + + if (skb->len < sizeof(wan_udp_pkt_t)){ + return UDP_INVALID_TYPE; + } + +#ifdef _WAN_UDP_DEBUG + printk(KERN_INFO "SIG %s = %s\n\ + UPP %x = %x\n\ + PRT %x = %x\n\ + REQ %i = %i\n\ + 36 th = %x 37th = %x\n", + wan_udp_pkt->wan_udp_signature, + UDPMGMT_SIGNATURE, + wan_udp_pkt->wan_udp_dport, + ntohs(card->wandev.udp_port), + wan_udp_pkt->wan_ip_p, + UDPMGMT_UDP_PROTOCOL, + wan_udp_pkt->wan_udp_request_reply, + UDPMGMT_REQUEST, + skb->data[36], skb->data[37]); +#endif + + if ((wan_udp_pkt->wan_udp_dport == ntohs(card->wandev.udp_port)) && + (wan_udp_pkt->wan_ip_p == UDPMGMT_UDP_PROTOCOL) && + (wan_udp_pkt->wan_udp_request_reply == UDPMGMT_REQUEST)) { + if (!strncmp(wan_udp_pkt->wan_udp_signature,UDPMGMT_SIGNATURE,8)){ + return UDP_CPIPE_TYPE; + } + if (!strncmp(wan_udp_pkt->wan_udp_signature,GLOBAL_UDP_SIGNATURE,8)){ + return UDP_CPIPE_TYPE; + } + } + return UDP_INVALID_TYPE; +} + +/*============================================================================ + * Set PORT state. + */ +static void port_set_state (sdla_t *card, int state) +{ + netdevice_t *dev; + + if (card->wandev.state != state) + { + switch (state) + { + case WAN_CONNECTED: + printk (KERN_INFO "%s: Link connected!\n", + card->devname); + break; + + case WAN_CONNECTING: + printk (KERN_INFO "%s: Link connecting...\n", + card->devname); + break; + + case WAN_DISCONNECTED: + printk (KERN_INFO "%s: Link disconnected!\n", + card->devname); + break; + } + + card->wandev.state = state; + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + if (dev && wan_netif_priv(dev)){ + chdlc_private_area_t *chdlc_priv_area = wan_netif_priv(dev); + chdlc_priv_area->common.state = state; + if (chdlc_priv_area->common.usedby == API){ + wan_update_api_state(chdlc_priv_area); + } + } + } +} + +/*=========================================================================== + * config_chdlc + * + * Configure the chdlc protocol and enable communications. + * + * The if_open() function binds this function to the poll routine. + * Therefore, this function will run every time the chdlc interface + * is brought up. We cannot run this function from the if_open + * because if_open does not have access to the remote IP address. + * + * If the communications are not enabled, proceed to configure + * the card and enable communications. + * + * If the communications are enabled, it means that the interface + * was shutdown by ether the user or driver. In this case, we + * have to check that the IP addresses have not changed. If + * the IP addresses have changed, we have to reconfigure the firmware + * and update the changed IP addresses. Otherwise, just exit. + * + */ + +static int config_chdlc (sdla_t *card, netdevice_t *dev) +{ + chdlc_private_area_t *chdlc_priv_area = wan_netif_priv(dev); + if (card->u.c.comm_enabled){ + + /* Jun 20. 2000: NC + * IP addresses are not used in the API mode */ + + if ((chdlc_priv_area->ip_local_tmp != chdlc_priv_area->ip_local || + chdlc_priv_area->ip_remote_tmp != chdlc_priv_area->ip_remote) && + chdlc_priv_area->common.usedby == WANPIPE) { + + /* The IP addersses have changed, we must + * stop the communications and reconfigure + * the card. Reason: the firmware must know + * the local and remote IP addresses. */ + disable_comm(card); + card->u.c.state = WAN_DISCONNECTED; + port_set_state(card, WAN_DISCONNECTED); + printk(KERN_INFO + "%s: IP addresses changed!\n", + card->devname); + printk(KERN_INFO + "%s: Restarting communications ...\n", + card->devname); + }else{ + /* IP addresses are the same and the link is up, + * we dont have to do anything here. Therefore, exit */ + return 0; + } + } + + chdlc_priv_area->ip_local = chdlc_priv_area->ip_local_tmp; + chdlc_priv_area->ip_remote = chdlc_priv_area->ip_remote_tmp; + + /* Setup the Board for asynchronous mode */ + if (card->u.c.async_mode){ + + if (set_asy_config(card)) { + printk (KERN_INFO "%s: Failed CHDLC Async configuration!\n", + card->devname); + return 0; + } + }else{ + /* Setup the Board for CHDLC */ + if (set_chdlc_config(card)) { + printk (KERN_INFO "%s: Failed CHDLC configuration!\n", + card->devname); + return 0; + } + + /* If baud rate external and set to + * idle mark or switching cts/rts then + * calibrate baud rate */ + if (card->wandev.clocking == WANOPT_EXTERNAL && + (card->wandev.line_idle == WANOPT_IDLE_MARK || + card->wandev.connection == WANOPT_SWITCHED)){ + + printk(KERN_INFO "%s: Calibrating Baud Rate ...\n",card->devname); + if (chdlc_calibrate_baud(card) != COMMAND_OK) + return -EINVAL; + + if (chdlc_read_baud_calibration(card)!= COMMAND_OK) + return -EINVAL; + } + } + + card->hw_iface.poke_byte(card->hw, card->intr_type_off, 0x00); + card->hw_iface.poke_byte(card->hw, card->intr_perm_off, 0x00); + + if (IS_TE1_CARD(card)) { + int err = -EINVAL; + printk(KERN_INFO "%s: Configuring onboard %s CSU/DSU\n", + card->devname, + (IS_T1_CARD(card))?"T1":"E1"); + if (card->wandev.fe_iface.config){ + err = card->wandev.fe_iface.config(&card->fe); + } + if (err){ + printk(KERN_INFO "%s: Failed %s configuratoin!\n", + card->devname, + (IS_T1_CARD(card))?"T1":"E1"); + return -EINVAL; + } + } + + + if (IS_56K_CARD(card)) { + int err = -EINVAL; + printk(KERN_INFO "%s: Configuring 56K onboard CSU/DSU\n", + card->devname); + + if (card->wandev.fe_iface.config){ + err = card->wandev.fe_iface.config(&card->fe); + } + if(err) { + printk (KERN_INFO "%s: Failed 56K configuration!\n", + card->devname); + return -EINVAL; + } + } + + + /* Set interrupt mode and mask */ + if (chdlc_set_intr_mode(card, APP_INT_ON_RX_FRAME | + APP_INT_ON_GLOBAL_EXCEP_COND | + APP_INT_ON_TX_FRAME | + APP_INT_ON_CHDLC_EXCEP_COND | APP_INT_ON_TIMER)){ + printk (KERN_INFO "%s: Failed to set interrupt triggers!\n", + card->devname); + return -EINVAL; + } + + /* Mask All interrupts */ + card->hw_iface.clear_bit(card->hw, card->intr_perm_off, + (APP_INT_ON_RX_FRAME | APP_INT_ON_TX_FRAME | + APP_INT_ON_TIMER | APP_INT_ON_GLOBAL_EXCEP_COND | + APP_INT_ON_CHDLC_EXCEP_COND)); + + /* In TTY mode, receive interrupt will be enabled during + * wanpipe_tty_open() operation */ + if (card->tty_opt){ + card->hw_iface.clear_bit(card->hw, card->intr_perm_off, APP_INT_ON_RX_FRAME); + } + + if(IS_TE1_CARD(card) && card->wandev.ignore_front_end_status == WANOPT_NO) { + /* Do not enable comms here, wait for TE1 + * to come up first */ + }else{ + /* Enable communications */ + if (card->u.c.async_mode){ + if (asy_comm_enable(card) != 0) { + printk(KERN_INFO "%s: Failed to enable async commnunication!\n", + card->devname); + card->hw_iface.poke_byte(card->hw, card->intr_perm_off, 0x00); + card->u.c.comm_enabled=0; + chdlc_set_intr_mode(card,0); + return -EINVAL; + } + }else{ + if (chdlc_comm_enable(card) != 0) { + printk(KERN_INFO "%s: Failed to enable chdlc communications!\n", + card->devname); + card->hw_iface.poke_byte(card->hw, card->intr_perm_off, 0x00); + card->u.c.comm_enabled=0; + chdlc_set_intr_mode(card,0); + return -EINVAL; + } + } + + DEBUG_EVENT("%s: Communications enabled on startup\n", + card->devname); + } + + /* Initialize Rx/Tx buffer control fields */ + init_chdlc_tx_rx_buff(card); + card->u.c.state = WAN_CONNECTING; + port_set_state(card, WAN_CONNECTING); + + /* Manually poll the 56K CSU/DSU to get the status */ + if (IS_56K_CARD(card)) { + /* 56K Update CSU/DSU alarms */ + card->wandev.fe_iface.read_alarm(&card->fe, 1); + } + + /* Unmask all interrupts except the Transmit and Timer interrupts */ + card->hw_iface.set_bit(card->hw, card->intr_perm_off, + (APP_INT_ON_RX_FRAME | APP_INT_ON_GLOBAL_EXCEP_COND | APP_INT_ON_CHDLC_EXCEP_COND)); + card->hw_iface.poke_byte(card->hw, card->intr_type_off, 0x00); + return 0; +} + + +/*============================================================ + * chdlc_poll + * + * Rationale: + * We cannot manipulate the routing tables, or + * ip addresses withing the interrupt. Therefore + * we must perform such actons outside an interrupt + * at a later time. + * + * Description: + * CHDLC polling routine, responsible for + * shutting down interfaces upon disconnect + * and adding/removing routes. + * + * Usage: + * This function is executed for each CHDLC + * interface through a tq_schedule bottom half. + * + * trigger_chdlc_poll() function is used to kick + * the chldc_poll routine. + */ + +static void chdlc_poll (void *dev_ptr) +{ + netdevice_t *dev=dev_ptr; + chdlc_private_area_t *chdlc_priv_area; + sdla_t *card; + u8 check_gateway=0; + SHARED_MEMORY_INFO_STRUCT flags; + + if (!dev || (chdlc_priv_area = wan_netif_priv(dev)) == NULL){ + return; + } + + card = chdlc_priv_area->card; + card->hw_iface.peek(card->hw, card->flags_off, &flags, sizeof(flags)); + + /* (Re)Configuraiton is in progress, stop what you are + * doing and get out */ + if (test_bit(PERI_CRIT,&card->wandev.critical)){ + clear_bit(POLL_CRIT,&card->wandev.critical); + return; + } + + /* if_open() function has triggered the polling routine + * to determine the configured IP addresses. Once the + * addresses are found, trigger the chdlc configuration */ + if (test_bit(0,&chdlc_priv_area->config_chdlc)){ + + chdlc_priv_area->ip_local_tmp = get_ip_address(dev,WAN_LOCAL_IP); + chdlc_priv_area->ip_remote_tmp = get_ip_address(dev,WAN_POINTOPOINT_IP); + + /* Jun 20. 2000 Bug Fix + * Only perform this check in WANPIPE mode, since + * IP addresses are not used in the API mode. */ + + if (chdlc_priv_area->ip_local_tmp == chdlc_priv_area->ip_remote_tmp && + card->u.c.slarp_timer == 0x00 && + !card->u.c.backup && + chdlc_priv_area->common.usedby == WANPIPE){ + + if (++chdlc_priv_area->ip_error > MAX_IP_ERRORS){ + printk(KERN_INFO "\n"); + printk(KERN_INFO "%s: --- WARNING ---\n", + card->devname); + printk(KERN_INFO + "%s: The local IP address is the same as the\n", + card->devname); + printk(KERN_INFO + "%s: Point-to-Point IP address.\n", + card->devname); + printk(KERN_INFO "%s: --- WARNING ---\n\n", + card->devname); + }else{ + clear_bit(POLL_CRIT,&card->wandev.critical); + chdlc_priv_area->poll_delay_timer.expires = jiffies+HZ; + add_timer(&chdlc_priv_area->poll_delay_timer); + return; + } + } + + clear_bit(0,&chdlc_priv_area->config_chdlc); + clear_bit(POLL_CRIT,&card->wandev.critical); + + card->u.c.timer_int_enabled |= TMR_INT_ENABLED_CONFIG; + flags.interrupt_info_struct.interrupt_permission |= APP_INT_ON_TIMER; + card->hw_iface.poke(card->hw, card->flags_off, &flags, sizeof(flags)); + return; + } + /* Dynamic interface implementation, as well as dynamic + * routing. */ + + switch (card->wandev.state){ + + case WAN_DISCONNECTED: + + /* If the dynamic interface configuration is on, and interface + * is up, then bring down the netowrk interface */ + + if (test_bit(DYN_OPT_ON,&chdlc_priv_area->interface_down) && + !test_bit(DEV_DOWN, &chdlc_priv_area->interface_down) && + dev->flags & IFF_UP){ + + printk(KERN_INFO "%s: Interface %s down.\n", + card->devname,dev->name); + change_dev_flags(dev,(dev->flags&~IFF_UP)); + set_bit(DEV_DOWN,&chdlc_priv_area->interface_down); + chdlc_priv_area->route_status = NO_ROUTE; + + }else{ + /* We need to check if the local IP address is + * zero. If it is, we shouldn't try to remove it. + */ + + if (dev->flags & IFF_UP && + get_ip_address(dev,WAN_LOCAL_IP) && + chdlc_priv_area->route_status != NO_ROUTE && + card->u.c.slarp_timer){ + + process_route(card); + } + } + + break; + + case WAN_CONNECTED: + + /* In SMP machine this code can execute before the interface + * comes up. In this case, we must make sure that we do not + * try to bring up the interface before dev_open() is finished */ + + + /* DEV_DOWN will be set only when we bring down the interface + * for the very first time. This way we know that it was us + * that brought the interface down */ + + if (test_bit(DYN_OPT_ON,&chdlc_priv_area->interface_down) && + test_bit(DEV_DOWN, &chdlc_priv_area->interface_down) && + !(dev->flags & IFF_UP)){ + + printk(KERN_INFO "%s: Interface %s up.\n", + card->devname,dev->name); + change_dev_flags(dev,(dev->flags|IFF_UP)); + clear_bit(DEV_DOWN,&chdlc_priv_area->interface_down); + check_gateway=1; + } + + if (chdlc_priv_area->route_status == ADD_ROUTE && + card->u.c.slarp_timer){ + + process_route(card); + check_gateway=1; + } + + if (chdlc_priv_area->gateway && check_gateway) + add_gateway(card,dev); + + break; + } + + clear_bit(POLL_CRIT,&card->wandev.critical); +} + +/*============================================================ + * trigger_chdlc_poll + * + * Description: + * Add a chdlc_poll() task into a tq_scheduler bh handler + * for a specific dlci/interface. This will kick + * the fr_poll() routine at a later time. + * + * Usage: + * Interrupts use this to defer a taks to + * a polling routine. + * + */ +static void trigger_chdlc_poll (netdevice_t *dev) +{ + chdlc_private_area_t *chdlc_priv_area; + sdla_t *card; + + if (!dev) + return; + + if ((chdlc_priv_area = dev->priv)==NULL) + return; + + card = chdlc_priv_area->card; + + if (test_and_set_bit(POLL_CRIT,&card->wandev.critical)){ + return; + } + if (test_bit(PERI_CRIT,&card->wandev.critical)){ + return; + } + wan_schedule_task(&chdlc_priv_area->poll_task); + return; +} + + +static void chdlc_poll_delay (unsigned long dev_ptr) +{ + netdevice_t *dev = (netdevice_t *)dev_ptr; + trigger_chdlc_poll(dev); +} + + +static int set_adapter_config (sdla_t* card) +{ + wan_mbox_t* mb = &card->wan_mbox; + ADAPTER_CONFIGURATION_STRUCT* cfg = (ADAPTER_CONFIGURATION_STRUCT*)mb->wan_data; + int err; + + card->hw_iface.getcfg(card->hw, SDLA_ADAPTERTYPE, &cfg->adapter_type); + cfg->adapter_config = 0x00; + cfg->operating_frequency = 00; + mb->wan_data_len = sizeof(ADAPTER_CONFIGURATION_STRUCT); + mb->wan_command = SET_ADAPTER_CONFIGURATION; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + + if(err != COMMAND_OK) { + chdlc_error(card,err,mb); + } + return (err); +} + + +void s508_lock (sdla_t *card, unsigned long *smp_flags) +{ + spin_lock_irqsave(&card->wandev.lock, *smp_flags); + if (card->next){ + spin_lock(&card->next->wandev.lock); + } +} + +void s508_unlock (sdla_t *card, unsigned long *smp_flags) +{ + if (card->next){ + spin_unlock(&card->next->wandev.lock); + } + spin_unlock_irqrestore(&card->wandev.lock, *smp_flags); +} + +//*********** TTY SECTION **************** + +#if 1 +//defined(LINUX_2_4) || defined(LINUX_2_1) + +static void wanpipe_tty_trigger_tx_irq(sdla_t *card) +{ + card->hw_iface.set_bit(card->hw, card->intr_perm_off, APP_INT_ON_TX_FRAME); +} + +static int wanpipe_tty_trigger_poll(sdla_t *card) +{ + if (test_and_set_bit(TASK_POLL,(void*)&card->wandev.critical)){ + return 0; + } + + if (wanpipe_queue_tq(&card->tty_task_queue) != 0){ + clear_bit(TASK_POLL,(void*)&card->wandev.critical); + return -EINVAL; + } + + if (wanpipe_mark_bh() != 0){ + clear_bit(TASK_POLL,(void*)&card->wandev.critical); + return -EINVAL; + } + return 0; +} + +static void tty_poll_task (void* data) +{ + sdla_t *card = (sdla_t*)data; + struct tty_struct *tty; + struct sk_buff *skb; + char fp=0; + + clear_bit(TASK_POLL,(void*)&card->wandev.critical); + + if ((tty=card->tty)==NULL) + return; + + while ((skb=skb_dequeue(&card->tty_rx_full)) != NULL){ + if (tty->ldisc.receive_buf){ + tty->ldisc.receive_buf(tty,skb->data,&fp,skb->len); + } + skb_trim(skb,0); + skb_queue_tail(&card->tty_rx_empty,skb); + } + + if (test_and_clear_bit(TX_INTR,(void*)&card->wandev.critical)){ + + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup){ + (tty->ldisc.write_wakeup)(tty); + } + wake_up_interruptible(&tty->write_wait); +#if defined(SERIAL_HAVE_POLL_WAIT) || \ + (defined LINUX_2_1 && LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,15)) + wake_up_interruptible(&tty->poll_wait); +#endif + } + return; +} + +static void wanpipe_tty_close(struct tty_struct *tty, struct file * filp) +{ + sdla_t *card; + unsigned long smp_flags; + + if (!tty || !tty->driver_data){ + return; + } + + card = (sdla_t*)tty->driver_data; + + if (!card) + return; + + printk(KERN_INFO "%s: Closing TTY Driver!\n", + card->devname); + + /* Sanity Check */ + if (!card->tty_open) + return; + + wanpipe_close(card); + if (--card->tty_open == 0){ + + struct sk_buff *skb; + + wan_spin_lock_irq(&card->wandev.lock,&smp_flags); + card->tty=NULL; + chdlc_disable_comm_shutdown(card); + + if (card->tty_buf){ + kfree(card->tty_buf); + card->tty_buf=NULL; + } + + while ((skb=skb_dequeue(&card->tty_rx_empty)) != NULL){ + wan_skb_free(skb); + } + + while ((skb=skb_dequeue(&card->tty_rx_full)) != NULL){ + wan_skb_free(skb); + } + + /* BUGFIX: Moved down here */ + wan_spin_unlock_irq(&card->wandev.lock,&smp_flags); + } + return; +} +static int wanpipe_tty_open(struct tty_struct *tty, struct file * filp) +{ + unsigned long smp_flags; + sdla_t *card; + + if (!tty){ + return -ENODEV; + } + + if (!tty->driver_data){ + int port; +#ifdef LINUX_2_6 + port = tty->index; +#else + port = MINOR(tty->device) - tty->driver.minor_start; +#endif + if ((port < 0) || (port >= NR_PORTS)) + return -ENODEV; + + tty->driver_data = WAN_CARD(port); + if (!tty->driver_data) + return -ENODEV; + } + + card = (sdla_t*)tty->driver_data; + + if (!card){ + wan_spin_lock_irq(&card->wandev.lock,&smp_flags); + card->tty=NULL; + wan_spin_unlock_irq(&card->wandev.lock,&smp_flags); + return -ENODEV; + } + + printk(KERN_INFO "%s: Opening TTY Driver!\n", + card->devname); + + if (card->tty_open == 0){ + struct sk_buff *skb; + int i; + + wan_spin_lock_irq(&card->wandev.lock,&smp_flags); + card->tty=tty; + wan_spin_unlock_irq(&card->wandev.lock,&smp_flags); + + if (!card->tty_buf){ + card->tty_buf = kmalloc(TTY_CHDLC_MAX_MTU, GFP_KERNEL); + if (!card->tty_buf){ + card->tty_buf=NULL; + card->tty=NULL; + return -ENOMEM; + } + } + + skb_queue_head_init(&card->tty_rx_empty); + skb_queue_head_init(&card->tty_rx_full); + + for (i=0;itty_rx_empty)) != NULL){ + wan_skb_free(skb); + } + kfree(card->tty_buf); + card->tty_buf=NULL; + card->tty=NULL; + return -ENOMEM; + } + skb_queue_tail(&card->tty_rx_empty,skb); + } + clear_bit(TTY_HANGUP,&card->wandev.critical); + } + + ++card->tty_open; + wanpipe_open(card); + return 0; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10) +static int wanpipe_tty_write(struct tty_struct * tty, + const unsigned char *buf, int count) +#else +static int wanpipe_tty_write(struct tty_struct * tty, int from_user, + const unsigned char *buf, int count) +#endif +{ + unsigned long smp_flags=0; + sdla_t *card=NULL; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10) + int from_user=0; +#endif + + if (!tty){ + DEBUG_TEST("NO TTY in Write\n"); + return -ENODEV; + } + + card = (sdla_t *)tty->driver_data; + + if (!card){ + DEBUG_TEST("No Card in TTY Write\n"); + return -ENODEV; + } + + if (count > card->wandev.mtu){ + DEBUG_TEST("Frame too big in Write %i Max: %i\n", + count,card->wandev.mtu); + return -EINVAL; + } + + if (card->wandev.state != WAN_CONNECTED){ + DEBUG_TEST("Card not connected in TTY Write\n"); + return -EINVAL; + } + + /* Lock the 508 Card: SMP is supported */ + if(card->type != SDLA_S514){ + s508_lock(card,&smp_flags); + } + + if (test_and_set_bit(SEND_CRIT,(void*)&card->wandev.critical)){ + printk(KERN_INFO "%s: Critical in TTY Write\n", + card->devname); + + /* Lock the 508 Card: SMP is supported */ + if(card->type != SDLA_S514) + s508_unlock(card,&smp_flags); + + return -EINVAL; + } + + if (from_user) { + + unsigned char *tmp_buf; + + if ((tmp_buf=card->tty_buf)==NULL){ + DEBUG_TEST("No TTY BUF in Write\n"); + + clear_bit(SEND_CRIT,(void*)&card->wandev.critical); + + if(card->type != SDLA_S514) + s508_unlock(card,&smp_flags); + + return -ENOMEM; + } + + if (copy_from_user(tmp_buf,buf,count)){ + DEBUG_TEST("%s: Failed to copy from user!\n", + card->devname); + + clear_bit(SEND_CRIT,(void*)&card->wandev.critical); + + if(card->type != SDLA_S514) + s508_unlock(card,&smp_flags); + + return -EINVAL; + } + + if (chdlc_send(card,(void*)tmp_buf,count,0)){ + DEBUG_TEST("%s: Failed to send, retry later: user!\n", + card->devname); + + clear_bit(SEND_CRIT,(void*)&card->wandev.critical); + + wanpipe_tty_trigger_tx_irq(card); + + if(card->type != SDLA_S514) + s508_unlock(card,&smp_flags); + return 0; + } + + }else{ + if (chdlc_send(card,(void*)buf,count,0)){ + DEBUG_TEST("%s: Failed to send, retry later: kernel!\n", + card->devname); + clear_bit(SEND_CRIT,(void*)&card->wandev.critical); + + wanpipe_tty_trigger_tx_irq(card); + + if(card->type != SDLA_S514) + s508_unlock(card,&smp_flags); + return 0; + } + } + DEBUG_TEST("%s: Packet sent OK: %i\n",card->devname,count); + clear_bit(SEND_CRIT,(void*)&card->wandev.critical); + + if(card->type != SDLA_S514) + s508_unlock(card,&smp_flags); + + return count; +} + +static void wanpipe_tty_receive(sdla_t *card, unsigned addr, unsigned int len) +{ + unsigned offset=0; + struct tty_struct *tty; + int i; + + i=0; + + if (!card->tty_open){ + DEBUG_TEST("%s: TTY not open during receive\n", + card->devname); + return; + } + + if ((tty=card->tty) == NULL){ + DEBUG_TEST("%s: No TTY on receive\n", + card->devname); + return; + } + + if (!tty->driver_data){ + DEBUG_TEST("%s: No Driver Data, or Flip on receive\n", + card->devname); + return; + } + + + if (card->u.c.async_mode){ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15) + unsigned char *buf; + struct sk_buff *skb; + +#if 1 +# warning "FIXME: Compilation error on 2.6.15 kernel" +#else + if (len > TTY_CHDLC_MAX_MTU){ + if (net_ratelimit()){ + printk(KERN_INFO + "%s: Received packet size too big: %i bytes, Max: %i!\n", + card->devname,len,TTY_FLIPBUF_SIZE); + } + return; + } + + skb=skb_dequeue(&card->tty_rx_empty); + if (skb == NULL){ + return; + } +#endif +#else + if ((tty->flip.count+len) >= TTY_FLIPBUF_SIZE){ + if (net_ratelimit()){ + printk(KERN_INFO + "%s: Received packet size too big: %i bytes, Max: %i!\n", + card->devname,len,TTY_FLIPBUF_SIZE); + } + return; + } + +#endif + if((addr + len) > card->u.c.rx_top_off + 1) { + offset = card->u.c.rx_top_off - addr + 1; + + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15) +#if 1 +# warning "FIXME: Compilation error on 2.6.15 kernel" +#else + buf=skb_put(skb,offset); + card->hw_iface.peek(card->hw, addr, buf, offset); + + addr = card->u.c.rx_base_off; + len -= offset; + + tty_insert_flip_string(tty,buf,offset); +#endif +#else + card->hw_iface.peek(card->hw, addr, tty->flip.char_buf_ptr, offset); + + addr = card->u.c.rx_base_off; + len -= offset; + + + tty->flip.char_buf_ptr+=offset; + tty->flip.count+=offset; + for (i=0;iflip.flag_buf_ptr = 0; + tty->flip.flag_buf_ptr++; + } +#endif + } + + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15) +#if 1 +# warning "FIXME: Compilation error on 2.6.15 kernel" +#else + buf=skb_put(skb,len); + card->hw_iface.peek(card->hw, addr, buf, len); + + tty_insert_flip_string(tty,buf,len); + + skb_trim(skb,0); + skb_queue_tail(&card->tty_rx_empty,skb); +#endif +#else + card->hw_iface.peek(card->hw, addr, tty->flip.char_buf_ptr, len); + + tty->flip.char_buf_ptr+=len; + card->tty->flip.count+=len; + for (i=0;iflip.flag_buf_ptr = 0; + tty->flip.flag_buf_ptr++; + } +#endif + tty->low_latency=1; + tty_flip_buffer_push(tty); + + }else{ + if (len > TTY_CHDLC_MAX_MTU){ + if (net_ratelimit()){ + printk(KERN_INFO + "%s: Received packet size too big: %i bytes, Max: %i!\n", + card->devname,len,TTY_FLIPBUF_SIZE); + } + return; + } + + { + unsigned char *buf; + struct sk_buff *skb; + + /* If there are no free buffers, then + * drop the incoming packet. This is ok + * though because TCP/IP will recover */ + skb=skb_dequeue(&card->tty_rx_empty); + if (skb == NULL){ + wanpipe_tty_trigger_poll(card); + return; + } + + if((addr + len) > card->u.c.rx_top_off + 1) { + offset = card->u.c.rx_top_off - addr + 1; + buf=skb_put(skb,offset); + + card->hw_iface.peek(card->hw, addr, buf, offset); + + addr = card->u.c.rx_base_off; + len -= offset; + } + + buf=skb_put(skb,len); + card->hw_iface.peek(card->hw, addr, buf, len); + + skb_queue_tail(&card->tty_rx_full,skb); + wanpipe_tty_trigger_poll(card); + } + } + + return; +} + +#if 0 +static int wanpipe_tty_ioctl(struct tty_struct *tty, struct file * file, + unsigned int cmd, unsigned long arg) +{ + return -ENOIOCTLCMD; +} +#endif + +static void wanpipe_tty_stop(struct tty_struct *tty) +{ + return; +} + +static void wanpipe_tty_start(struct tty_struct *tty) +{ + return; +} + + +static int config_tty (sdla_t *card) +{ + + /* Setup the Board for asynchronous mode */ + if (card->u.c.async_mode){ + + if (set_asy_config(card)) { + printk (KERN_INFO "%s: Failed CHDLC Async configuration!\n", + card->devname); + return -EINVAL; + } + }else{ + /* Setup the Board for CHDLC */ + if (set_chdlc_config(card)) { + printk (KERN_INFO "%s: Failed CHDLC configuration!\n", + card->devname); + return -EINVAL; + } + } + + card->hw_iface.poke_byte(card->hw, card->intr_type_off, 0x00); + card->hw_iface.poke_byte(card->hw, card->intr_perm_off, 0x00); + + if (IS_TE1_CARD(card)) { + int err = -EINVAL; + printk(KERN_INFO "%s: Configuring onboard %s CSU/DSU\n", + card->devname, + (IS_T1_CARD(card))?"T1":"E1"); + if (card->wandev.fe_iface.config){ + err = card->wandev.fe_iface.config(&card->fe); + } + if (err){ + printk(KERN_INFO "%s: Failed %s configuratoin!\n", + card->devname, + (IS_T1_CARD(card))?"T1":"E1"); + return -EINVAL; + } + } + + + if (IS_56K_CARD(card)) { + int err = -EINVAL; + printk(KERN_INFO "%s: Configuring 56K onboard CSU/DSU\n", + card->devname); + + if (card->wandev.fe_iface.config){ + err = card->wandev.fe_iface.config(&card->fe); + } + if(err){ + printk (KERN_INFO "%s: Failed 56K configuration!\n", + card->devname); + return -EINVAL; + } + } + + + /* Set interrupt mode and mask */ + if (chdlc_set_intr_mode(card, APP_INT_ON_RX_FRAME | + APP_INT_ON_GLOBAL_EXCEP_COND | + APP_INT_ON_TX_FRAME | + APP_INT_ON_CHDLC_EXCEP_COND | APP_INT_ON_TIMER)){ + printk (KERN_INFO "%s: Failed to set interrupt triggers!\n", + card->devname); + return -EINVAL; + } + + + /* Mask All interrupts */ + card->hw_iface.clear_bit(card->hw, card->intr_perm_off, + (APP_INT_ON_RX_FRAME | APP_INT_ON_TX_FRAME | + APP_INT_ON_TIMER | APP_INT_ON_GLOBAL_EXCEP_COND | + APP_INT_ON_CHDLC_EXCEP_COND)); + + /* Enable communications */ + if(IS_TE1_CARD(card) && card->wandev.ignore_front_end_status == WANOPT_NO) { + + }else{ + if (card->u.c.async_mode){ + if (asy_comm_enable(card) != 0) { + printk(KERN_INFO "%s: Failed to enable async commnunication!\n", + card->devname); + card->hw_iface.poke_byte(card->hw, card->intr_perm_off, 0x00); + card->u.c.comm_enabled=0; + chdlc_set_intr_mode(card,0); + return -EINVAL; + } + }else{ + if (chdlc_comm_enable(card) != 0) { + printk(KERN_INFO "%s: Failed to enable chdlc communications!\n", + card->devname); + card->hw_iface.poke_byte(card->hw, card->intr_perm_off, 0x00); + card->u.c.comm_enabled=0; + chdlc_set_intr_mode(card,0); + return -EINVAL; + } + } + + DEBUG_EVENT("%s: Communications enabled on startup\n", + card->devname); + } + + /* Initialize Rx/Tx buffer control fields */ + init_chdlc_tx_rx_buff(card); + card->u.c.state = WAN_CONNECTING; + port_set_state(card, WAN_CONNECTING); + + + /* Manually poll the 56K CSU/DSU to get the status */ + if (IS_56K_CARD(card)) { + /* 56K Update CSU/DSU alarms */ + card->wandev.fe_iface.read_alarm(&card->fe, 1); + } + + /* Unmask all interrupts except the Transmit and Timer interrupts */ + card->hw_iface.set_bit(card->hw, card->intr_perm_off, + (APP_INT_ON_RX_FRAME | APP_INT_ON_GLOBAL_EXCEP_COND | + APP_INT_ON_CHDLC_EXCEP_COND)); + card->hw_iface.poke_byte(card->hw, card->intr_type_off, 0x00); + return 0; +} + + +static int change_speed(sdla_t *card, struct tty_struct *tty, + struct termios *old_termios) +{ + int baud, ret=0; + unsigned cflag; + int dbits,sbits,parity,handshaking; + + cflag = tty->termios->c_cflag; + + /* There is always one stop bit */ + sbits=WANOPT_ONE; + + /* Parity is defaulted to NONE */ + parity = WANOPT_NONE; + + handshaking=0; + + /* byte size and parity */ + switch (cflag & CSIZE) { + case CS5: dbits = 5; break; + case CS6: dbits = 6; break; + case CS7: dbits = 7; break; + case CS8: dbits = 8; break; + /* Never happens, but GCC is too dumb to figure it out */ + default: dbits = 8; break; + } + + /* One more stop bit should be supported, thus increment + * the number of stop bits Max=2 */ + if (cflag & CSTOPB) { + sbits = WANOPT_TWO; + } + if (cflag & PARENB) { + parity = WANOPT_EVEN; + } + if (cflag & PARODD){ + parity = WANOPT_ODD; + } + + /* Determine divisor based on baud rate */ + baud = tty_get_baud_rate(tty); + + if (!baud) + baud = 9600; /* B0 transition handled in rs_set_termios */ + + if (cflag & CRTSCTS) { + handshaking|=ASY_RTS_HS_FOR_RX; + } + + /*NC: Aug 1 2003 + + iflag ignore parity has nothing + do with parity configuration. + indicates whether we should monitory + parity errors. + Thus, comment out the code below + + if (I_IGNPAR(tty)) + parity = WANOPT_NONE; + */ + + if (I_IXOFF(tty)){ + handshaking|=ASY_XON_XOFF_HS_FOR_RX; + handshaking|=ASY_XON_XOFF_HS_FOR_TX; + } + + if (I_IXON(tty)){ + handshaking|=ASY_XON_XOFF_HS_FOR_RX; + handshaking|=ASY_XON_XOFF_HS_FOR_TX; + } + + if (card->u.c.async_mode){ + if (card->wandev.bps != baud) + ret=1; + card->wandev.bps = baud; + } + + if (card->u.c.async_mode){ + if (card->u.c.protocol_options != handshaking) + ret=1; + card->u.c.protocol_options = handshaking; + + if (card->u.c.tx_bits_per_char != dbits) + ret=1; + card->u.c.tx_bits_per_char = dbits; + + if (card->u.c.rx_bits_per_char != dbits) + ret=1; + card->u.c.rx_bits_per_char = dbits; + + if (card->u.c.stop_bits != sbits) + ret=1; + card->u.c.stop_bits = sbits; + + if (card->u.c.parity != parity) + ret=1; + card->u.c.parity = parity; + + card->u.c.break_timer = 50; + card->u.c.inter_char_timer = 10; + card->u.c.rx_complete_length = 100; + card->u.c.xon_char = 0xFE; + }else{ + card->u.c.protocol_options |= HDLC_STREAMING_MODE; + } + + return ret; +} + + +static void wanpipe_tty_set_termios(struct tty_struct *tty, struct termios *old_termios) +{ + sdla_t *card; + int err=1; + + if (!tty){ + return; + } + + card = (sdla_t *)tty->driver_data; + + if (!card) + return; + + if (change_speed(card, tty, old_termios) || !card->u.c.comm_enabled){ + unsigned long smp_flags; + + if (card->u.c.comm_enabled){ + wan_spin_lock_irq(&card->wandev.lock,&smp_flags); + chdlc_disable_comm_shutdown(card); + wan_spin_unlock_irq(&card->wandev.lock,&smp_flags); + } + wan_spin_lock_irq(&card->wandev.lock,&smp_flags); + err = config_tty(card); + wan_spin_unlock_irq(&card->wandev.lock,&smp_flags); + if (card->u.c.async_mode){ + printk(KERN_INFO "%s: TTY Async Configuration:\n" + " Baud =%i\n" + " Handshaking =%s\n" + " Tx Dbits =%i\n" + " Rx Dbits =%i\n" + " Parity =%s\n" + " Stop Bits =%i\n", + card->devname, + card->wandev.bps, + opt_decode[card->u.c.protocol_options], + card->u.c.tx_bits_per_char, + card->u.c.rx_bits_per_char, + p_decode[card->u.c.parity] , + card->u.c.stop_bits); + }else{ + printk(KERN_INFO "%s: TTY Sync Configuration:\n" + " Baud =%i\n" + " Protocol =HDLC_STREAMING\n", + card->devname,card->wandev.bps); + } + if (!err){ + card->u.c.state = WAN_CONNECTED; + port_set_state(card,WAN_CONNECTED); + }else{ + card->u.c.state = WAN_DISCONNECTED; + port_set_state(card,WAN_DISCONNECTED); + } + } + return; +} + +static void wanpipe_tty_put_char(struct tty_struct *tty, unsigned char ch) +{ + sdla_t *card; + unsigned long smp_flags=0; + + if (!tty){ + return; + } + + card = (sdla_t *)tty->driver_data; + + if (!card) + return; + + if (card->wandev.state != WAN_CONNECTED) + return; + + if(card->type != SDLA_S514) + s508_lock(card,&smp_flags); + + if (test_and_set_bit(SEND_CRIT,(void*)&card->wandev.critical)){ + + wanpipe_tty_trigger_tx_irq(card); + + if(card->type != SDLA_S514) + s508_unlock(card,&smp_flags); + return; + } + + if (chdlc_send(card,(void*)&ch,1,0)){ + wanpipe_tty_trigger_tx_irq(card); + DEBUG_TEST("%s: Failed to TX char!\n",card->devname); + }else{ + DEBUG_TEST("%s: Char TX OK\n",card->devname); + } + + clear_bit(SEND_CRIT,(void*)&card->wandev.critical); + + if(card->type != SDLA_S514) + s508_unlock(card,&smp_flags); + + return; +} + +static void wanpipe_tty_flush_chars(struct tty_struct *tty) +{ + return; +} + +static void wanpipe_tty_flush_buffer(struct tty_struct *tty) +{ + if (!tty) + return; + + wake_up_interruptible(&tty->write_wait); +#if defined(SERIAL_HAVE_POLL_WAIT) || \ + (defined LINUX_2_1 && LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,15)) + wake_up_interruptible(&tty->poll_wait); +#endif + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); + + return; +} + +/* + * This function is used to send a high-priority XON/XOFF character to + * the device + */ +#ifndef LINUX_2_6 +static void wanpipe_tty_send_xchar(struct tty_struct *tty, char ch) +{ + return; +} +#endif + +static int wanpipe_tty_chars_in_buffer(struct tty_struct *tty) +{ + return 0; +} + + +static int wanpipe_tty_write_room(struct tty_struct *tty) +{ + sdla_t *card; + + DEBUG_TEST("TTY Write Room\n"); + + if (!tty){ + return 0; + } + + card = (sdla_t *)tty->driver_data; + if (!card) + return 0; + + if (card->wandev.state != WAN_CONNECTED) + return 0; + + return SEC_MAX_NO_DATA_BYTES_IN_FRAME; +} + + +static int set_modem_status(sdla_t *card, unsigned char data) +{ + wan_mbox_t *mb = &card->wan_mbox; + int err; + + mb->wan_data_len=1; + mb->wan_command=SET_MODEM_STATUS; + mb->wan_data[0]=data; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != COMMAND_OK) + chdlc_error (card, err, mb); + + return err; +} + +static void wanpipe_tty_hangup(struct tty_struct *tty) +{ + sdla_t *card; + unsigned long smp_flags; + + printk(KERN_INFO "TTY Hangup!\n"); + + if (!tty){ + return; + } + + card = (sdla_t *)tty->driver_data; + if (!card) + return; + + wan_spin_lock_irq(&card->wandev.lock,&smp_flags); + set_modem_status(card,0); + wan_spin_unlock_irq(&card->wandev.lock,&smp_flags); + return; +} + +#ifndef LINUX_2_6 +static void wanpipe_tty_break(struct tty_struct *tty, int break_state) +{ + return; +} + +static void wanpipe_tty_wait_until_sent(struct tty_struct *tty, int timeout) +{ + return; +} +#endif + +static void wanpipe_tty_throttle(struct tty_struct * tty) +{ + return; +} + +static void wanpipe_tty_unthrottle(struct tty_struct * tty) +{ + return; +} + +int wanpipe_tty_read_proc(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + return 0; +} + +#ifdef LINUX_2_6 +static struct tty_operations wanpipe_tty_ops = { + .open = wanpipe_tty_open, + .close = wanpipe_tty_close, + .write = wanpipe_tty_write, + .put_char = wanpipe_tty_put_char, + .flush_chars = wanpipe_tty_flush_chars, + .write_room = wanpipe_tty_write_room, + .chars_in_buffer = wanpipe_tty_chars_in_buffer, + .flush_buffer = wanpipe_tty_flush_buffer, +// .ioctl = wanpipe_tty_ioctl, + .throttle = wanpipe_tty_throttle, + .unthrottle = wanpipe_tty_unthrottle, + .set_termios = wanpipe_tty_set_termios, + .stop = wanpipe_tty_stop, + .start = wanpipe_tty_start, + .hangup = wanpipe_tty_hangup, +}; +#endif + + +/* + * The serial driver boot-time initialization code! + */ +int wanpipe_tty_init(sdla_t *card) +{ + struct serial_state * state; + + /* Initialize the tty_driver structure */ + + if (card->tty_minor < 0 || card->tty_minor > NR_PORTS){ + printk(KERN_INFO "%s: Illegal Minor TTY number (0-4): %i\n", + card->devname,card->tty_minor); + return -EINVAL; + } + + if (WAN_CARD(card->tty_minor)){ + printk(KERN_INFO "%s: TTY Minor %i, already in use\n", + card->devname,card->tty_minor); + return -EBUSY; + } + + + if (tty_init_cnt==0){ + + printk(KERN_INFO "%s: TTY %s Driver Init: Major %i, Minor Range %i-%i\n", + card->devname, + card->u.c.async_mode ? "ASYNC" : "SYNC", + WAN_TTY_MAJOR,MIN_PORT,MAX_PORT); + + tty_driver_mode = card->u.c.async_mode; + + + memset(&serial_driver, 0, sizeof(struct tty_driver)); + serial_driver.magic = TTY_DRIVER_MAGIC; + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)) + serial_driver.owner = THIS_MODULE; +#endif + + serial_driver.driver_name = "wanpipe_tty"; +#if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS_FS)) + serial_driver.name = "ttyWP/%d"; +#else + serial_driver.name = "ttyWP"; +#endif + serial_driver.major = WAN_TTY_MAJOR; + serial_driver.minor_start = WAN_TTY_MINOR; + serial_driver.num = NR_PORTS; + serial_driver.type = TTY_DRIVER_TYPE_SERIAL; + serial_driver.subtype = SERIAL_TYPE_NORMAL; + + serial_driver.init_termios = tty_std_termios; + serial_driver.init_termios.c_cflag = + B9600 | CS8 | CREAD | HUPCL | CLOCAL; + serial_driver.flags = TTY_DRIVER_REAL_RAW; + + +#ifdef LINUX_2_6 + tty_set_operations(&serial_driver, &wanpipe_tty_ops); +#else + serial_driver.refcount = &serial_refcount; + serial_driver.table = serial_table; + serial_driver.termios = serial_termios; + serial_driver.termios_locked = serial_termios_locked; + + serial_driver.open = wanpipe_tty_open; + serial_driver.close = wanpipe_tty_close; + serial_driver.write = wanpipe_tty_write; + + serial_driver.put_char = wanpipe_tty_put_char; + serial_driver.flush_chars = wanpipe_tty_flush_chars; + serial_driver.write_room = wanpipe_tty_write_room; + serial_driver.chars_in_buffer = wanpipe_tty_chars_in_buffer; + serial_driver.flush_buffer = wanpipe_tty_flush_buffer; + //serial_driver.ioctl = wanpipe_tty_ioctl; + serial_driver.throttle = wanpipe_tty_throttle; + serial_driver.unthrottle = wanpipe_tty_unthrottle; + serial_driver.send_xchar = wanpipe_tty_send_xchar; + serial_driver.set_termios = wanpipe_tty_set_termios; + serial_driver.stop = wanpipe_tty_stop; + serial_driver.start = wanpipe_tty_start; + serial_driver.hangup = wanpipe_tty_hangup; + serial_driver.break_ctl = wanpipe_tty_break; + serial_driver.wait_until_sent = wanpipe_tty_wait_until_sent; + serial_driver.read_proc = wanpipe_tty_read_proc; + + /* + * The callout device is just like normal device except for + * major number and the subtype code. + */ + callout_driver = serial_driver; +#if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS_FS)) + callout_driver.name = "cuwp/%d"; +#else + callout_driver.name = "cuwp"; +#endif + callout_driver.major = TTYAUX_MAJOR; + callout_driver.subtype = SERIAL_TYPE_CALLOUT; + callout_driver.read_proc = 0; + callout_driver.proc_entry = 0; +#endif + + if (tty_register_driver(&serial_driver)){ + printk(KERN_INFO "%s: Failed to register serial driver!\n", + card->devname); + } + +#ifndef LINUX_2_6 + if (tty_register_driver(&callout_driver)){ + printk(KERN_INFO "%s: Failed to register callout driver!\n", + card->devname); + } +#endif + + } + + + /* The subsequent ports must comply to the initial configuration */ + if (tty_driver_mode != card->u.c.async_mode){ + printk(KERN_INFO "%s: Error: TTY Driver operation mode mismatch!\n", + card->devname); + printk(KERN_INFO "%s: The TTY driver is configured for %s!\n", + card->devname, tty_driver_mode ? "ASYNC" : "SYNC"); + return -EINVAL; + } + + tty_init_cnt++; + +#if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS_FS)) + printk(KERN_INFO "%s: Initializing TTY %s Driver Minor %i : /dev/ttyWP/%i\n", + card->devname, + tty_driver_mode ? "ASYNC" : "SYNC", + card->tty_minor,card->tty_minor); +#else + printk(KERN_INFO "%s: Initializing TTY %s Driver Minor %i : /dev/ttyWP%i\n", + card->devname, + tty_driver_mode ? "ASYNC" : "SYNC", + card->tty_minor,card->tty_minor); +#endif + + tty_card_map[card->tty_minor] = card; + + state = &rs_table[card->tty_minor]; + + state->magic = SSTATE_MAGIC; + state->line = 0; + state->type = PORT_UNKNOWN; + state->custom_divisor = 0; + state->close_delay = 5*HZ/10; + state->closing_wait = 30*HZ; + +#ifndef LINUX_2_6 + state->callout_termios = callout_driver.init_termios; + state->normal_termios = serial_driver.init_termios; +#endif + state->icount.cts = state->icount.dsr = + state->icount.rng = state->icount.dcd = 0; + state->icount.rx = state->icount.tx = 0; + state->icount.frame = state->icount.parity = 0; + state->icount.overrun = state->icount.brk = 0; + state->irq = card->wandev.irq; + + INIT_WORK(&card->tty_task_queue,tty_poll_task,card); + return 0; +} + +#endif + +/* + * ****************************************************************** + * Proc FS function + */ +#define PROC_CFG_FRM "%-15s| %-12s|\n" +#define PROC_STAT_FRM "%-15s| %-12s| %-14s|\n" +static char chdlc_config_hdr[] = + "Interface name | Device name |\n"; +static char chdlc_status_hdr[] = + "Interface name | Device name | Status |\n"; + +static int chdlc_get_config_info(void* priv, struct seq_file* m, int* stop_cnt) +{ + chdlc_private_area_t* chdlc_priv_area = priv; + sdla_t* card = NULL; + + if (chdlc_priv_area == NULL) + return m->count; + card = chdlc_priv_area->card; + + if ((m->from == 0 && m->count == 0) || (m->from && m->from == *stop_cnt)){ + PROC_ADD_LINE(m, + "%s", chdlc_config_hdr); + } + + PROC_ADD_LINE(m, + PROC_CFG_FRM, chdlc_priv_area->if_name, card->devname); + return m->count; +} + +static int chdlc_get_status_info(void* priv, struct seq_file* m, int* stop_cnt) +{ + chdlc_private_area_t* chdlc_priv_area = priv; + sdla_t* card = NULL; + + if (chdlc_priv_area == NULL) + return m->count; + card = chdlc_priv_area->card; + + if ((m->from == 0 && m->count == 0) || (m->from && m->from == *stop_cnt)){ + PROC_ADD_LINE(m, + "%s", chdlc_status_hdr); + } + + PROC_ADD_LINE(m, + PROC_STAT_FRM, + chdlc_priv_area->if_name, + card->devname, + STATE_DECODE(chdlc_priv_area->common.state)); + + return m->count; +} + +#define PROC_DEV_FR_S_FRM "%-20s| %-14s|\n" +#define PROC_DEV_FR_D_FRM "%-20s| %-14d|\n" +#define PROC_DEV_SEPARATE "=====================================\n" + + +static int chdlc_set_dev_config(struct file *file, + const char *buffer, + unsigned long count, + void *data) +{ + int cnt = 0; + wan_device_t* wandev = (void*)data; + sdla_t* card = NULL; + + if (wandev == NULL) + return cnt; + + card = (sdla_t*)wandev->private; + + printk(KERN_INFO "%s: New device config (%s)\n", + wandev->name, buffer); + /* Parse string */ + + return count; +} + + +#define PROC_IF_FR_S_FRM "%-30s\t%-14s\n" +#define PROC_IF_FR_D_FRM "%-30s\t%-14d\n" +#define PROC_IF_FR_L_FRM "%-30s\t%-14ld\n" +#define PROC_IF_SEPARATE "====================================================\n" + +static int chdlc_set_if_info(struct file *file, + const char *buffer, + unsigned long count, + void *data) +{ + netdevice_t* dev = (void*)data; + chdlc_private_area_t* chdlc_priv_area = NULL; + + if (dev == NULL || dev->priv == NULL) + return count; + + chdlc_priv_area = (chdlc_private_area_t*)dev->priv; + + + printk(KERN_INFO "%s: New interface config (%s)\n", + chdlc_priv_area->if_name, buffer); + /* Parse string */ + + return count; +} + +static void chdlc_handle_front_end_state(void* card_id) +{ + netdevice_t *dev; + int rc; + sdla_t* card = (sdla_t*)card_id; + + if (card->tty_opt){ + if (card->fe.fe_status == FE_CONNECTED){ + set_bit(TTY_HANGUP,&card->wandev.critical); + if(card->u.c.comm_enabled == 0) { + + rc=chdlc_comm_enable(card); + if (rc==0){ + init_chdlc_tx_rx_buff(card); + DEBUG_EVENT("%s: Communications enabled\n", + card->devname); + port_set_state(card, WAN_CONNECTING); + card->u.c.state = WAN_CONNECTING; + + }else{ + DEBUG_EVENT("%s: Critical Error: Failed to enable comms 0x%X\n", + card->devname,rc); + port_set_state(card, WAN_DISCONNECTED); + } + } + + }else{ + + if (card->wandev.ignore_front_end_status == WANOPT_NO && + card->u.c.comm_enabled){ + + printk(KERN_INFO "%s: Communications disabled\n", + card->devname); + chdlc_comm_disable (card); + card->u.c.state = WAN_DISCONNECTED; + port_set_state(card, WAN_DISCONNECTED); + } + + + if (card->tty && card->tty_open){ + if (test_and_clear_bit(TTY_HANGUP,&card->wandev.critical)){ + printk(KERN_INFO "%s: Hanging up TTY: physical link down.\n", + card->devname); + tty_hangup(card->tty); + } + } + } + return; + } + + if (card->wandev.ignore_front_end_status == WANOPT_YES){ + return; + } + + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + + if (IS_TE1_CARD(card)){ + if (card->fe.fe_status == FE_CONNECTED) { + if (card->u.c.state != WAN_CONNECTED) { + if(card->u.c.comm_enabled == 0) { + + rc=chdlc_comm_enable(card); + if (rc==0){ + init_chdlc_tx_rx_buff(card); + DEBUG_EVENT("%s: Communications enabled\n", + card->devname); + + port_set_state(card, WAN_CONNECTING); + card->u.c.state = WAN_CONNECTING; + + }else{ + DEBUG_EVENT("%s: Critical Error: Failed to enable comms 0x%X\n", + card->devname,rc); + port_set_state(card, WAN_DISCONNECTED); + } + } + }else{ + DEBUG_TEST("%s: Warning: Comms are already enabled!\n", + card->devname); + } + + }else{ + port_set_state(card, WAN_DISCONNECTED); + if (dev){ + trigger_chdlc_poll(dev); + } + if (card->u.c.comm_enabled){ + printk(KERN_INFO "%s: Communications disabled\n", + card->devname); + chdlc_comm_disable (card); + card->u.c.state = WAN_DISCONNECTED; + } + } + + }else{ + if (card->fe.fe_status == FE_CONNECTED){ + if (card->u.c.state == WAN_CONNECTED){ + port_set_state(card,WAN_CONNECTED); + if (dev){ + trigger_chdlc_poll(dev); + } + } + }else{ + if (!(card->u.c.protocol_options & IGNORE_KPALV_FOR_LINK_STAT)){ + port_set_state(card,WAN_DISCONNECTED); + if (dev){ + trigger_chdlc_poll(dev); + } + + /* Start debugging */ + WAN_DEBUG_START(card); + } + } + } +} + + +/*************************************************************************** +** +** +** +*/ +static int chdlc_debugging(sdla_t* card) +{ + wan_mbox_t* mb = &card->wan_mbox; + CHDLC_OPERATIONAL_STATS_STRUCT* op_stats = NULL; + static unsigned long rx_keepalives = 0; + unsigned long smp_flags; + int err = 0; + + wan_spin_lock_irq(&card->wandev.lock,&smp_flags); + err = chdlc_read_op_stats(card); + wan_spin_unlock_irq(&card->wandev.lock,&smp_flags); + if (err) + return 0; + op_stats = (CHDLC_OPERATIONAL_STATS_STRUCT *)mb->wan_data; + if (card->wan_debugging_state == WAN_DEBUGGING_CONT){ + rx_keepalives = op_stats->CHDLC_SLARP_REPLY_Rx_count; + card->wan_debugging_state = WAN_DEBUGGING_PROTOCOL; + return 15; + } + + if (op_stats->CHDLC_SLARP_REPLY_Rx_count != rx_keepalives){ + if (card->wan_debug_last_msg != WAN_DEBUG_CHDLC_UNKNWN_MSG){ + DEBUG_EVENT("%s: Unknown CHDLC problem!\n", + card->devname); + DEBUG_EVENT("%s: Contact your dealer.\n", + card->devname); + } + card->wan_debug_last_msg = WAN_DEBUG_CHDLC_UNKNWN_MSG; + }else{ + if (card->wan_debug_last_msg != WAN_DEBUG_CHDLC_KPLV_MSG){ + DEBUG_EVENT("%s: No replies to Keepalive packets!\n", + card->devname); + DEBUG_EVENT("%s: Check remote router or ISP.\n", + card->devname); + } + card->wan_debug_last_msg = WAN_DEBUG_CHDLC_KPLV_MSG; + } + return 0; +} + +static unsigned long chdlc_crc_frames(sdla_t* card) +{ + wan_mbox_t* mb = &card->wan_mbox; + COMMS_ERROR_STATS_STRUCT* stats = NULL; + unsigned long smp_flags; + unsigned long crc_err_count = 0; + + wan_spin_lock_irq(&card->wandev.lock,&smp_flags); + if (!chdlc_read_comm_err_stats(card)){ + stats = (COMMS_ERROR_STATS_STRUCT *)mb->wan_data; + crc_err_count = stats->CRC_err_count; + } + wan_spin_unlock_irq(&card->wandev.lock,&smp_flags); + return crc_err_count; +} + +static unsigned long chdlc_abort_frames(sdla_t * card) +{ + wan_mbox_t* mb = &card->wan_mbox; + COMMS_ERROR_STATS_STRUCT* stats = NULL; + unsigned long smp_flags; + unsigned long rx_abort_count = 0; + + wan_spin_lock_irq(&card->wandev.lock,&smp_flags); + if (!chdlc_read_comm_err_stats(card)){ + stats = (COMMS_ERROR_STATS_STRUCT *)mb->wan_data; + rx_abort_count = stats->Rx_abort_count; + } + wan_spin_unlock_irq(&card->wandev.lock,&smp_flags); + return rx_abort_count; +} + +static unsigned long chdlc_tx_underun_frames(sdla_t* card) +{ + wan_mbox_t* mb = &card->wan_mbox; + COMMS_ERROR_STATS_STRUCT* stats = NULL; + unsigned long smp_flags; + unsigned long tx_underruns = 0; + + wan_spin_lock_irq(&card->wandev.lock,&smp_flags); + if (!chdlc_read_comm_err_stats(card)){ + stats = (COMMS_ERROR_STATS_STRUCT *)mb->wan_data; + tx_underruns = stats->sec_Tx_abort_msd_Tx_int_count; + } + wan_spin_unlock_irq(&card->wandev.lock,&smp_flags); + return tx_underruns; +} + +/****** End ****************************************************************/ diff -Nur linux.org/drivers/net/wan/sdladrv.c linux-2.6.17/drivers/net/wan/sdladrv.c --- linux.org/drivers/net/wan/sdladrv.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/drivers/net/wan/sdladrv.c 2006-08-30 10:07:16.000000000 +0000 @@ -0,0 +1,6164 @@ +/***************************************************************************** +* sdladrv.c SDLA Support Module. Main module. +* +* This module is a library of common hardware-specific functions +* used by all Sangoma drivers. +* +* Author: Alex Feldman, Nenad Corbic, Gideon Hack +* +* Copyright: (c) 1995-2003 Sangoma Technologies Inc. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version +* 2 of the License, or (at your option) any later version. +* ============================================================================ +* Dec 15. 2003 Nenad Corbic Redesigned hw abstraction layer to +* Alex Feldman support both BSD and Linux as well +* as to abstract the HW layer from +* layers above. +* Added support for ADSL,S51X,AFT cards. +* Oct 02. 2002 Nenad Corbic sdla_exec() update +* Timeout using jiffies and nloops since +* jiffies don't work when irq's are turned +* off. +* Apr 25, 2001 Nenad Corbic Fixed the 2.0.X kernel bug in pci_init. +* Mar 20, 2001 Nenad Corbic Added the auto_pci_cfg filed, to support +* the PCISLOT #0. +* Apr 04, 2000 Nenad Corbic Fixed the auto memory detection code. +* The memory test at address 0xC8000. +* Mar 09, 2000 Nenad Corbic Added Gideon's Bug Fix: clear pci +* interrupt flags on initial load. +* Jun 02, 1999 Gideon Hack Added support for the S514 adapter. +* Updates for Linux 2.2.X kernels. +* Sep 17, 1998 Jaspreet Singh Updates for linux 2.2.X kernels +* Dec 20, 1996 Gene Kozin Version 3.0.0. Complete overhaul. +* Jul 12, 1996 Gene Kozin Changes for Linux 2.0 compatibility. +* Jun 12, 1996 Gene Kozin Added support for S503 card. +* Apr 30, 1996 Gene Kozin SDLA hardware interrupt is acknowledged before +* calling protocolspecific ISR. +* Register I/O ports with Linux kernel. +* Miscellaneous bug fixes. +* Dec 20, 1995 Gene Kozin Fixed a bug in interrupt routine. +* Oct 14, 1995 Gene Kozin Initial version. +*****************************************************************************/ + +/***************************************************************************** + * Notes: + * ------ + * 1. This code is ment to be system-independent (as much as possible). To + * achive this, various macros are used to hide system-specific interfaces. + * To compile this code, one of the following constants must be defined: + * + * Platform Define + * -------- ------ + * Linux _LINUX_ + * SCO Unix _SCO_UNIX_ + * + * 2. Supported adapter types: + * + * S502A + * ES502A (S502E) + * S503 + * S507 + * S508 (S509) + * + * 3. S502A Notes: + * + * There is no separate DPM window enable/disable control in S502A. It + * opens immediately after a window number it written to the HMCR + * register. To close the window, HMCR has to be written a value + * ????1111b (e.g. 0x0F or 0xFF). + * + * S502A DPM window cannot be located at offset E000 (e.g. 0xAE000). + * + * There should be a delay of ??? before reading back S502A status + * register. + * + * 4. S502E Notes: + * + * S502E has a h/w bug: although default IRQ line state is HIGH, enabling + * interrupts by setting bit 1 of the control register (BASE) to '1' + * causes it to go LOW! Therefore, disabling interrupts by setting that + * bit to '0' causes low-to-high transition on IRQ line (ghosty + * interrupt). The same occurs when disabling CPU by resetting bit 0 of + * CPU control register (BASE+3) - see the next note. + * + * S502E CPU and DPM control is limited: + * + * o CPU cannot be stopped independently. Resetting bit 0 of the CPUi + * control register (BASE+3) shuts the board down entirely, including + * DPM; + * + * o DPM access cannot be controlled dynamically. Ones CPU is started, + * bit 1 of the control register (BASE) is used to enable/disable IRQ, + * so that access to shared memory cannot be disabled while CPU is + * running. + ****************************************************************************/ + + +#define __SDLA_HW_LEVEL +#define __SDLADRV__ + +/* +**************************************************************************** +**** For Debug purpose (only OpenBSD) **** +**************************************************************************** +*/ + +#ifdef __OpenBSD__ +# undef WANDEBUG /* Uncomment this line for debug purpose */ +#endif + + +/*************************************************************************** +**** I N C L U D E F I L E S **** +***************************************************************************/ +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +#elif defined(__LINUX__)||defined(__KERNEL__) +# define _K22X_MODULE_FIX_ +# include +# include +# include +# include +# include +# include /* SDLA firmware module definitions */ +# include /* SDLA PCI hardware definitions */ +# include +# include /* API definitions */ +#else +# error "Unsupported Operating System!" +#endif + +/*************************************************************************** +**** M A C R O S / D E F I N E S **** +***************************************************************************/ +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) +# define EXPORT_SYMBOL(symbol) +#endif +#define SDLA_IODELAY 100 /* I/O Rd/Wr delay, 10 works for 486DX2-66 */ +#define EXEC_DELAY 20 /* shared memory access delay, mks */ +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) +# define EXEC_TIMEOUT (HZ*2) +#endif +#define MAX_NLOOPS (EXEC_DELAY*2000) + /* timeout used if jiffies are stopped + * EXEC_DELAY=20 + * EXEC_TIMEOUT=EXEC_DELAY*2000 = 40000 + * 40000 ~= 80 jiffies = EXEC_TIMEOUT */ + +#define EXEC_HZ_DIVISOR 8/10 /* We don't want to wait a full second on sdla_exec + * timeout, thus use HZ * EXEC_HZ_DIVISOR to get + * the number of jiffies we would like to wait */ + + +/* I/O port address range */ +#define S502A_IORANGE 3 +#define S502E_IORANGE 4 +#define S503_IORANGE 3 +#define S507_IORANGE 4 +#define S508_IORANGE 4 + +/* Maximum amount of memory */ +#define S502_MAXMEM 0x10000L +#define S503_MAXMEM 0x10000L +#define S507_MAXMEM 0x40000L +#define S508_MAXMEM 0x40000L + +/* Minimum amount of memory */ +#define S502_MINMEM 0x8000L +#define S503_MINMEM 0x8000L +#define S507_MINMEM 0x20000L +#define S508_MINMEM 0x20000L + +#define IS_SUPPORTED_ADAPTER(hw) (hw->type==SDLA_S508 || hw->type==SDLA_S514 || hw->type==SDLA_ADSL) + +#define IS_S514(hw) (hw->type == SDLA_S514) +#define IS_S518(hw) (hw->type == SDLA_ADSL) +#define IS_S508(hw) (hw->type == SDLA_S508) + +#define SDLA_TYPE(hw) IS_S508(hw) ? "S508" : \ + IS_S514(hw) ? "S514" : \ + IS_S518(hw) ? "S518 (ADSL)" : "Unknown" + +#define SDLA_ISA_CARD 0 +#define SDLA_PCI_CARD 1 + +#define SDLA_MAGIC(hw) WAN_ASSERT(hw->magic != SDLADRV_MAGIC) + +/****** Function Prototypes *************************************************/ + +/* Hardware-specific functions */ +static int sdla_register_check (wandev_conf_t* conf, char* devname); +static int sdla_setup (void* phw, wandev_conf_t* conf); +static int sdla_load (void* phw, void* psfm, unsigned len); +static int sdla_down (void* phw); +static int sdla_halt (void* phw); +static int sdla_inten (sdlahw_t* hw); +static int sdla_intack (void* phw, u32 int_status); +static int sdla_read_int_stat (void* phw, u32* int_status); +#if 0 +static int sdla_intde (sdlahw_t* hw); +static int sdla_intr (sdlahw_t* hw); +#endif +static int sdla_mapmem (void* phw, unsigned long addr); +static int sdla_check_mismatch(void* phw, unsigned char media); +static int sdla_getcfg(void* phw, int type, void*); +static int sdla_isa_read_1(void* phw, unsigned int offset, u8*); +static int sdla_isa_write_1(void* phw, unsigned int offset, u8); +static int sdla_io_write_1(void* phw, unsigned int offset, u8); +static int sdla_io_read_1(void* phw, unsigned int offset, u8*); +static int sdla_bus_write_1(void* phw, unsigned int offset, u8); +static int sdla_bus_write_2(void* phw, unsigned int offset, u16); +static int sdla_bus_write_4(void* phw, unsigned int offset, u32); +static int sdla_bus_read_1(void* phw, unsigned int offset, u8*); +static int sdla_bus_read_2(void* phw, unsigned int offset, u16*); +static int sdla_bus_read_4(void* phw, unsigned int offset, u32*); +static int sdla_pci_write_config_byte(void*, int, u8); +static int sdla_pci_write_config_word(void*, int, u16); +static int sdla_pci_write_config_dword(void*, int, u32); +static int sdla_pci_read_config_byte(void*, int, u8*); +static int sdla_pci_read_config_word(void*, int, u16*); +static int sdla_pci_read_config_dword(void*, int, u32*); +static int sdla_cmd (void* phw, unsigned long offset, wan_mbox_t* mbox); + +static int sdla_exec (sdlahw_t* hw, unsigned long offset); +static int sdla_peek (void* phw, unsigned long addr, void* pbuf, unsigned len); +static int sdla_poke (void* phw, unsigned long addr, void* pbuf, unsigned len); +static int sdla_poke_byte (void* phw, unsigned long addr, u8); +static int sdla_set_bit (void* phw, unsigned long addr, u8); +static int sdla_clear_bit (void* phw, unsigned long addr, u8); +static void sdla_peek_by_4 (sdlahw_t* hw, unsigned long offset, void* pbuf, unsigned int len); +static void sdla_poke_by_4 (sdlahw_t* hw, unsigned long offset, void* pbuf, unsigned int len); +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) +static int sdla_set_intrhand(void* phw, void (*isr_func)(void*), void* arg, int); +static int sdla_restore_intrhand(void* phw, int); +#endif +static int sdla_get_hwcard(void* phw, void** phwcard); +static int sdla_get_hwprobe(void* phw, int port, void** str); + +static int sdla_memory_map(sdlahw_t* hw, int cpu_no); +static int sdla_memory_unmap(sdlahw_t* hw); + +static int sdla_detect (sdlahw_t* hw); +static int sdla_autodpm (sdlahw_t* hw); +static int sdla_setdpm (sdlahw_t* hw); +static int sdla_start(sdlahw_t* hw, unsigned addr); +/*ALEXstatic int sdla_load (sdlahw_t* hw, sfm_t* sfm, unsigned len);*/ +static int sdla_init (sdlahw_t* hw); +static unsigned long sdla_memtest (sdlahw_t* hw); +static int sdla_bootcfg (sdlahw_t* hw, sfm_info_t* sfminfo); +static unsigned char sdla_make_config_byte (sdlahw_t* hw); + +static int sdla_init_s502a (sdlahw_t* hw); +static int sdla_init_s502e (sdlahw_t* hw); +static int sdla_init_s503 (sdlahw_t* hw); +static int sdla_init_s507 (sdlahw_t* hw); +static int sdla_init_s508 (sdlahw_t* hw); + +static int sdla_detect_s502a (sdlahw_t* hw); +static int sdla_detect_s502e (sdlahw_t* hw); +static int sdla_detect_s503 (sdlahw_t* hw); +static int sdla_detect_s507 (sdlahw_t* hw); +static int sdla_detect_s508 (sdlahw_t* hw); +static int sdla_detect_s514 (sdlahw_t* hw); +static int sdla_detect_pulsar(sdlahw_t* hw); +static int sdla_detect_aft(sdlahw_t* hw); + +static int sdla_is_te1(void* phw); +static int sdla_is_56k(void* phw); + +static sdlahw_t* sdla_find_adapter(wandev_conf_t* conf, char* devname); + +/* Miscellaneous functions */ +static int sdla_get_option_index (unsigned* optlist, unsigned optval); +static unsigned sdla_check_memregion (sdlahw_t* hw); +static unsigned sdla_test_memregion (sdlahw_t* hw, unsigned len); +static unsigned short sdla_checksum (unsigned char* buf, unsigned len); +static int sdla_init_pci_slot(sdlahw_t *); + + +static sdlahw_card_t* sdla_card_register(unsigned char hw_type, int slot_no, int bus_no, int ioport); +static int sdla_card_unregister (unsigned char hw_type, int slot_no, int bus_no, int ioport); +static sdlahw_card_t* sdla_card_search(unsigned char hw_type, int slot_no, int bus_no, int ioport); + +static sdlahw_t* sdla_hw_register(sdlahw_card_t* card, int cpu_no, int irq, void*); +static int sdla_hw_unregister(sdlahw_card_t* card, int cpu_no); +static sdlahw_t* sdla_hw_search(unsigned char hw_type, int slot_no, int bus_no, int ioport, int cpu_no); + +static int sdla_s514_hw_select (sdlahw_card_t* card, int cpu_no, int irq, void*); +static int sdla_adsl_hw_select (sdlahw_card_t* card, int cpu_no, int irq, void*); +static int sdla_aft_hw_select (sdlahw_card_t* card, int cpu_no, int irq, void*); +static void sdla_save_hw_probe (sdlahw_t* hw, int port); + +static int sdla_hw_unlock(void *phw, wan_smp_flag_t *flag); +static int sdla_hw_lock(void *phw, wan_smp_flag_t *flag); + +static sdla_dma_addr_t sdla_pci_map_dma(void *phw, void *buf, int len, int ctrl); +static int sdla_pci_unmap_dma(void *phw, sdla_dma_addr_t buf, int len, int ctrl); + +static int sdla_is_same_hwcard(void* phw1, void *phw2); +static int sdla_hw_fe_test_and_set(void *phw); +static int sdla_hw_fe_clear(void *phw); + +static int sdla_hw_read_cpld(void *phw, u16 off, u8 *data); +static int sdla_hw_write_cpld(void *phw, u16 off, u8 data); + +#if defined(__LINUX__) +#if defined(WAN_DEBUG_MEM) + atomic_t wan_debug_mem; + EXPORT_SYMBOL(wan_debug_mem); +#endif +static int sdla_pci_probe(sdlahw_t*); +#endif +/****** Global Data ********************************************************** + * Note: All data must be explicitly initialized!!! + */ +#if defined(__FreeBSD__) && (__FreeBSD_version < 500000) +volatile extern int ticks; /* This line will causes redundant + redeclaration warning. Don't worry, + otherwise loop in calibrate_delay() will + never finished (optimization) */ +#endif + +/* SDLA ISA/PCI varibles */ +extern int Sangoma_cards_no; /* total number of SDLA cards */ +extern int Sangoma_devices_no; /* Max number of Sangoma dev */ +extern int Sangoma_PCI_cards_no; /* total number of S514 cards */ + +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) +extern sdladev_t sdladev[]; /* SDLA info structure */ +#endif + +/* private data */ +#if defined(CONFIG_PRODUCT_WANPIPE_GENERIC) +char *wan_drvname = "wanpipe(lite)"; +static char *wan_fullname = "WANPIPE(Lite) Hardware Support Module"; +#else +static char *wan_drvname = "wanpipe"; +static char *wan_fullname = "WANPIPE(tm) Hardware Support Module"; +#endif + +/* Array of already initialized PCI slots */ +static int pci_slot_ar[MAX_S514_CARDS]; + +WAN_LIST_HEAD(, sdlahw_card) sdlahw_card_head = + WAN_LIST_HEAD_INITIALIZER(&sdlahw_card_head); +WAN_LIST_HEAD(, sdlahw) sdlahw_head = + WAN_LIST_HEAD_INITIALIZER(&sdlahw_head); +WAN_LIST_HEAD(, sdla_hw_probe) sdlahw_probe_head = + WAN_LIST_HEAD_INITIALIZER(&sdlahw_probe_head); +static sdla_hw_type_cnt_t sdla_adapter_cnt; + +#if defined(__LINUX__) +static unsigned long EXEC_TIMEOUT; +#endif + +/* Hardware configuration options. + * These are arrays of configuration options used by verification routines. + * The first element of each array is its size (i.e. number of options). + */ +static unsigned s502_port_options[] = + { 4, 0x250, 0x300, 0x350, 0x360 } +; +static unsigned s503_port_options[] = + { 8, 0x250, 0x254, 0x300, 0x304, 0x350, 0x354, 0x360, 0x364 } +; +static unsigned s508_port_options[] = + { 8, 0x250, 0x270, 0x280, 0x300, 0x350, 0x360, 0x380, 0x390 } +; + +static unsigned s502a_irq_options[] = { 0 }; +static unsigned s502e_irq_options[] = { 4, 2, 3, 5, 7 }; +static unsigned s503_irq_options[] = { 5, 2, 3, 4, 5, 7 }; +static unsigned s508_irq_options[] = { 8, 3, 4, 5, 7, 10, 11, 12, 15 }; + +static unsigned s502a_dpmbase_options[] = +{ + 28, + 0xA0000, 0xA2000, 0xA4000, 0xA6000, 0xA8000, 0xAA000, 0xAC000, + 0xC0000, 0xC2000, 0xC4000, 0xC6000, 0xC8000, 0xCA000, 0xCC000, + 0xD0000, 0xD2000, 0xD4000, 0xD6000, 0xD8000, 0xDA000, 0xDC000, + 0xE0000, 0xE2000, 0xE4000, 0xE6000, 0xE8000, 0xEA000, 0xEC000, +}; +static unsigned s507_dpmbase_options[] = +{ + 32, + 0xA0000, 0xA2000, 0xA4000, 0xA6000, 0xA8000, 0xAA000, 0xAC000, 0xAE000, + 0xB0000, 0xB2000, 0xB4000, 0xB6000, 0xB8000, 0xBA000, 0xBC000, 0xBE000, + 0xC0000, 0xC2000, 0xC4000, 0xC6000, 0xC8000, 0xCA000, 0xCC000, 0xCE000, + 0xE0000, 0xE2000, 0xE4000, 0xE6000, 0xE8000, 0xEA000, 0xEC000, 0xEE000, +}; +static unsigned s508_dpmbase_options[] = +{ + 32, + 0xA0000, 0xA2000, 0xA4000, 0xA6000, 0xA8000, 0xAA000, 0xAC000, 0xAE000, + 0xC0000, 0xC2000, 0xC4000, 0xC6000, 0xC8000, 0xCA000, 0xCC000, 0xCE000, + 0xD0000, 0xD2000, 0xD4000, 0xD6000, 0xD8000, 0xDA000, 0xDC000, 0xDE000, + 0xE0000, 0xE2000, 0xE4000, 0xE6000, 0xE8000, 0xEA000, 0xEC000, 0xEE000, +}; + +/* +static unsigned s508_dpmsize_options[] = { 1, 0x2000 }; +*/ + +static unsigned s502a_pclk_options[] = { 2, 3600, 7200 }; +static unsigned s502e_pclk_options[] = { 5, 3600, 5000, 7200, 8000, 10000 }; +static unsigned s503_pclk_options[] = { 3, 7200, 8000, 10000 }; +static unsigned s507_pclk_options[] = { 1, 12288 }; +static unsigned s508_pclk_options[] = { 1, 16000 }; + +/* Host memory control register masks */ +static unsigned char s502a_hmcr[] = +{ + 0x10, 0x12, 0x14, 0x16, 0x18, 0x1A, 0x1C, /* A0000 - AC000 */ + 0x20, 0x22, 0x24, 0x26, 0x28, 0x2A, 0x2C, /* C0000 - CC000 */ + 0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, /* D0000 - DC000 */ + 0x30, 0x32, 0x34, 0x36, 0x38, 0x3A, 0x3C, /* E0000 - EC000 */ +}; +static unsigned char s502e_hmcr[] = +{ + 0x10, 0x12, 0x14, 0x16, 0x18, 0x1A, 0x1C, 0x1E, /* A0000 - AE000 */ + 0x20, 0x22, 0x24, 0x26, 0x28, 0x2A, 0x2C, 0x2E, /* C0000 - CE000 */ + 0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E, /* D0000 - DE000 */ + 0x30, 0x32, 0x34, 0x36, 0x38, 0x3A, 0x3C, 0x3E, /* E0000 - EE000 */ +}; +static unsigned char s507_hmcr[] = +{ + 0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E, /* A0000 - AE000 */ + 0x40, 0x42, 0x44, 0x46, 0x48, 0x4A, 0x4C, 0x4E, /* B0000 - BE000 */ + 0x80, 0x82, 0x84, 0x86, 0x88, 0x8A, 0x8C, 0x8E, /* C0000 - CE000 */ + 0xC0, 0xC2, 0xC4, 0xC6, 0xC8, 0xCA, 0xCC, 0xCE, /* E0000 - EE000 */ +}; +static unsigned char s508_hmcr[] = +{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* A0000 - AE000 */ + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* C0000 - CE000 */ + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, /* D0000 - DE000 */ + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, /* E0000 - EE000 */ +}; + +static unsigned char s507_irqmask[] = +{ + 0x00, 0x20, 0x40, 0x60, 0x80, 0xA0, 0xC0, 0xE0 +}; + +/* Entry Point for Low-Level function */ +int sdladrv_init(void*); +int sdladrv_exit(void*); + +/*****************************************************************************/ +/* Loadable kernel module function interface */ +#if !defined(CONFIG_PRODUCT_WANPIPE_GENERIC) +# if !defined(__OpenBSD__) && !defined(__NetBSD__) +WAN_MODULE_DEFINE( + sdladrv, "sdladrv", + "Alex Feldman ", + "Sangoma WANPIPE: HW Layer", + "GPL", + sdladrv_init, sdladrv_exit, NULL); +WAN_MODULE_VERSION(sdladrv, SDLADRV_MAJOR_VER); +# endif +#endif + + +/*============================================================================ + * Module init point. + */ +int sdladrv_init(void* arg) +{ + int volatile i=0; + + if (WANPIPE_VERSION_BETA){ + DEBUG_EVENT("%s Beta%s-%s %s %s\n", + wan_fullname, WANPIPE_SUB_VERSION, WANPIPE_VERSION, + WANPIPE_COPYRIGHT_DATES,WANPIPE_COMPANY); + }else{ + DEBUG_EVENT("%s Stable %s-%s %s %s\n", + wan_fullname, WANPIPE_VERSION, WANPIPE_SUB_VERSION, + WANPIPE_COPYRIGHT_DATES,WANPIPE_COMPANY); + } + +#if defined(__LINUX__) + EXEC_TIMEOUT=HZ*EXEC_HZ_DIVISOR; +#endif + /* Initialize the PCI Card array, which + * will store flags, used to mark + * card initialization state */ + for (i=0; ihwcard, tmp->cpu_no) == -EBUSY){ + return -EBUSY; + } + } + WAN_LIST_INIT(&sdlahw_head); + + elm_hw_card = WAN_LIST_FIRST(&sdlahw_card_head); + while(elm_hw){ + sdlahw_card_t *tmp = elm_hw_card; + elm_hw_card = WAN_LIST_NEXT(elm_hw_card, next); + if (sdla_card_unregister(tmp->hw_type, + tmp->slot_no, + tmp->bus_no, + tmp->ioport) == -EBUSY){ + return -EBUSY; + } + } + WAN_LIST_INIT(&sdlahw_card_head); + + elm_hw_probe = WAN_LIST_FIRST(&sdlahw_probe_head); + while(elm_hw_probe){ + sdla_hw_probe_t *tmp = elm_hw_probe; + elm_hw_probe = WAN_LIST_NEXT(elm_hw_probe, next); + if (tmp->used){ + DEBUG_EVENT("sdladrv: HW probe info is in used (%s)\n", + tmp->hw_info); + return -EBUSY; + } + WAN_LIST_REMOVE(tmp, next); + wan_free(tmp); + } + +#if defined(WAN_DEBUG_MEM) + DEBUG_EVENT("sdladrv: Total Mem %d\n",wan_atomic_read(&wan_debug_mem)); +#endif + return 0; +} + +/* +***************************************************************************** +***************************************************************************** +G*** S A N G O M A H A R D W A R E P R O B E ***** +***************************************************************************** +***************************************************************************** +*/ +/* +***************************************************************************** +** sdla_save_hw_probe +***************************************************************************** +*/ +#define SDLA_HWPROBE_ISA_FORMAT \ + "%-10s : IOPORT=0x%X : PORT=%s" +#define SDLA_HWPROBE_PCI_FORMAT \ + "%-10s : SLOT=%d : BUS=%d : IRQ=%d : CPU=%c : PORT=%s" +#define SDLA_HWPROBE_AFT_FORMAT \ + "%-10s : SLOT=%d : BUS=%d : IRQ=%d : CPU=%c : PORT=%d : V=%02X" +#define SDLA_HWPROBE_AFT_1_2_FORMAT \ + "%-10s : SLOT=%d : BUS=%d : IRQ=%d : CPU=%c : PORT=%s : V=%02X" +#define SDLA_HWPROBE_AFT_SH_FORMAT \ + "%-10s : SLOT=%d : BUS=%d : IRQ=%d : CPU=%c : PORT=%d : HWEC=%d : V=%02X" +#define SDLA_HWPROBE_A200_SH_FORMAT \ + "%-10s : SLOT=%d : BUS=%d : IRQ=%d : CPU=%c : PORT=%s : HWEC=%d : V=%02X" + +static void +sdla_save_hw_probe (sdlahw_t* hw, int port) +{ + sdla_hw_probe_t *tmp_hw_probe, *tmp; + + tmp_hw_probe = wan_malloc(sizeof(sdla_hw_probe_t)); + if (!tmp_hw_probe) + return; + + memset(tmp_hw_probe,0,sizeof(sdla_hw_probe_t)); + + if (hw->hwcard->hw_type == SDLA_PCI_CARD){ + switch(hw->hwcard->adptr_type){ + case A104_ADPTR_4TE1: + case A108_ADPTR_8TE1: + if (hw->hwcard->adptr_subtype == AFT_SUBTYPE_SHARK){ + snprintf(tmp_hw_probe->hw_info, + sizeof(tmp_hw_probe->hw_info), + SDLA_HWPROBE_AFT_SH_FORMAT, + hw->hwcard->adptr_name, + hw->hwcard->slot_no, + hw->hwcard->bus_no, + hw->irq, + SDLA_GET_CPU(hw->cpu_no), + port+1, /* line_no */ + hw->hwcard->hwec_chan_no, + hw->hwcard->core_rev); + }else{ + snprintf(tmp_hw_probe->hw_info, + sizeof(tmp_hw_probe->hw_info), + SDLA_HWPROBE_AFT_FORMAT, + hw->hwcard->adptr_name, + hw->hwcard->slot_no, + hw->hwcard->bus_no, + hw->irq, + SDLA_GET_CPU(hw->cpu_no), + port+1, + hw->hwcard->core_rev + ); /* line_no */ + } + break; + + case A200_ADPTR_ANALOG: + /*sprintf(tmp_hw_probe->hw_info,*/ + snprintf(tmp_hw_probe->hw_info, + sizeof(tmp_hw_probe->hw_info), + SDLA_HWPROBE_A200_SH_FORMAT, + hw->hwcard->adptr_name, + hw->hwcard->slot_no, + hw->hwcard->bus_no, + hw->irq, + SDLA_GET_CPU(hw->cpu_no), + port ? "SEC" : "PRI", + hw->hwcard->hwec_chan_no, + hw->hwcard->core_rev); + break; + + + case A101_ADPTR_1TE1: + case A101_ADPTR_2TE1: + /*sprintf(tmp_hw_probe->hw_info,*/ + snprintf(tmp_hw_probe->hw_info, + sizeof(tmp_hw_probe->hw_info), + SDLA_HWPROBE_AFT_1_2_FORMAT, + hw->hwcard->adptr_name, + hw->hwcard->slot_no, + hw->hwcard->bus_no, + hw->irq, + SDLA_GET_CPU(hw->cpu_no), + port ? "SEC" : "PRI", + hw->hwcard->core_rev); + break; + + default: + /*sprintf(tmp_hw_probe->hw_info,*/ + snprintf(tmp_hw_probe->hw_info, + sizeof(tmp_hw_probe->hw_info), + SDLA_HWPROBE_PCI_FORMAT, + hw->hwcard->adptr_name, + hw->hwcard->slot_no, + hw->hwcard->bus_no, + hw->irq, + SDLA_GET_CPU(hw->cpu_no), + port ? "SEC" : "PRI"); + break; + } + }else{ + /*sprintf(tmp_hw_probe->hw_info, */ + snprintf(tmp_hw_probe->hw_info, sizeof(tmp_hw_probe->hw_info), + SDLA_HWPROBE_ISA_FORMAT, + "S508-ISA",hw->hwcard->ioport, port ? "SEC" : "PRI"); + } + + hw->hwport[port].hwprobe = tmp_hw_probe; + hw->max_ports++; + tmp_hw_probe->used++; + + WAN_LIST_FOREACH(tmp, &sdlahw_probe_head, next){ + if (!WAN_LIST_NEXT(tmp, next)){ + break; + } + } + if (tmp){ + WAN_LIST_INSERT_AFTER(tmp, tmp_hw_probe, next); + }else{ + WAN_LIST_INSERT_HEAD(&sdlahw_probe_head, tmp_hw_probe, next); + + } + return; +} + +static void sdla_get_adptr_name(sdlahw_t* hw) +{ + sprintf(hw->hwcard->adptr_name, "%s%s%s", + SDLA_ADPTR_NAME(hw->hwcard->adptr_type), + AFT_SUBTYPE(hw->hwcard->adptr_subtype), + AFT_SECURITY(hw->hwcard->adptr_security)); + + return; +} + +#define AFT_CHIP_CFG_REG 0x40 +#define AFT_CHIPCFG_SFR_IN_BIT 2 +#define AFT_CHIPCFG_SFR_EX_BIT 1 +static int sdla_get_cpld_info(sdlahw_t* hw) +{ + unsigned int reg, reg1; + unsigned short cpld_off; + unsigned char status = 0, tmp = 0, adptr_sec = 0; + + if (sdla_memory_map(hw, SDLA_CPU_A)){ + return -EINVAL; + } + + switch(hw->hwcard->adptr_type){ + case A101_ADPTR_1TE1: + case A101_ADPTR_2TE1: + cpld_off = AFT_SECURITY_CPLD_REG; + sdla_hw_read_cpld(hw, cpld_off, &tmp); + adptr_sec = AFT_GET_SECURITY(tmp); + switch(adptr_sec){ + case AFT_SECURITY_1LINE_UNCH: + case AFT_SECURITY_2LINE_UNCH: + hw->hwcard->adptr_security = AFT_SECURITY_UNCHAN; + break; + case AFT_SECURITY_1LINE_CH: + case AFT_SECURITY_2LINE_CH: + hw->hwcard->adptr_security = AFT_SECURITY_CHAN; + break; + default: + DEBUG_EVENT( + "%s: AFT-A101-2 Critical error: Unknown Security ID (0x%02X)!\n", + wan_drvname, adptr_sec); + break; + } + break; + + case A104_ADPTR_4TE1: + /* Enable memory access */ + sdla_bus_read_4(hw, AFT_CHIP_CFG_REG, ®1); + reg = reg1; + wan_clear_bit(AFT_CHIPCFG_SFR_IN_BIT, ®); + wan_clear_bit(AFT_CHIPCFG_SFR_EX_BIT, ®); + sdla_bus_write_4(hw, AFT_CHIP_CFG_REG, reg); + + if (hw->hwcard->adptr_subtype == AFT_SUBTYPE_SHARK){ + cpld_off = AFT_SH_CPLD_BOARD_STATUS_REG; + sdla_hw_read_cpld(hw, cpld_off, &status); + hw->hwcard->hwec_chan_no = A104_ECCHAN(AFT_SH_SECURITY(status)); + }else{ + + cpld_off = AFT_SECURITY_CPLD_REG; + sdla_hw_read_cpld(hw, cpld_off, &tmp); + adptr_sec = AFT_GET_SECURITY(tmp); + if (adptr_sec == AFT_SECURITY_1LINE_UNCH){ + hw->hwcard->adptr_security = AFT_SECURITY_UNCHAN; + }else if (adptr_sec == AFT_SECURITY_1LINE_CH){ + hw->hwcard->adptr_security = AFT_SECURITY_CHAN; + }else if (adptr_sec == 0x02){ + /*FIXME: ALEX CHANGE HARDCODED VALUE FOR SHARK */ + hw->hwcard->adptr_security = AFT_SECURITY_CHAN; + }else{ + DEBUG_EVENT( + "%s: AFT-A104 Critical error: Unknown Security ID (%02X)!\n", + wan_drvname, adptr_sec); + } + } + + /* Restore original value */ + sdla_bus_write_4(hw, AFT_CHIP_CFG_REG, reg1); + break; + + case A108_ADPTR_8TE1: + /* Enable memory access */ + sdla_bus_read_4(hw, AFT_CHIP_CFG_REG, ®1); + reg = reg1; + wan_clear_bit(AFT_CHIPCFG_SFR_IN_BIT, ®); + wan_clear_bit(AFT_CHIPCFG_SFR_EX_BIT, ®); + sdla_bus_write_4(hw, AFT_CHIP_CFG_REG, reg); + + if (hw->hwcard->adptr_subtype == AFT_SUBTYPE_SHARK){ + cpld_off = AFT_SH_CPLD_BOARD_STATUS_REG; + sdla_hw_read_cpld(hw, cpld_off, &status); + hw->hwcard->hwec_chan_no = A108_ECCHAN(AFT_SH_SECURITY(status)); + } + + /* Restore original value */ + sdla_bus_write_4(hw, AFT_CHIP_CFG_REG, reg1); + break; + + case A300_ADPTR_U_1TE3: + /* By default, AFT-A300 is unchannelized! */ + hw->hwcard->adptr_security = AFT_SECURITY_UNCHAN; + break; + + case A200_ADPTR_ANALOG: + /* Enable memory access */ + sdla_bus_read_4(hw, AFT_CHIP_CFG_REG, ®1); + reg = reg1; + wan_clear_bit(AFT_CHIPCFG_SFR_IN_BIT, ®); + wan_clear_bit(AFT_CHIPCFG_SFR_EX_BIT, ®); + sdla_bus_write_4(hw, AFT_CHIP_CFG_REG, reg); + + if (hw->hwcard->adptr_subtype == AFT_SUBTYPE_SHARK){ + cpld_off = A200_SH_CPLD_BOARD_STATUS_REG; + sdla_hw_read_cpld(hw, cpld_off, &status); + hw->hwcard->hwec_chan_no = A200_ECCHAN(AFT_SH_SECURITY(status)); + + if (hw->hwcard->hwec_chan_no){ + + /* Check EC access */ + /* Clear octasic reset */ + cpld_off = 0x00; + sdla_hw_write_cpld(hw, cpld_off, 0x01); + + /* Set octasic reset */ + cpld_off = 0x00; + sdla_hw_write_cpld(hw, cpld_off, 0x00); + } + } + + /* Restore original value */ + sdla_bus_write_4(hw, AFT_CHIP_CFG_REG, reg1); + break; + } + sdla_memory_unmap(hw); + return 0; +} + +/* +***************************************************************************** +** sdla_hw_select +***************************************************************************** +*/ +static int sdla_s514_hw_select (sdlahw_card_t* hwcard, int cpu_no, int irq, void* dev) +{ + sdlahw_t* hw=NULL; + int number_of_cards = 0; + + hwcard->cfg_type = WANOPT_S51X; + hwcard->type = SDLA_S514; + sdla_adapter_cnt.s514x_adapters++; + switch(hwcard->adptr_type){ + case S5144_ADPTR_1_CPU_T1E1: + if ((hw = sdla_hw_register(hwcard, cpu_no, irq, dev)) == NULL){ + return -EINVAL; + } + sdla_get_adptr_name(hw); + DEBUG_EVENT( + "%s: %s T1/E1 card found, cpu(s) 1, bus #%d, slot #%d, irq #%d\n", + wan_drvname, + hwcard->adptr_name, + hwcard->bus_no, hwcard->slot_no, irq); + + sdla_save_hw_probe(hw, 0); + sdla_save_hw_probe(hw, 1); + number_of_cards += 2; + break; + + case S5145_ADPTR_1_CPU_56K: + if ((hw = sdla_hw_register(hwcard, cpu_no, irq, dev)) == NULL){ + return -EINVAL; + } + sdla_get_adptr_name(hw); + DEBUG_EVENT( + "%s: %s 56K card found, cpu(s) 1, bus #%d, slot #%d, irq #%d\n", + wan_drvname, + hwcard->adptr_name, + hwcard->bus_no, hwcard->slot_no, irq); + + sdla_save_hw_probe(hw, 0); + sdla_save_hw_probe(hw, 1); + number_of_cards += 2; + break; + + + case S5142_ADPTR_2_CPU_SERIAL: + if ((hw = sdla_hw_register(hwcard, cpu_no, irq, dev)) == NULL){ + return -EINVAL; + } + sdla_get_adptr_name(hw); + /* Print the message only for CPU A. + ** BSD calls this function for both CPUs */ + if (cpu_no == SDLA_CPU_A){ + DEBUG_EVENT( + "%s: %s V35/RS232 card found, cpu(s) 2, bus #%d, slot #%d, irq #%d\n", + wan_drvname, + hwcard->adptr_name, + hwcard->bus_no, hwcard->slot_no, irq); + }else{ +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) + sdla_adapter_cnt.s514x_adapters--; +#endif + } + + sdla_save_hw_probe(hw, 0); + sdla_save_hw_probe(hw, 1); + number_of_cards += 2; +#if defined(__LINUX__) + if ((hw = sdla_hw_register(hwcard, SDLA_CPU_B, irq, dev)) == NULL){ + return -EINVAL; + } + sdla_save_hw_probe(hw, 0); + sdla_save_hw_probe(hw, 1); + number_of_cards += 2; +#endif + break; + + + case S5143_ADPTR_1_CPU_FT1: + if ((hw = sdla_hw_register(hwcard, cpu_no, irq, dev)) == NULL){ + return -EINVAL; + } + sdla_get_adptr_name(hw); + DEBUG_EVENT( + "%s: %s FT1 card found, cpu(s) 1, bus #%d, slot #%d, irq #%d\n", + wan_drvname, + hwcard->adptr_name, + hwcard->bus_no, hwcard->slot_no, irq); + + sdla_save_hw_probe(hw, 0); + number_of_cards += 1; + break; + + case S5147_ADPTR_2_CPU_T1E1: + if ((hw = sdla_hw_register(hwcard, cpu_no, irq, dev)) == NULL){ + return -EINVAL; + } + sdla_get_adptr_name(hw); + /* Print the message only for CPU A. + ** BSD calls this function for both CPUs */ + if (cpu_no == SDLA_CPU_A){ + DEBUG_EVENT( + "%s: %s T1/E1 card found, cpu(s) 2, bus #%d, slot #%d, irq #%d\n", + wan_drvname, + hwcard->adptr_name, + hwcard->bus_no, hwcard->slot_no, irq); + }else{ +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) + sdla_adapter_cnt.s514x_adapters--; +#endif + } + + sdla_save_hw_probe(hw, 0); + number_of_cards += 1; +#if defined(__LINUX__) + if ((hw = sdla_hw_register(hwcard, SDLA_CPU_B, irq, dev)) == NULL){ + return -EINVAL; + } + sdla_save_hw_probe(hw, 0); + number_of_cards += 1; +#endif + break; + + case S5148_ADPTR_1_CPU_T1E1: + hwcard->adptr_type = S5144_ADPTR_1_CPU_T1E1; + if ((hw = sdla_hw_register(hwcard, cpu_no, irq, dev)) == NULL){ + return -EINVAL; + } + sdla_get_adptr_name(hw); + DEBUG_EVENT( + "%s: S514-8-PCI T1/E1 card found, cpu(s) 1, bus #%d, slot #%d, irq #%d\n", + wan_drvname, hwcard->bus_no, hwcard->slot_no, irq); + sdla_save_hw_probe(hw, 0); + number_of_cards += 1; + break; + + default: + if ((hw = sdla_hw_register(hwcard, cpu_no, irq, dev)) == NULL){ + return -EINVAL; + } + sdla_get_adptr_name(hw); + DEBUG_EVENT( + "%s: S514-1-PCI V35/RS232/FT1 card found, cpu(s) 1, bus #%d, slot #%d, irq #%d\n", + wan_drvname, hwcard->bus_no, hwcard->slot_no, irq); + sdla_save_hw_probe(hw, 0); + sdla_save_hw_probe(hw, 1); + number_of_cards += 2; + break; + } + return number_of_cards; +} + +static int sdla_adsl_hw_select (sdlahw_card_t* hwcard, int cpu_no, int irq, void* dev) +{ + sdlahw_t* hw=NULL; + int number_of_cards = 0; + + hwcard->cfg_type = WANOPT_ADSL; + hwcard->type = SDLA_ADSL; + switch(hwcard->adptr_type){ + case S518_ADPTR_1_CPU_ADSL: + sdla_adapter_cnt.s518_adapters++; + if ((hw = sdla_hw_register(hwcard, cpu_no, irq, dev)) == NULL){ + return -EINVAL; + } + sdla_get_adptr_name(hw); + DEBUG_EVENT( + "%s: %s ADSL card found, cpu(s) 1, bus #%d, slot #%d, irq #%d\n", + wan_drvname, + hwcard->adptr_name, + hwcard->bus_no, hwcard->slot_no, irq); + sdla_save_hw_probe(hw, 0); + number_of_cards += 1; + break; + + default: + DEBUG_EVENT( + "%s: Unknown GSI adapter (bus #%d, slot #%d, irq #%d)!\n", + wan_drvname, hwcard->bus_no, hwcard->slot_no, irq); + break; + } + + return number_of_cards; +} + + +static int sdla_aft_hw_select (sdlahw_card_t* hwcard, int cpu_no, int irq, void* dev) +{ + sdlahw_t* hw=NULL; + int number_of_cards = 0; + + hwcard->type = SDLA_AFT; + switch(hwcard->adptr_type){ + case A101_ADPTR_1TE1: + hwcard->cfg_type = WANOPT_AFT; + sdla_adapter_cnt.aft101_adapters++; + if ((hw = sdla_hw_register(hwcard, cpu_no, irq, dev)) == NULL){ + return -EINVAL; + } + sdla_get_cpld_info(hw); + sdla_get_adptr_name(hw); + sdla_save_hw_probe(hw, 0); + number_of_cards += 1; + DEBUG_EVENT( + "%s: %s T1/E1 card found (%s rev.%X), cpu(s) 1, bus #%d, slot #%d, irq #%d\n", + wan_drvname, + hwcard->adptr_name, + AFT_CORE_ID_DECODE(hwcard->core_id), + hwcard->core_rev, + hwcard->bus_no, hwcard->slot_no, irq); + break; + + case A101_ADPTR_2TE1: + hwcard->cfg_type = WANOPT_AFT; + sdla_adapter_cnt.aft101_adapters++; + if ((hw = sdla_hw_register(hwcard, cpu_no, irq, dev)) == NULL){ + return -EINVAL; + } + sdla_get_cpld_info(hw); + sdla_get_adptr_name(hw); + sdla_save_hw_probe(hw, 0); + number_of_cards += 1; +#if defined(__LINUX__) + if (hwcard->pci_dev->resource[1].flags){ + if ((hw = sdla_hw_register(hwcard, SDLA_CPU_B, irq, dev)) == NULL){ + return -EINVAL; + } + sdla_save_hw_probe(hw, 0); + number_of_cards += 1; + } +#endif + if (cpu_no == SDLA_CPU_A){ + DEBUG_EVENT( + "%s: %s T1/E1 card found (%s rev.%X), cpu(s) 2, bus #%d, slot #%d, irq #%d\n", + wan_drvname, + hwcard->adptr_name, + AFT_CORE_ID_DECODE(hwcard->core_id), + hwcard->core_rev, + hwcard->bus_no, hwcard->slot_no, irq); + }else{ +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) + sdla_adapter_cnt.aft101_adapters--; +#endif + } + break; + + case A104_ADPTR_4TE1: + hwcard->cfg_type = WANOPT_AFT104; + sdla_adapter_cnt.aft104_adapters++; + if ((hw = sdla_hw_register(hwcard, cpu_no, irq, dev)) == NULL){ + return -EINVAL; + } + sdla_get_cpld_info(hw); + sdla_get_adptr_name(hw); + sdla_save_hw_probe(hw, 0); + number_of_cards ++; + sdla_save_hw_probe(hw, 1); + number_of_cards ++; + sdla_save_hw_probe(hw, 2); + number_of_cards ++; + sdla_save_hw_probe(hw, 3); + number_of_cards ++; + DEBUG_EVENT( + "%s: %s T1/E1 card found (%s rev.%X), cpu(s) 1, line(s) 4, bus #%d, slot #%d, irq #%d\n", + wan_drvname, + hwcard->adptr_name, + AFT_CORE_ID_DECODE(hwcard->core_id), + hwcard->core_rev, + hwcard->bus_no, hwcard->slot_no, irq); + break; + + case A108_ADPTR_8TE1: + hwcard->cfg_type = WANOPT_AFT108; + sdla_adapter_cnt.aft108_adapters++; + if ((hw = sdla_hw_register(hwcard, cpu_no, irq, dev)) == NULL){ + return -EINVAL; + } + sdla_get_cpld_info(hw); + sdla_get_adptr_name(hw); + sdla_save_hw_probe(hw, 0); + number_of_cards ++; + sdla_save_hw_probe(hw, 1); + number_of_cards ++; + sdla_save_hw_probe(hw, 2); + number_of_cards ++; + sdla_save_hw_probe(hw, 3); + number_of_cards ++; + sdla_save_hw_probe(hw, 4); + number_of_cards ++; + sdla_save_hw_probe(hw, 5); + number_of_cards ++; + sdla_save_hw_probe(hw, 6); + number_of_cards ++; + sdla_save_hw_probe(hw, 7); + number_of_cards ++; + DEBUG_EVENT( + "%s: %s T1/E1 card found (%s rev.%X), cpu(s) 1, line(s) 8, bus #%d, slot #%d, irq #%d\n", + wan_drvname, + hwcard->adptr_name, + AFT_CORE_ID_DECODE(hwcard->core_id), + hwcard->core_rev, + hwcard->bus_no, hwcard->slot_no, irq); + break; + + case A300_ADPTR_U_1TE3: + hwcard->cfg_type = WANOPT_AFT300; + sdla_adapter_cnt.aft300_adapters++; + + if ((hw = sdla_hw_register(hwcard, cpu_no, irq, dev)) == NULL){ + return -EINVAL; + } + sdla_get_cpld_info(hw); + sdla_get_adptr_name(hw); + sdla_save_hw_probe(hw, 0); + number_of_cards += 1; + DEBUG_EVENT( + "%s: %s T3/E3 card found (%s rev.%X), cpu(s) 1, bus #%d, slot #%d, irq #%d\n", + wan_drvname, + hwcard->adptr_name, + AFT_CORE_ID_DECODE(hwcard->core_id), + hwcard->core_rev, + hwcard->bus_no, hwcard->slot_no, irq); + break; + + case A200_ADPTR_ANALOG: + hwcard->cfg_type = WANOPT_AFT_ANALOG; + sdla_adapter_cnt.aft200_adapters++; + + if ((hw = sdla_hw_register(hwcard, cpu_no, irq, dev)) == NULL){ + return -EINVAL; + } + sdla_get_cpld_info(hw); + sdla_get_adptr_name(hw); + sdla_save_hw_probe(hw, 0); + number_of_cards += 1; + DEBUG_EVENT( + "%s: %s FXO/FXS card found (%s rev.%X), cpu(s) 1, bus #%d, slot #%d, irq #%d\n", + wan_drvname, + hwcard->adptr_name, + AFT_CORE_ID_DECODE(hwcard->core_id), + hwcard->core_rev, + hwcard->bus_no, hwcard->slot_no, irq); + break; + + default: +#if 1 + hwcard->cfg_type = WANOPT_AFT104; + sdla_adapter_cnt.aft_x_adapters++; + + if ((hw = sdla_hw_register(hwcard, cpu_no, irq, dev)) == NULL){ + return -EINVAL; + } + sdla_get_cpld_info(hw); + sdla_get_adptr_name(hw); + sdla_save_hw_probe(hw, 0); + number_of_cards += 1; + DEBUG_EVENT( + "%s: %s PCI-X card found (%s rev.%X), cpu(s) 1, bus #%d, slot #%d, irq #%d\n", + wan_drvname, + hwcard->adptr_name, + AFT_CORE_ID_DECODE(hwcard->core_id), + hwcard->core_rev, + hwcard->bus_no, hwcard->slot_no, irq); +#else + DEBUG_EVENT( + "%s: Unknown adapter %04X (bus #%d, slot #%d, irq #%d)!\n", + wan_drvname, + hwcard->adptr_type, + hwcard->bus_no, + hwcard->slot_no, + irq); +#endif + break; + } + + return number_of_cards; +} + +/* +***************************************************************************** +** sdla_pci_probe +***************************************************************************** +*/ +#if defined(__LINUX__) +static int sdla_pci_probe(sdlahw_t *hw) +{ + sdlahw_card_t* tmp_hwcard = NULL; + sdlahw_card_t* hwcard = NULL; + int number_pci_cards = 0; + u16 pci_device_id; + u16 PCI_subsys_vendor; + u16 pci_subsystem_id; + struct pci_dev* pci_dev = NULL; + struct pci_bus* bus = NULL; + + WAN_ASSERT(hw == NULL); + WAN_ASSERT(hw->hwcard == NULL); + tmp_hwcard = hw->hwcard; + while ((pci_dev = pci_get_device(V3_VENDOR_ID, V3_DEVICE_ID, pci_dev)) + != NULL) { + + tmp_hwcard->pci_dev = pci_dev; + sdla_pci_read_config_word(hw, + PCI_SUBSYS_VENDOR_WORD, + &PCI_subsys_vendor); + + if(PCI_subsys_vendor != SANGOMA_SUBSYS_VENDOR) + continue; + + sdla_pci_read_config_word(hw, + PCI_SUBSYS_ID_WORD, + &pci_subsystem_id); + + hwcard = sdla_card_register(SDLA_PCI_CARD, + ((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK), + pci_dev->bus->number, + 0); + if (hwcard == NULL){ + continue; + } + hwcard->adptr_type = pci_subsystem_id & 0xFF; + hwcard->pci_dev = pci_dev; + + /* A dual cpu card can support up to 4 physical connections, + * where a single cpu card can support up to 2 physical + * connections. The FT1 card can only support a single + * connection, however we cannot distinguish between a Single + * CPU card and an FT1 card. */ + number_pci_cards += + sdla_s514_hw_select(hwcard, SDLA_CPU_A, pci_dev->irq, NULL); + + } + + /* Search for Pulsar PCI cards */ + pci_dev = NULL; + + while ((pci_dev = pci_get_device(PCI_VENDOR_ID_GSI, PCI_DEVICE_ID_GSI_ADSL, pci_dev)) + != NULL) { + + tmp_hwcard->pci_dev = pci_dev; + sdla_pci_read_config_word(hw, PCI_SUBSYS_ID_WORD, &pci_subsystem_id); + + if ((pci_subsystem_id & 0xFF) != S518_ADPTR_1_CPU_ADSL){ + continue; + } + + hwcard = sdla_card_register(SDLA_PCI_CARD, + ((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK), + pci_dev->bus->number, + 0); + if (hwcard == NULL){ + continue; + } + hwcard->adptr_type = pci_subsystem_id & 0xFF; + hwcard->pci_dev = pci_dev; + + number_pci_cards += + sdla_adsl_hw_select(hwcard, SDLA_CPU_A, pci_dev->irq, NULL); + + } + + pci_dev=NULL; + while((pci_dev = pci_get_device(SANGOMA_PCI_VENDOR, PCI_ANY_ID, pci_dev)) != NULL){ + + bus = pci_dev->bus; + + tmp_hwcard->pci_dev = pci_dev; + /* ALEX 11/18 + * Supporting different aft cards */ + sdla_pci_read_config_word(hw, + PCI_DEVICE_ID_WORD, + &pci_device_id); + if (pci_device_id == SANGOMA_PCI_DEVICE || pci_device_id == SANGOMA_PCI_4_DEVICE){ + /* Old A-series cards, keep original sequence */ + continue; + } + sdla_pci_read_config_word(hw, + PCI_SUBSYS_VENDOR_WORD, + &PCI_subsys_vendor); + sdla_pci_read_config_word(hw, + PCI_SUBSYS_ID_WORD, + &pci_subsystem_id); + + hwcard = sdla_card_register(SDLA_PCI_CARD, + ((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK), + pci_dev->bus->number, + 0); + if (hwcard == NULL){ + continue; + } + + switch(PCI_subsys_vendor){ + case A101_1TE1_SUBSYS_VENDOR: + hwcard->adptr_type = A101_ADPTR_1TE1; + break; + + case A101_2TE1_SUBSYS_VENDOR: + hwcard->adptr_type = A101_ADPTR_2TE1; + break; + + case A104_4TE1_SUBSYS_VENDOR: + hwcard->adptr_type = A104_ADPTR_4TE1; + break; + + case A104_1TE1_SHARK_SUBSYS_VENDOR: + hwcard->adptr_type = A101_ADPTR_1TE1; + hwcard->adptr_subtype = AFT_SUBTYPE_SHARK; + break; + + case A104_2TE1_SHARK_SUBSYS_VENDOR: + hwcard->adptr_type = A101_ADPTR_2TE1; + hwcard->adptr_subtype = AFT_SUBTYPE_SHARK; + break; + + case A104_4TE1_SHARK_SUBSYS_VENDOR: + hwcard->adptr_type = A104_ADPTR_4TE1; + hwcard->adptr_subtype = AFT_SUBTYPE_SHARK; + break; + + case A104_8TE1_SHARK_SUBSYS_VENDOR: + hwcard->adptr_type = A108_ADPTR_8TE1; + hwcard->adptr_subtype = AFT_SUBTYPE_SHARK; + break; + + case A300_UTE3_SHARK_SUBSYS_VENDOR: + hwcard->adptr_type = A300_ADPTR_U_1TE3; + hwcard->adptr_subtype = AFT_SUBTYPE_SHARK; + break; + + case A305_CTE3_SHARK_SUBSYS_VENDOR: + hwcard->adptr_type = A305_ADPTR_C_1TE3; + hwcard->adptr_subtype = AFT_SUBTYPE_SHARK; + break; + + case A200_REMORA_SHARK_SUBSYS_VENDOR: + hwcard->adptr_type = A200_ADPTR_ANALOG; + hwcard->adptr_subtype = AFT_SUBTYPE_SHARK; + break; + + default: + DEBUG_EVENT("%s: Unsupported subsystem vendor id %04X (bus=%d, slot=%d)\n", + wan_drvname, + PCI_subsys_vendor, + pci_dev->bus->number, + ((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK)); + continue; + } + + hwcard->core_id = pci_subsystem_id & AFT_CORE_ID_MASK; + hwcard->core_rev= (pci_subsystem_id & AFT_CORE_REV_MASK) >> 8; + hwcard->pci_dev = pci_dev; + number_pci_cards += + sdla_aft_hw_select(hwcard, SDLA_CPU_A, pci_dev->irq, NULL); + /* ALEX sdla_adapter_cnt.AFT_adapters++; */ + } + + pci_dev=NULL; + while((pci_dev = pci_get_device(SANGOMA_PCI_VENDOR, SANGOMA_PCI_DEVICE, pci_dev)) != NULL){ + + bus = pci_dev->bus; + + tmp_hwcard->pci_dev = pci_dev; + /* ALEX 11/18 + * Supporting different aft cards */ + sdla_pci_read_config_word(hw, + PCI_SUBSYS_VENDOR_WORD, + &PCI_subsys_vendor); + + hwcard = sdla_card_register(SDLA_PCI_CARD, + ((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK), + pci_dev->bus->number, + 0); + if (hwcard == NULL){ + continue; + } + + switch(PCI_subsys_vendor){ + case A101_1TE1_SUBSYS_VENDOR: + hwcard->adptr_type = A101_ADPTR_1TE1; + break; + + case A101_2TE1_SUBSYS_VENDOR: + hwcard->adptr_type = A101_ADPTR_2TE1; + break; + + case A300_UTE3_SUBSYS_VENDOR: + hwcard->adptr_type = A300_ADPTR_U_1TE3; + break; + + default: + DEBUG_EVENT("%s: Unsupported subsystem vendor id %04X (bus=%d, slot=%d)\n", + wan_drvname, + PCI_subsys_vendor, + pci_dev->bus->number, + ((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK)); + continue; + } + + sdla_pci_read_config_word(hw, + PCI_SUBSYS_ID_WORD, + &pci_subsystem_id); + hwcard->core_id = pci_subsystem_id & AFT_CORE_ID_MASK; + hwcard->core_rev= (pci_subsystem_id & AFT_CORE_REV_MASK) >> 8; + hwcard->pci_dev = pci_dev; + number_pci_cards += + sdla_aft_hw_select(hwcard, SDLA_CPU_A, pci_dev->irq, NULL); + /*ALEX sdla_adapter_cnt.AFT_adapters++; */ + } + + pci_dev=NULL; + while((pci_dev = pci_get_device(SANGOMA_PCI_VENDOR, SANGOMA_PCI_4_DEVICE, pci_dev)) != NULL){ + + bus = pci_dev->bus; + + tmp_hwcard->pci_dev = pci_dev; + /* ALEX 11/18 + * Supporting different aft cards */ + sdla_pci_read_config_word(hw, + PCI_SUBSYS_VENDOR_WORD, + &PCI_subsys_vendor); + sdla_pci_read_config_word(hw, + PCI_SUBSYS_ID_WORD, + &pci_subsystem_id); + + hwcard = sdla_card_register(SDLA_PCI_CARD, + ((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK), + pci_dev->bus->number, + 0); + if (hwcard == NULL){ + continue; + } + + switch(PCI_subsys_vendor){ + case A101_1TE1_SUBSYS_VENDOR: + hwcard->adptr_type = A101_ADPTR_1TE1; + break; + + case A101_2TE1_SUBSYS_VENDOR: + hwcard->adptr_type = A101_ADPTR_2TE1; + break; + + case A104_4TE1_SUBSYS_VENDOR: + hwcard->adptr_type = A104_ADPTR_4TE1; + break; + + case A104_4TE1_SHARK_SUBSYS_VENDOR: + hwcard->adptr_type = A104_ADPTR_4TE1; + hwcard->adptr_subtype = AFT_SUBTYPE_SHARK; + break; + + default: + DEBUG_EVENT("%s: Unsupported subsystem vendor id %04X (bus=%d, slot=%d)\n", + wan_drvname, + PCI_subsys_vendor, + pci_dev->bus->number, + ((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK)); + continue; + } + + hwcard->core_id = pci_subsystem_id & AFT_CORE_ID_MASK; + hwcard->core_rev= (pci_subsystem_id & AFT_CORE_REV_MASK) >> 8; + hwcard->pci_dev = pci_dev; + number_pci_cards += + sdla_aft_hw_select(hwcard, SDLA_CPU_A, pci_dev->irq, NULL); + /* ALEX sdla_adapter_cnt.AFT_adapters++; */ + } + + pci_dev=NULL; + while ((pci_dev = pci_get_device(SANGOMA_PCI_VENDOR_OLD, SANGOMA_PCI_DEVICE, pci_dev)) + != NULL) { + + bus = pci_dev->bus; + + tmp_hwcard->pci_dev = pci_dev; + /* ALEX 11/18 + * Supporting different aft cards */ + sdla_pci_read_config_word(hw, + PCI_SUBSYS_VENDOR_WORD, + &PCI_subsys_vendor); + + hwcard = sdla_card_register(SDLA_PCI_CARD, + ((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK), + pci_dev->bus->number, + 0); + if (hwcard == NULL){ + continue; + } + + switch(PCI_subsys_vendor){ + case A101_1TE1_SUBSYS_VENDOR: + hwcard->adptr_type = A101_ADPTR_1TE1; + break; + + case A101_2TE1_SUBSYS_VENDOR: + hwcard->adptr_type = A101_ADPTR_2TE1; + break; + + case A300_UTE3_SUBSYS_VENDOR: + hwcard->adptr_type = A300_ADPTR_U_1TE3; + break; + + default: + DEBUG_EVENT("%s: Unsupported subsystem vendor id %04X (bus=%d, slot=%d)\n", + wan_drvname, + PCI_subsys_vendor, + pci_dev->bus->number, + ((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK)); + continue; + } + + sdla_pci_read_config_word(hw, + PCI_SUBSYS_ID_WORD, + &pci_subsystem_id); + hwcard->core_id = pci_subsystem_id & AFT_CORE_ID_MASK; + hwcard->core_rev= (pci_subsystem_id & AFT_CORE_REV_MASK) >> 8; + hwcard->pci_dev = pci_dev; + number_pci_cards += + sdla_aft_hw_select(hwcard, SDLA_CPU_A, pci_dev->irq, NULL); + /* ALEX sdla_adapter_cnt.AFT_adapters++; */ + } + + pci_dev = NULL; + while ((pci_dev = pci_get_device(PLX_VENDOR_ID, PLX_DEVICE_ID, pci_dev)) + != NULL) { + + tmp_hwcard->pci_dev = pci_dev; + //sdla_pci_read_config_word(hw, + // PCI_SUBSYS_VENDOR_WORD, + // &PCI_subsys_vendor); + + //if(PCI_subsys_vendor != SANGOMA_SUBSYS_VENDOR) + // continue; + + //sdla_pci_read_config_word(hw, + // PCI_SUBSYS_ID_WORD, + // &pci_subsystem_id); + + hwcard = sdla_card_register(SDLA_PCI_CARD, + ((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK), + pci_dev->bus->number, + 0); + if (hwcard == NULL){ + continue; + } + + //hwcard->adptr_type = pci_subsystem_id & 0xFF; + hwcard->adptr_type = A104_ADPTR_X_4TE1; + hwcard->adptr_subtype = AFT_SUBTYPE_SHARK; + hwcard->pci_dev = pci_dev; + + number_pci_cards += + sdla_aft_hw_select(hwcard, SDLA_CPU_A, pci_dev->irq, NULL); + + } + + return number_pci_cards; +} +#endif + +/* +***************************************************************************** +** sdla_hw_probe +***************************************************************************** +*/ +EXPORT_SYMBOL(sdla_hw_probe); + +unsigned int sdla_hw_probe(void) +{ + sdlahw_card_t* hwcard; + sdlahw_t* hw; +#if defined(__LINUX__) + sdlahw_card_t tmp_hwcard; + sdlahw_t tmp_hw; + unsigned* opt = s508_port_options; + unsigned int cardno=0; + int i; + + //if (!WAN_LIST_EMPTY(&sdlahw_card_head)){ + // DEBUG_EVENT("ADBG> SDLA_HW_PROBE: Number configured cards %d\n", + // cardno); + // return cardno; + //} + + memset(&tmp_hw, 0, sizeof(tmp_hw)); + tmp_hw.hwcard = &tmp_hwcard; + tmp_hw.magic = SDLADRV_MAGIC; + + for (i = 1; i <= opt[0]; i++) { + tmp_hwcard.hw_type = SDLA_ISA_CARD; + tmp_hwcard.ioport = opt[i]; + if (!sdla_detect_s508(&tmp_hw)){ + DEBUG_EVENT("%s: S508-ISA card found, port 0x%x\n", + wan_drvname, tmp_hwcard.ioport); + hwcard = sdla_card_register(SDLA_ISA_CARD, + 0, + 0, + tmp_hwcard.ioport); + if (hwcard == NULL){ + continue; + } + hwcard->adptr_type = 0x00; + hwcard->pci_dev = NULL; + hwcard->cfg_type = WANOPT_S50X; + + hw = sdla_hw_register(hwcard, SDLA_CPU_A, 0, NULL); + if (hw == NULL){ + sdla_card_unregister ( + SDLA_ISA_CARD, + 0, + 0, + tmp_hwcard.ioport); + continue; + } + sdla_save_hw_probe(hw, 1); + sdla_save_hw_probe(hw, 0); + + /* S508 card can support up to two physical links */ + cardno += 2; + + sdla_adapter_cnt.s508_adapters++; + } + tmp_hwcard.ioport = 0x00; + } + +# ifdef CONFIG_PCI + tmp_hwcard.hw_type = SDLA_PCI_CARD; + tmp_hwcard.slot_no = 0; + tmp_hwcard.bus_no = 0; + cardno += sdla_pci_probe(&tmp_hw); +# else + DEBUG_EVENT( "Warning, Kernel not compiled for PCI support!\n"); + DEBUG_EVENT( "PCI Hardware Probe Failed!\n"); +# endif + + return cardno; +#else + sdladev_t* dev = NULL; + sdla_pci_dev_t pci_dev = NULL; + int cnt = 0; + + for(cnt=0; cnt< Sangoma_cards_no; cnt++){ + + dev = &sdladev[cnt]; + if (dev->type == SDLA_S508){ + DEBUG_EVENT( "%s: S508-ISA card found, port 0x%x\n", + wan_drvname, sdladev_ioport(dev)); + hwcard = sdla_card_register( + SDLA_ISA_CARD, + 0, + 0, + sdladev_ioport(dev)); + if (hwcard == NULL) continue; + + hwcard->adptr_type = 0x00; + hwcard->pci_dev = NULL; + hwcard->cfg_type = WANOPT_S50X; + + hw = sdla_hw_register(hwcard, SDLA_CPU_A, 0, dev); + if (hw == NULL){ + sdla_card_unregister ( + SDLA_ISA_CARD, + 0, + 0, + sdladev_ioport(dev)); + continue; + } + hw->irq = sdladev_irq(dev); + hw->dpmbase = sdladev_maddr(dev); + +#if defined(__NetBSD__) || defined(__OpenBSD__) + hw->ioh = dev->u.isa.ioh; + hwcard->iot = dev->sc->ia.ia_iot; + hwcard->memt = dev->sc->ia.ia_memt; +#endif + sdla_save_hw_probe(hw, 1); + sdla_save_hw_probe(hw, 0); + + sdla_adapter_cnt.s508_adapters++; + continue; + } +# if defined(__FreeBSD__) +# if (__FreeBSD_version > 400000) + pci_dev = dev->sc->dev; +# else + pci_dev = dev->u.pci.pci_dev; +# endif +# else + pci_dev = &dev->sc->pa; +# endif + + hwcard = sdla_card_register(SDLA_PCI_CARD, + sdladev_slot(dev), + sdladev_bus(dev), + 0); + if (hwcard == NULL){ + continue; + } + hwcard->adptr_type = dev->adapter_type; + hwcard->adptr_subtype = dev->adapter_subtype; + hwcard->pci_dev = pci_dev; +#if defined(__NetBSD__) || defined(__OpenBSD__) + hwcard->memt = pci_dev->pa_memt; +#endif + switch(dev->vendor_id){ + case V3_VENDOR_ID: + if (dev->subvendor_id == SANGOMA_SUBSYS_VENDOR){ + sdla_s514_hw_select(hwcard, + sdladev_cpu(dev), + sdladev_irq(dev), + dev); + + }else if (dev->device_id == SANGOMA_PCI_DEVICE){ + hwcard->core_id = + dev->subsystem_id & AFT_CORE_ID_MASK; + hwcard->core_rev= + (dev->subsystem_id & AFT_CORE_REV_MASK) >> 8; + sdla_aft_hw_select(hwcard, + sdladev_cpu(dev), + sdladev_irq(dev), + dev); + }else{ + DEBUG_EVENT("%s: Unknown Sangoma device (%04X)\n", + wan_drvname, dev->device_id); + } + break; + + case PCI_VENDOR_ID_GSI: + sdla_adsl_hw_select(hwcard, + sdladev_cpu(dev), + sdladev_irq(dev), + dev); + break; + + case SANGOMA_PCI_VENDOR: + hwcard->core_id = + dev->subsystem_id & AFT_CORE_ID_MASK; + hwcard->core_rev= + (dev->subsystem_id & AFT_CORE_REV_MASK) >> 8; + sdla_aft_hw_select(hwcard, + sdladev_cpu(dev), + sdladev_irq(dev), + dev); + break; + + default: + DEBUG_EVENT("%s: Unknown Sangoma card (%04X)\n", + wan_drvname, dev->vendor_id); + } + } + return Sangoma_devices_no; +#endif +} + +/* +***************************************************************************** +** sdla_get_hw_probe +***************************************************************************** +*/ +EXPORT_SYMBOL(sdla_get_hw_probe); +void *sdla_get_hw_probe (void) +{ + return WAN_LIST_FIRST(&sdlahw_probe_head); +} + +/* +***************************************************************************** +** sdla_get_hw_adptr_cnt +***************************************************************************** +*/ +EXPORT_SYMBOL(sdla_get_hw_adptr_cnt); +void *sdla_get_hw_adptr_cnt (void) +{ + return &sdla_adapter_cnt; +} + +/* +***************************************************************************** +** sdla_card_register +***************************************************************************** +*/ +static sdlahw_card_t* +sdla_card_register(unsigned char hw_type, int slot_no, int bus_no, int ioport) +{ + sdlahw_card_t *new_hwcard, *last_hwcard; + + new_hwcard = sdla_card_search(hw_type, slot_no, bus_no, ioport); + if (new_hwcard){ + if (hw_type == SDLA_PCI_CARD){ + DEBUG_EVENT("%s: Card is already exists (slot=%d,bus=%d)!\n", + __FUNCTION__, + slot_no, + bus_no); + }else{ + DEBUG_EVENT("%s: Card is already exists (ioport=%d)!\n", + __FUNCTION__, + ioport); + } + return NULL; + } + new_hwcard = wan_malloc(sizeof(sdlahw_card_t)); + if (!new_hwcard){ + return NULL; + } + + memset(new_hwcard,0,sizeof(sdlahw_card_t)); + + new_hwcard->hw_type = hw_type; + new_hwcard->slot_no = slot_no; + new_hwcard->bus_no = bus_no; + new_hwcard->ioport = ioport; + wan_spin_lock_init(&new_hwcard->pcard_lock); + + WAN_LIST_FOREACH(last_hwcard, &sdlahw_card_head, next){ + if (!WAN_LIST_NEXT(last_hwcard, next)){ + break; + } + } + if (last_hwcard){ + WAN_LIST_INSERT_AFTER(last_hwcard, new_hwcard, next); + }else{ + WAN_LIST_INSERT_HEAD(&sdlahw_card_head, new_hwcard, next); + + } + return new_hwcard; +} + +/* +***************************************************************************** +** sdla_card_unregister +***************************************************************************** +*/ +static int +sdla_card_unregister (unsigned char hw_type, int slot_no, int bus_no, int ioport) +{ + sdlahw_card_t* tmp_card; + + WAN_LIST_FOREACH(tmp_card, &sdlahw_card_head, next){ + if (tmp_card->hw_type != hw_type){ + continue; + } + if (tmp_card->hw_type == SDLA_PCI_CARD && + tmp_card->slot_no == slot_no && tmp_card->bus_no == bus_no){ + break; + }else if (tmp_card->hw_type == SDLA_ISA_CARD && + tmp_card->ioport == ioport){ + break; + } + } + if (tmp_card == NULL){ + if (hw_type == SDLA_PCI_CARD){ + DEBUG_EVENT("%s: Error: Card didn't find (slot=%d,bus=%d)\n", + __FUNCTION__, + slot_no, + bus_no); + }else{ + DEBUG_EVENT("%s: Error: Card didn't find (ioport=%d)\n", + __FUNCTION__, + ioport); + } + return -EFAULT; + } + if (tmp_card->used){ + if (hw_type == SDLA_PCI_CARD){ + DEBUG_EVENT("%s: Error: This card is still in used (slot=%d,bus=%d,used=%d)\n", + __FUNCTION__, + slot_no, + bus_no, + tmp_card->used); + }else{ + DEBUG_EVENT("%s: Error: This card is still in used (ioport=%d,used=%d)\n", + __FUNCTION__, + ioport, + tmp_card->used); + } + return -EBUSY; + } + WAN_LIST_REMOVE(tmp_card, next); + wan_free(tmp_card); + return 0; +} +/* +***************************************************************************** +** sdla_card_search +***************************************************************************** +*/ +static sdlahw_card_t* +sdla_card_search(unsigned char hw_type, int slot_no, int bus_no, int ioport) +{ + sdlahw_card_t* tmp_card; + + WAN_LIST_FOREACH(tmp_card, &sdlahw_card_head, next){ + if (tmp_card->hw_type != hw_type){ + continue; + } + switch(tmp_card->hw_type){ + case SDLA_PCI_CARD: + if (tmp_card->slot_no == slot_no && tmp_card->bus_no == bus_no){ + return tmp_card; + } + break; + case SDLA_ISA_CARD: + if (tmp_card->ioport == ioport){ + return tmp_card; + } + break; + } + } + return NULL; +} + +/* +***************************************************************************** +** sdla_cpu_register +***************************************************************************** +*/ +static sdlahw_t* +sdla_hw_register(sdlahw_card_t* hwcard, int cpu_no, int irq, void* dev) +{ + sdlahw_t *new_hw, *last_hw; + + new_hw = sdla_hw_search(hwcard->hw_type, hwcard->slot_no, hwcard->bus_no, hwcard->ioport, cpu_no); + if (new_hw){ + if (hwcard->hw_type == SDLA_PCI_CARD){ + DEBUG_TEST("%s: CPU is already exists (slot=%d,bus=%d,cpu=%c)!\n", + __FUNCTION__, + hwcard->slot_no, + hwcard->bus_no, + SDLA_GET_CPU(cpu_no)); + }else{ + DEBUG_TEST("%s: CPU is already exists (ioport=%d)!\n", + __FUNCTION__, + hwcard->ioport); + } + return NULL; + } + new_hw = wan_malloc(sizeof(sdlahw_t)); + if (!new_hw) + return NULL; + + memset(new_hw,0,sizeof(sdlahw_t)); + new_hw->devname = NULL; + new_hw->cpu_no = cpu_no; + new_hw->irq = irq; + new_hw->hwcard = hwcard; + new_hw->dev = dev; + new_hw->magic = SDLADRV_MAGIC; + hwcard->used++; + + + WAN_LIST_FOREACH(last_hw, &sdlahw_head, next){ + if (!WAN_LIST_NEXT(last_hw, next)){ + break; + } + } + if (last_hw){ + WAN_LIST_INSERT_AFTER(last_hw, new_hw, next); + }else{ + WAN_LIST_INSERT_HEAD(&sdlahw_head, new_hw, next); + + } + return new_hw; +} + +/* +***************************************************************************** +** sdla_hw_unregister +***************************************************************************** +*/ +static int +sdla_hw_unregister (sdlahw_card_t* hwcard, int cpu_no) +{ + sdlahw_t* tmp_hw; + int i; + + WAN_LIST_FOREACH(tmp_hw, &sdlahw_head, next){ + if (tmp_hw->hwcard != hwcard){ + continue; + } + if (tmp_hw->cpu_no == cpu_no){ + break; + } + } + if (tmp_hw == NULL){ + if (hwcard->hw_type == SDLA_PCI_CARD){ + DEBUG_EVENT("%s: Error: Devive didn't find (slot=%d,bus=%d,cpu=%c)\n", + __FUNCTION__, + hwcard->slot_no, + hwcard->bus_no, + SDLA_GET_CPU(cpu_no)); + }else{ + DEBUG_EVENT("%s: Error: Device didn't find (ioport=%d,cpu=%c)\n", + __FUNCTION__, + hwcard->ioport, + SDLA_GET_CPU(cpu_no)); + } + return -EFAULT; + } + if (tmp_hw->used){ + if (hwcard->hw_type == SDLA_PCI_CARD){ + DEBUG_EVENT("%s: Error: This cpu is still in used (slot=%d,bus=%d,cpu=%c,used=%d)\n", + __FUNCTION__, + hwcard->slot_no, + hwcard->bus_no, + SDLA_GET_CPU(cpu_no), + hwcard->used); + }else{ + DEBUG_EVENT("%s: Error: This cpu is still in used (ioport=%d, used=%d)\n", + __FUNCTION__, + hwcard->ioport, + hwcard->used); + } + return -EBUSY; + } + for(i = 0; i < SDLA_MAX_PORTS; i++){ + if (tmp_hw->hwport[i].hwprobe){ + tmp_hw->hwport[i].hwprobe->used--; + tmp_hw->hwport[i].hwprobe = NULL; + } + } + tmp_hw->hwcard = NULL; + + hwcard->used--; /* Decrement card usage */ + WAN_LIST_REMOVE(tmp_hw, next); + wan_free(tmp_hw); + return 0; +} + +/* +***************************************************************************** +** sdla_cpu_search +***************************************************************************** +*/ +static sdlahw_t* +sdla_hw_search(unsigned char hw_type, int slot_no, int bus_no, int ioport, int cpu_no) +{ + sdlahw_t* tmp_hw; + + WAN_LIST_FOREACH(tmp_hw, &sdlahw_head, next){ + if (tmp_hw->hwcard == NULL){ + DEBUG_EVENT("%s: Critical Error: line %d\n", + __FUNCTION__,__LINE__); + continue; + } + if (tmp_hw->hwcard->hw_type != hw_type){ + continue; + } + switch(hw_type){ + case SDLA_PCI_CARD: + if (tmp_hw->hwcard->slot_no == slot_no && + tmp_hw->hwcard->bus_no == bus_no && + tmp_hw->cpu_no == cpu_no){ + return tmp_hw; + } + break; + case SDLA_ISA_CARD: + if (tmp_hw->hwcard->ioport == ioport){ + return tmp_hw; + } + break; + } + } + return NULL; +} + + +/* +***************************************************************************** +***************************************************************************** +*** S A N G O M A H A R D W A R E R E G I S T E R ***** +***************************************************************************** +***************************************************************************** +*/ +/* +***************************************************************************** +** sdla_register +***************************************************************************** +*/ +EXPORT_SYMBOL(sdla_register); + +void* sdla_register(sdlahw_iface_t* hw_iface, wandev_conf_t* conf, char* devname) +{ + sdlahw_card_t* hwcard = NULL; + sdlahw_t* hw = NULL; + + if (sdla_register_check(conf, devname)){ + return NULL; + } + + hw = sdla_find_adapter(conf, devname); + if (hw == NULL || hw->hwcard == NULL || hw->used >= hw->max_ports){ + return NULL; + } + hwcard = hw->hwcard; + + hw_iface->setup = sdla_setup; + hw_iface->down = sdla_down; +#if defined(CONFIG_PRODUCT_WANPIPE_GENERIC) + hw_iface->load = sdla_load; +#endif + hw_iface->intack = sdla_intack; + hw_iface->read_int_stat = sdla_read_int_stat; + hw_iface->mapmem = sdla_mapmem; + hw_iface->check_mismatch= sdla_check_mismatch; + hw_iface->peek = sdla_peek; + hw_iface->poke = sdla_poke; + hw_iface->poke_byte = sdla_poke_byte; + hw_iface->getcfg = sdla_getcfg; + hw_iface->isa_read_1 = sdla_isa_read_1; + hw_iface->isa_write_1 = sdla_isa_write_1; + hw_iface->io_read_1 = sdla_io_read_1; + hw_iface->io_write_1 = sdla_io_write_1; + hw_iface->bus_read_1 = sdla_bus_read_1; + hw_iface->bus_read_2 = sdla_bus_read_2; + hw_iface->bus_read_4 = sdla_bus_read_4; + hw_iface->bus_write_1 = sdla_bus_write_1; + hw_iface->bus_write_2 = sdla_bus_write_2; + hw_iface->bus_write_4 = sdla_bus_write_4; +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) + hw_iface->set_intrhand = sdla_set_intrhand; + hw_iface->restore_intrhand= sdla_restore_intrhand; +#endif + hw_iface->is_te1 = sdla_is_te1; + hw_iface->is_56k = sdla_is_56k; + hw_iface->get_hwcard = sdla_get_hwcard; + hw_iface->get_hwprobe = sdla_get_hwprobe; + hw_iface->hw_lock = sdla_hw_lock; + hw_iface->hw_unlock = sdla_hw_unlock; + hw_iface->pci_map_dma = sdla_pci_map_dma; + hw_iface->pci_unmap_dma = sdla_pci_unmap_dma; + hw_iface->hw_same = sdla_is_same_hwcard; + hw_iface->fe_test_and_set_bit = sdla_hw_fe_test_and_set; + hw_iface->fe_clear_bit = sdla_hw_fe_clear; + switch(hwcard->cfg_type){ + case WANOPT_S50X: + hwcard->type = SDLA_S508; + hw_iface->cmd = sdla_cmd; + hw_iface->set_bit = sdla_set_bit; + hw_iface->clear_bit = sdla_clear_bit; + DEBUG_EVENT("%s: Found: %s card, IoPort=0x%X, Irq=%d\n", + devname, + SDLA_DECODE_CARDTYPE(hwcard->cfg_type), + hwcard->ioport, + hw->irq); + break; + + case WANOPT_S51X: + hwcard->type = SDLA_S514; + hw_iface->load = sdla_load; /* For Edukit */ + hw_iface->hw_halt = sdla_halt; /* For Edukit */ + hw_iface->start = sdla_start; /* For Edukit */ + hw_iface->cmd = sdla_cmd; + hw_iface->set_bit = sdla_set_bit; + hw_iface->clear_bit = sdla_clear_bit; + hw_iface->pci_read_config_byte = sdla_pci_read_config_byte; + hw_iface->pci_read_config_word = sdla_pci_read_config_word; + hw_iface->pci_read_config_dword = sdla_pci_read_config_dword; + hw_iface->pci_write_config_byte = sdla_pci_write_config_byte; + hw_iface->pci_write_config_word = sdla_pci_write_config_word; + hw_iface->pci_write_config_dword = sdla_pci_write_config_dword; + DEBUG_EVENT("%s: Found: %s card, CPU %c, PciSlot=%d, PciBus=%d\n", + devname, + SDLA_DECODE_CARDTYPE(hwcard->cfg_type), + SDLA_GET_CPU(hw->cpu_no), + hwcard->slot_no, + hwcard->bus_no); + break; + + case WANOPT_ADSL: + hwcard->type = SDLA_ADSL; + hw_iface->pci_read_config_byte = sdla_pci_read_config_byte; + hw_iface->pci_read_config_word = sdla_pci_read_config_word; + hw_iface->pci_read_config_dword = sdla_pci_read_config_dword; + hw_iface->pci_write_config_byte = sdla_pci_write_config_byte; + hw_iface->pci_write_config_word = sdla_pci_write_config_word; + hw_iface->pci_write_config_dword = sdla_pci_write_config_dword; + DEBUG_EVENT("%s: Found: %s card, CPU %c, PciSlot=%d, PciBus=%d\n", + devname, + SDLA_DECODE_CARDTYPE(hwcard->cfg_type), + SDLA_GET_CPU(hw->cpu_no), + hwcard->slot_no, + hwcard->bus_no); + break; + + case WANOPT_AFT: + case WANOPT_AFT104: + case WANOPT_AFT108: + case WANOPT_AFT300: + case WANOPT_AFT_ANALOG: + hwcard->type = SDLA_AFT; + hw_iface->set_bit = sdla_set_bit; + hw_iface->clear_bit = sdla_clear_bit; + hw_iface->pci_read_config_byte = sdla_pci_read_config_byte; + hw_iface->pci_read_config_word = sdla_pci_read_config_word; + hw_iface->pci_read_config_dword = sdla_pci_read_config_dword; + hw_iface->pci_write_config_byte = sdla_pci_write_config_byte; + hw_iface->pci_write_config_word = sdla_pci_write_config_word; + hw_iface->pci_write_config_dword = sdla_pci_write_config_dword; + + hw_iface->read_cpld = sdla_hw_read_cpld; + hw_iface->write_cpld = sdla_hw_write_cpld; + + switch(hw->hwcard->adptr_type){ + case A104_ADPTR_4TE1: + case A108_ADPTR_8TE1: + case A200_ADPTR_ANALOG: + DEBUG_EVENT("%s: Found: %s card, CPU %c, PciSlot=%d, PciBus=%d, Port=%d\n", + devname, + SDLA_DECODE_CARDTYPE(hwcard->cfg_type), + SDLA_GET_CPU(hw->cpu_no), + hwcard->slot_no, + hwcard->bus_no, + (conf) ? conf->comm_port : hw->used); + break; + default: + DEBUG_EVENT("%s: Found: %s card, CPU %c, PciSlot=%d, PciBus=%d\n", + devname, + SDLA_DECODE_CARDTYPE(hwcard->cfg_type), + SDLA_GET_CPU(hw->cpu_no), + hwcard->slot_no, + hwcard->bus_no); + break; + } + break; + + default: + DEBUG_EVENT("%s: ERROR, invalid card type! 0x%X\n", + devname, + hwcard->cfg_type); + return NULL; + } + + + /* NC: + * Increment the usage count when we know + * for sure that the hw has been taken */ + hw->hwport[(conf)?conf->comm_port:hw->used].used++; + hw->hwport[(conf)?conf->comm_port:hw->used].devname = devname; + if (!hw->used){ + hw->devname = devname; + } + hw->used++; + + return hw; +} + +/* +***************************************************************************** +** sdla_unregister +***************************************************************************** +*/ +EXPORT_SYMBOL(sdla_unregister); + +int sdla_unregister(void** p_hw, char* devname) +{ + sdlahw_t* hw = *(sdlahw_t**)p_hw; + int port; + + if (hw){ + for(port = 0; port < SDLA_MAX_PORTS; port++){ + if (hw->hwport[port].devname == devname){ + hw->hwport[port].devname = NULL; + hw->hwport[port].used--; + break; + } + } + + hw->used--; + if (!hw->used){ + hw->devname = NULL; + } + + *p_hw = NULL; + } + return 0; +} + +/******* Kernel APIs ********************************************************/ +static int sdla_register_check (wandev_conf_t* conf, char* devname) +{ + if (conf == NULL){ + return 0; + } + /* Create sdlahw_t now */ +#if defined(__LINUX__) + if (conf->card_type != WANOPT_S50X){ +# ifdef CONFIG_PCI + if(!pci_present()){ + DEBUG_EVENT("%s: PCI BIOS not present!\n", devname); + return 0; + } +# else + DEBUG_EVENT( "%s: Linux not compiled for PCI usage!\n", devname); + return 0; +# endif + } +#endif + + if (conf->card_type==WANOPT_S50X){ + DEBUG_EVENT("%s: Locating: %s card, IoPort=0x%X, Irq=%d\n", + devname, + SDLA_DECODE_CARDTYPE(conf->card_type), + conf->ioport, + conf->irq); + }else if (conf->auto_pci_cfg){ + DEBUG_EVENT("%s: Locating: %s card, CPU %c, PciSlot=Auto, PciBus=Auto\n", + devname, + SDLA_DECODE_CARDTYPE(conf->card_type), + conf->S514_CPU_no[0]); + }else{ + DEBUG_EVENT("%s: Locating: %s card, CPU %c, PciSlot=%d, PciBus=%d\n", + devname, + SDLA_DECODE_CARDTYPE(conf->card_type), + conf->S514_CPU_no[0], + conf->PCI_slot_no, + conf->pci_bus_no); + } + + switch(conf->card_type){ + + case WANOPT_S50X: /* Sangoma ISA cards */ + break; + + case WANOPT_S51X: + if (conf->auto_pci_cfg && sdla_adapter_cnt.s514x_adapters > 1){ + DEBUG_EVENT( "%s: HW Autodetect failed: Multiple S514X cards found! \n" + "%s: Disable the Autodetect feature and supply\n" + "%s: the PCI Slot and Bus numbers for each card.\n", + devname,devname,devname); + return -EINVAL; + } + break; + + case WANOPT_ADSL: + if (conf->auto_pci_cfg && sdla_adapter_cnt.s518_adapters > 1){ + DEBUG_EVENT( "%s: HW Autodetect failed: Multiple S518 ADSL cards found! \n" + "%s: Disable the Autodetect feature and supply\n" + "%s: the PCI Slot and Bus numbers for each card.\n", + devname,devname,devname); + return -EINVAL; + } + break; + + case WANOPT_AFT: + if (conf->auto_pci_cfg && sdla_adapter_cnt.aft101_adapters > 1){ + DEBUG_EVENT( "%s: HW Auto PCI failed: Multiple AFT-101/102 cards found! \n" + "%s: Disable the Autodetect feature and supply\n" + "%s: the PCI Slot and Bus numbers for each card.\n", + devname,devname,devname); + return -EINVAL; + } + break; + + case WANOPT_AFT104: + if (conf->auto_pci_cfg && sdla_adapter_cnt.aft104_adapters > 1){ + DEBUG_EVENT( "%s: HW Auto PCI failed: Multiple AFT-104 cards found! \n" + "%s: Disable the Autodetect feature and supply\n" + "%s: the PCI Slot and Bus numbers for each card.\n", + devname,devname,devname); + return -EINVAL; + } + break; + + case WANOPT_AFT108: + if (conf->auto_pci_cfg && sdla_adapter_cnt.aft108_adapters > 1){ + DEBUG_EVENT( "%s: HW Auto PCI failed: Multiple AFT-108 cards found! \n" + "%s: Disable the Autodetect feature and supply\n" + "%s: the PCI Slot and Bus numbers for each card.\n", + devname,devname,devname); + return -EINVAL; + } + break; + + case WANOPT_AFT_ANALOG: + if (conf->auto_pci_cfg && sdla_adapter_cnt.aft200_adapters > 1){ + DEBUG_EVENT( "%s: HW Auto PCI failed: Multiple AFT-ANALOG cards found! \n" + "%s: Disable the Autodetect feature and supply\n" + "%s: the PCI Slot and Bus numbers for each card.\n", + devname,devname,devname); + return -EINVAL; + } + break; + + case WANOPT_AFT300: + if (conf->auto_pci_cfg && sdla_adapter_cnt.aft300_adapters > 1){ + DEBUG_EVENT( "%s: HW Auto PCI failed: Multiple AFT-300 cards found! \n" + "%s: Disable the Autodetect feature and supply\n" + "%s: the PCI Slot and Bus numbers for each card.\n", + devname,devname,devname); + return -EINVAL; + } + break; + + default: + DEBUG_EVENT("%s: Unsupported Sangoma Card (0x%X) requested by user!\n", + devname,conf->card_type); + return -EINVAL; + + } + return 0; +} + +/*============================================================================ + * Set up adapter. + * o detect adapter type + * o verify hardware configuration options + * o check for hardware conflicts + * o set up adapter shared memory + * o test adapter memory + * o load firmware + * Return: 0 ok. + * < 0 error + */ +/* ALEX int sdla_setup (sdlahw_t* hw, void* sfm, unsigned len)*/ +static int sdla_setup (void* phw, wandev_conf_t* conf) +{ + sdlahw_card_t* hwcard = NULL; + sdlahw_t* hw = (sdlahw_t*)phw; + unsigned* irq_opt = NULL; /* IRQ options */ + unsigned* dpmbase_opt = NULL; /* DPM window base options */ + unsigned* pclk_opt = NULL; /* CPU clock rate options */ + int err=0; + + WAN_ASSERT(hw == NULL); + SDLA_MAGIC(hw); + WAN_ASSERT(hw->hwcard == NULL); + hwcard = hw->hwcard; + /* ALEX VVVV*/ + /* for an S514 adapter, pass the CPU number and the slot number read */ + /* from 'router.conf' to the 'sdla_setup()' function via the 'port' */ + /* parameter */ + switch(hwcard->type){ + case SDLA_S514: + + if (conf && !conf->S514_CPU_no[0]){ + DEBUG_EVENT("%s: ERROR, invalid S514 CPU [ A|B ]\n", + hw->devname); + return -EINVAL; + } +#if 0 + if (conf->S514_CPU_no[0] == 'A'){ + hw->cpu_no = SDLA_CPU_A; + }else if (conf->S514_CPU_no[0] == 'B'){ + hw->cpu_no = SDLA_CPU_B; + } + hw->slot_no = conf->PCI_slot_no; + hw->bus_no = conf->pci_bus_no; + hw->auto_pci_cfg = conf->auto_pci_cfg; + + if (hw->auto_pci_cfg == WANOPT_YES){ + DEBUG_EVENT("%s: Setting CPU to %c and Slot to Auto\n", + hw->devname, + SDLA_GET_CPU(hw->cpu_no)); + }else{ + DEBUG_EVENT("%s: Setting CPU to %c and Slot to %i\n", + hw->devname, + SDLA_GET_CPU(hw->cpu_no), + hwcard->slot_no); + } + hw->dpmbase = (sdla_mem_handle_t)conf->maddr; +#endif + break; + + case SDLA_S508: + /* 508 Card io port and irq initialization */ +#if 0 + hw->port = conf->ioport; +#endif + hw->irq = (conf && conf->irq == 9) ? 2 : conf->irq; + if(conf && conf->maddr){ + hw->dpmbase = (sdla_mem_handle_t)phys_to_virt(conf->maddr); + } + break; + + case SDLA_ADSL: +#if 0 + hw->cpu_no = SDLA_CPU_A; + hw->slot_no = conf->PCI_slot_no; + hw->auto_pci_cfg = conf->auto_pci_cfg; + hw->bus_no = conf->pci_bus_no; + + if (hw->auto_pci_cfg == WANOPT_YES){ + DEBUG_EVENT("%s: Setting Slot and Bus to Auto\n", + hw->devname); + }else{ + DEBUG_EVENT("%s: Setting Slot to %i Bus to %i\n", + hw->devname, + hwcard->slot_no, + hwcard->bus_no); + } + hw->dpmbase = (sdla_mem_handle_t)conf->maddr; +#endif + hw->fwid = SFID_ADSL; + break; + + case SDLA_AFT: + + switch(hw->hwcard->adptr_type){ + case A104_ADPTR_4TE1: + case A108_ADPTR_8TE1: + case A200_ADPTR_ANALOG: + if (hw->used > 1){ + if (conf) conf->irq = hw->irq; + return 0; + } + break; + } + + hw->fwid = SFID_AFT; + break; + + default: + DEBUG_EVENT("%s: Invalid card type %x\n", + hw->devname, hw->hwcard->type); + return -EINVAL; + } + + hw->dpmsize = SDLA_WINDOWSIZE; + hw->pclk = (conf) ? conf->hw_opt[1] : 0; + + if (sdla_detect(hw) != 0) { + return -ENODEV; + } + + switch(hwcard->type){ + case SDLA_S502A: + case SDLA_S502E: + case SDLA_S503: + case SDLA_S507: + case SDLA_S508: + DEBUG_EVENT("%s: found S%04u card at port 0x%X.\n", + hw->devname, hwcard->type, hwcard->ioport); + + hw->dpmsize = SDLA_WINDOWSIZE; + + switch(hwcard->type){ + case SDLA_S502A: + hw->io_range = S502A_IORANGE; + irq_opt = s502a_irq_options; + dpmbase_opt = s502a_dpmbase_options; + pclk_opt = s502a_pclk_options; + break; + + case SDLA_S502E: + hw->io_range = S502E_IORANGE; + irq_opt = s502e_irq_options; + dpmbase_opt = s508_dpmbase_options; + pclk_opt = s502e_pclk_options; + break; + + case SDLA_S503: + hw->io_range = S503_IORANGE; + irq_opt = s503_irq_options; + dpmbase_opt = s508_dpmbase_options; + pclk_opt = s503_pclk_options; + break; + + case SDLA_S507: + hw->io_range = S507_IORANGE; + irq_opt = s508_irq_options; + dpmbase_opt = s507_dpmbase_options; + pclk_opt = s507_pclk_options; + break; + + case SDLA_S508: + hw->io_range = S508_IORANGE; + irq_opt = s508_irq_options; + dpmbase_opt = s508_dpmbase_options; + pclk_opt = s508_pclk_options; + break; + } + + /* Verify IRQ configuration options */ + if (!sdla_get_option_index(irq_opt, hw->irq)) { + DEBUG_EVENT("%s: IRQ %d is illegal!\n", + hw->devname, hw->irq); + return -EINVAL; + } + + /* Verify CPU clock rate configuration options */ + if (hw->pclk == 0) + hw->pclk = pclk_opt[1]; /* use default */ + + else if (!sdla_get_option_index(pclk_opt, hw->pclk)) { + DEBUG_EVENT("%s: CPU clock %u is illegal!\n", + hw->devname, hw->pclk); + return -EINVAL; + } + DEBUG_EVENT("%s: assuming CPU clock rate of %u kHz.\n", + hw->devname, hw->pclk); + + /* Setup adapter dual-port memory window and test memory */ + if (hw->dpmbase == 0) { + err = sdla_autodpm(hw); + if (err) { + DEBUG_EVENT("%s: can't find available memory region!\n", + hw->devname); + return err; + } + } + else if (!sdla_get_option_index(dpmbase_opt, + virt_to_phys((void*)hw->dpmbase))) { + DEBUG_EVENT("%s: memory address 0x%lX is illegal!\n", + hw->devname, + (unsigned long)virt_to_phys((void*)hw->dpmbase)); + return -EINVAL; + } + else if (sdla_setdpm(hw)) { + DEBUG_EVENT("%s: 8K memory region at 0x%lX is not available!\n", + hw->devname, + (unsigned long)virt_to_phys((void*)hw->dpmbase)); + return -EINVAL; + } + DEBUG_EVENT("%s: dual-port memory window is set at 0x%lX.\n", + hw->devname, (unsigned long)virt_to_phys((void*)hw->dpmbase)); + + + /* If we find memory in 0xE**** Memory region, + * warn the user to disable the SHADOW RAM. + * Since memory corruption can occur if SHADOW is + * enabled. This can causes random crashes ! */ + if (virt_to_phys((void*)hw->dpmbase) >= 0xE0000){ + DEBUG_EVENT("\n(WARNING) %s: !!!!!!!! WARNING !!!!!!!!\n",hw->devname); + DEBUG_EVENT("(WANRINIG) %s: WANPIPE is using 0x%lX memory region !!!\n", + hw->devname, + (unsigned long)virt_to_phys((void*)hw->dpmbase)); + DEBUG_EVENT("(WARNING) Please disable the SHADOW RAM, otherwise\n"); + DEBUG_EVENT("(WARNING) your system might crash randomly from time to time !\n"); + DEBUG_EVENT("(WARNING) %s: !!!!!!!! WARNING !!!!!!!!\n\n",hw->devname); + } + break; + + case SDLA_S514: + + if (conf) conf->irq = hw->irq; + if (conf && conf->config_id == WANCONFIG_DEBUG){ + hw->memory = MAX_SIZEOF_S514_MEMORY; + return 0; + } + hw->memory = sdla_test_memregion(hw, MAX_SIZEOF_S514_MEMORY); + if(hw->memory < (256 * 1024)) { + DEBUG_EVENT("%s: error in testing S514 memory (0x%lX)\n", + hw->devname, hw->memory); + sdla_down(hw); + return -EINVAL; + } + break; + + case SDLA_ADSL: + if (conf) conf->irq = hw->irq; + return 0; + break; + + case SDLA_AFT: + if (conf) conf->irq = hw->irq; + return 0; + break; + + default: + DEBUG_EVENT("%s: Invalid card type %x\n", + hw->devname, hwcard->type); + return -EINVAL; + } + + DEBUG_EVENT("%s: found %luK bytes of on-board memory\n", + hw->devname, hw->memory / 1024); + + /* Load firmware. If loader fails then shut down adapter */ + if (conf){ + err = sdla_load(hw, conf->data, conf->data_size); + } + if (err){ + sdla_down(hw); /* shutdown adapter */ + } + + return err; +} + + + +/*============================================================================ + * Prepare configuration byte identifying adapter type and CPU clock rate. + */ +static unsigned char sdla_make_config_byte (sdlahw_t* hw) +{ + sdlahw_card_t* card = NULL; + unsigned char byte = 0; + + WAN_ASSERT(hw == NULL); + WAN_ASSERT(hw->hwcard == NULL); + card = hw->hwcard; + switch (hw->pclk) { + case 5000: byte = 0x01; break; + case 7200: byte = 0x02; break; + case 8000: byte = 0x03; break; + case 10000: byte = 0x04; break; + case 16000: byte = 0x05; break; + } + + switch (card->type) { + case SDLA_S502E: byte |= 0x80; break; + case SDLA_S503: byte |= 0x40; break; + } + return byte; +} + +/*============================================================================ + * Prepare boot-time firmware configuration data. + * o position DPM window + * o initialize configuration data area + */ +static int sdla_bootcfg (sdlahw_t* hw, sfm_info_t* sfminfo) +{ + sdlahw_card_t* card = NULL; + unsigned int offset = 0; + + WAN_ASSERT(hw == NULL); + WAN_ASSERT(hw->hwcard == NULL); + card = hw->hwcard; + if (!sfminfo->datasize) return 0; /* nothing to do */ + + if (sdla_mapmem(hw, sfminfo->dataoffs) != 0) + return -EIO; + + if (card->type == SDLA_S514){ + offset = sfminfo->dataoffs; + }else{ + offset = sfminfo->dataoffs - (unsigned long)hw->vector; + } + + sdla_bus_set_region_1(hw, 0x00, 0x00, sfminfo->datasize); + sdla_bus_write_1(hw, offset, sdla_make_config_byte(hw)); + + switch (sfminfo->codeid) { + case SFID_X25_502: + case SFID_X25_508: + sdla_bus_write_1(hw, offset + 0x01, 3); + sdla_bus_write_1(hw, offset + 0x01, 3); /* T1 timer */ + sdla_bus_write_1(hw, offset + 0x03, 10); /* N2 */ + sdla_bus_write_1(hw, offset + 0x06, 7); /* HDLC window size */ + sdla_bus_write_1(hw, offset + 0x0B, 1); /* DTE */ + sdla_bus_write_1(hw, offset + 0x0C, 2); /* X.25 packet window size */ + sdla_bus_write_2(hw, offset + 0x0D, 128); /* default X.25 data size */ + sdla_bus_write_2(hw, offset + 0x0F, 128); /* maximum X.25 data size */ + break; + } + return 0; +} + +/*============================================================================ + * Start adapter's CPU. + * o calculate a pointer to adapter's cold boot entry point + * o position DPM window + * o place boot instruction (jp addr) at cold boot entry point + * o start CPU + */ +static int sdla_start (sdlahw_t* hw, unsigned addr) +{ + sdlahw_card_t* card = NULL; + unsigned int offset = 0; + int err, i; + u8 tmp; + + WAN_ASSERT(hw == NULL); + SDLA_MAGIC(hw); + WAN_ASSERT(hw->hwcard == NULL); + card = hw->hwcard; + if (!card->ioport && (card->type != SDLA_S514)) return -EFAULT; + + switch (card->type) { + case SDLA_S502A: + offset = 0x66; + break; + + case SDLA_S502E: + case SDLA_S503: + case SDLA_S507: + case SDLA_S508: + case SDLA_S514: + break; + + default: + return -EINVAL; + } + + err = sdla_mapmem(hw, 0); + if (err) return err; + + sdla_bus_write_1(hw, offset, 0xC3); + sdla_bus_write_2(hw, offset + 1, addr); + + switch (card->type) { + case SDLA_S502A: + sdla_isa_write_1(hw, 0x00, 0x10); /* issue NMI to CPU */ + hw->regs[0] = 0x10; + break; + + case SDLA_S502E: + sdla_isa_write_1(hw, 0x03, 0x01); /* start CPU */ + hw->regs[3] = 0x01; + for (i = 0; i < SDLA_IODELAY; ++i); + sdla_isa_read_1(hw, 0x00, &tmp); + if (tmp & 0x01) { /* verify */ + /* + * Enabling CPU changes functionality of the + * control register, so we have to reset its + * mirror. + */ + sdla_isa_write_1(hw, 0x00, 0); /* disable interrupts */ + hw->regs[0] = 0; + } + else return -EIO; + break; + + case SDLA_S503: + tmp = hw->regs[0] | 0x09; /* set bits 0 and 3 */ + sdla_isa_write_1(hw, 0x00, tmp); + hw->regs[0] = tmp; /* update mirror */ + for (i = 0; i < SDLA_IODELAY; ++i); + sdla_isa_read_1(hw, 0x00, &tmp); + if (!(tmp & 0x01)) /* verify */ + return -EIO; + break; + + case SDLA_S507: + tmp = hw->regs[0] | 0x02; + sdla_isa_write_1(hw, 0x00, tmp); + hw->regs[0] = tmp; /* update mirror */ + for (i = 0; i < SDLA_IODELAY; ++i); + sdla_isa_read_1(hw, 0x00, &tmp); + if (!(tmp & 0x04)) /* verify */ + return -EIO; + break; + + case SDLA_S508: + tmp = hw->regs[0] | 0x02; + sdla_isa_write_1(hw, 0x00, tmp); + hw->regs[0] = tmp; /* update mirror */ + for (i = 0; i < SDLA_IODELAY; ++i); + sdla_isa_read_1(hw, 0x01, &tmp); + if (!(tmp & 0x02)) /* verify */ + return -EIO; + break; + + case SDLA_S514: + + sdla_io_write_1(hw, 0x00, S514_CPU_START); + break; + + default: + return -EINVAL; + } + return 0; +} + +/*============================================================================ + * Load adapter from the memory image of the SDLA firmware module. + * o verify firmware integrity and compatibility + * o start adapter up + */ +static int sdla_load (void* phw, void* psfm, unsigned len) +{ + sdlahw_card_t* hwcard = NULL; + sdlahw_t* hw = (sdlahw_t*)phw; + sfm_t* sfm = (sfm_t*)psfm; + unsigned char test[256]; + int i; + + WAN_ASSERT(hw == NULL); + SDLA_MAGIC(hw); + WAN_ASSERT(hw->hwcard == NULL); + hwcard = hw->hwcard; + + /* Verify firmware signature */ + if (strcmp(sfm->signature, SFM_SIGNATURE)) { + DEBUG_EVENT("%s: not SDLA firmware!\n", + hw->devname); + return -EINVAL; + } + + /* Verify firmware module format version */ + if (sfm->version != SFM_VERSION) { + DEBUG_EVENT("%s: firmware format %u rejected! Expecting %u.\n", + hw->devname, sfm->version, SFM_VERSION); + return -EINVAL; + } + + /* Verify firmware module length and checksum */ + if ((len - offsetof(sfm_t, image) != sfm->info.codesize) || + (sdla_checksum((void*)&sfm->info, + sizeof(sfm_info_t) + sfm->info.codesize) != sfm->checksum)) { + DEBUG_EVENT("%s: firmware corrupted!\n", hw->devname); + return -EINVAL; + } + + /* Announce */ + DEBUG_EVENT("%s: loading %s (ID=%u)...\n", hw->devname, + (sfm->descr[0] != '\0') ? sfm->descr : "unknown firmware", + sfm->info.codeid); + + if (hwcard->type == SDLA_S514){ + DEBUG_EVENT("%s: loading S514 adapter, CPU %c\n", + hw->devname, SDLA_GET_CPU(hw->cpu_no)); + } + + /* Scan through the list of compatible adapters and make sure our + * adapter type is listed. + */ + for (i = 0; + (i < SFM_MAX_SDLA) && (sfm->info.adapter[i] != hwcard->type); + ++i); + + if (i == SFM_MAX_SDLA){ + DEBUG_EVENT("%s: firmware is not compatible with S%u!\n", + hw->devname, hwcard->type); + return -EINVAL; + } + + + /* Make sure there is enough on-board memory */ + if (hw->memory < sfm->info.memsize){ + DEBUG_EVENT("%s: firmware needs %u bytes of on-board memory!\n", + hw->devname, sfm->info.memsize); + return -EINVAL; + } + + /* Move code onto adapter */ + if (sdla_poke(hw, sfm->info.codeoffs, sfm->image, sfm->info.codesize)) { + DEBUG_EVENT("%s: failed to load code segment!\n", + hw->devname); + return -EIO; + } + if (sdla_peek(hw, sfm->info.codeoffs, test, 100)){ + DEBUG_EVENT("%s: Failed to read from card memory!\n", + hw->devname); + return -EIO; + } + if (strncmp(sfm->image, test, 100) != 0){ + DEBUG_EVENT("%s: failed to test code segment!\n", + hw->devname); + return -EIO; + } + + /* Prepare boot-time configuration data and kick-off CPU */ + sdla_bootcfg(hw, &sfm->info); + + if (sfm->info.codeid != SFID_BSCMP514 && sfm->info.codeid != SFID_POS){ + if (sdla_start(hw, sfm->info.startoffs)) { + DEBUG_EVENT("%s: Damn... Adapter won't start!\n", + hw->devname); + return -EIO; + } + } + + /* position DPM window over the mailbox and enable interrupts */ + if (sdla_mapmem(hw, sfm->info.winoffs) || sdla_inten(hw)) { + DEBUG_EVENT("%s: adapter hardware failure!\n", + hw->devname); + return -EIO; + } + + hw->fwid = sfm->info.codeid; /* set firmware ID */ + return 0; +} + +/* +***************************************************************************** +** sdla_halt +***************************************************************************** +*/ +static int sdla_halt (void* phw) +{ + sdlahw_card_t* card = NULL; + sdlahw_t* hw = (sdlahw_t*)phw; + int i; + + WAN_ASSERT(hw == NULL); + SDLA_MAGIC(hw); + WAN_ASSERT(hw->hwcard == NULL); + card = hw->hwcard; + if(!card->ioport && (card->type != SDLA_S514)) + return -EFAULT; + + switch (card->type) { + case SDLA_S502A: + sdla_isa_write_1(hw, 0x00, 0x08); /* halt CPU */ + sdla_isa_write_1(hw, 0x00, 0x08); + sdla_isa_write_1(hw, 0x00, 0x08); + hw->regs[0] = 0x08; + sdla_isa_write_1(hw, 0x01, 0xFF); /* close memory window */ + hw->regs[1] = 0xFF; + break; + + case SDLA_S502E: + sdla_isa_write_1(hw, 0x03, 0); /* stop CPU */ + sdla_isa_write_1(hw, 0x00, 0); /* reset board */ + for (i = 0; i < S502E_IORANGE; ++i) + hw->regs[i] = 0 + ; + break; + + case SDLA_S503: + case SDLA_S507: + case SDLA_S508: + sdla_isa_write_1(hw, 0x00, 0); /* reset board logic */ + hw->regs[0] = 0; + break; + + case SDLA_S514: + /* halt the adapter */ + sdla_io_write_1(hw, 0x00, S514_CPU_HALT); + /* Test and clear PCI memory */ + sdla_test_memregion(hw, MAX_SIZEOF_S514_MEMORY); + break; + } + return 0; +} + + +/*============================================================================ + * Shut down SDLA: disable shared memory access and interrupts, stop CPU, etc. + */ +static int sdla_down (void* phw) +{ + sdlahw_card_t* card = NULL; + sdlahw_t* hw = (sdlahw_t*)phw; + unsigned int CPU_no; + u32 int_config, int_status; + int i; + + WAN_ASSERT(hw == NULL); + SDLA_MAGIC(hw); + WAN_ASSERT(hw->hwcard == NULL); + card = hw->hwcard; + switch (card->type) { + + case SDLA_S502A: + + if (!card->ioport){ + return -EFAULT; + } + + sdla_isa_write_1(hw, 0x00, 0x08); /* halt CPU */ + sdla_isa_write_1(hw, 0x00, 0x08); + sdla_isa_write_1(hw, 0x00, 0x08); + hw->regs[0] = 0x08; + sdla_isa_write_1(hw, 0x01, 0xFF); /* close memory window */ + hw->regs[1] = 0xFF; + break; + + case SDLA_S502E: + + if (!card->ioport){ + return -EFAULT; + } + + sdla_isa_write_1(hw, 0x03, 0); /* stop CPU */ + sdla_isa_write_1(hw, 0x00, 0); /* reset board */ + for (i = 0; i < S502E_IORANGE; ++i) + hw->regs[i] = 0 + ; + break; + + case SDLA_S503: + case SDLA_S507: + case SDLA_S508: + + if (!card->ioport){ + return -EFAULT; + } + + sdla_isa_write_1(hw, 0x00, 0); /* reset board logic */ + hw->regs[0] = 0; + break; + + case SDLA_S514: + /* halt the adapter */ + sdla_io_write_1(hw, 0x00, S514_CPU_HALT); + CPU_no = hw->cpu_no; + + /* disable the PCI IRQ and disable memory access */ + sdla_pci_read_config_dword(hw, PCI_INT_CONFIG, &int_config); + int_config &= (hw->cpu_no == SDLA_CPU_A) ? ~PCI_DISABLE_IRQ_CPU_A : ~PCI_DISABLE_IRQ_CPU_B; + sdla_pci_write_config_dword(hw, PCI_INT_CONFIG, int_config); + + sdla_read_int_stat(hw, &int_status); + sdla_intack(hw, int_status); + + if (hw->cpu_no == SDLA_CPU_A){ + sdla_pci_write_config_dword(hw, PCI_MAP0_DWORD, PCI_CPU_A_MEM_DISABLE); + }else{ + sdla_pci_write_config_dword(hw, PCI_MAP1_DWORD, PCI_CPU_B_MEM_DISABLE); + } + + /* free up the allocated virtual memory */ + if (hw->status & SDLA_MEM_MAPPED){ + sdla_bus_space_unmap(hw, hw->dpmbase, MAX_SIZEOF_S514_MEMORY); + hw->status &= ~SDLA_MEM_MAPPED; + } + + if (hw->status & SDLA_IO_MAPPED){ + sdla_bus_space_unmap(hw, hw->vector, 16); + hw->status &= ~SDLA_IO_MAPPED; + } + + break; + +/* ALEX*/ + case SDLA_ADSL: + + sdla_memory_unmap(hw); +#if 0 + if (hw->status & SDLA_MEM_RESERVED){ + sdla_release_mem_region(hw, hw->mem_base_addr, GSI_PCI_MEMORY_SIZE); + hw->status &= ~SDLA_MEM_RESERVED; + } + + /* free up the allocated virtual memory */ + if (hw->status & SDLA_MEM_MAPPED){ + sdla_bus_space_unmap(hw, hw->dpmbase, GSI_PCI_MEMORY_SIZE); + hw->status &= ~SDLA_MEM_MAPPED; + } +#endif + break; + + case SDLA_AFT: + + switch(hw->hwcard->adptr_type){ + case A104_ADPTR_4TE1: + case A108_ADPTR_8TE1: + case A200_ADPTR_ANALOG: + if (hw->used > 1){ + break; + } + /* fall throught */ + default: + sdla_memory_unmap(hw); + break; + } + break; + + default: + return -EINVAL; + } + return 0; +} + +/*============================================================================ + * Enable interrupt generation. + */ +static int sdla_inten (sdlahw_t* hw) +{ + sdlahw_card_t* card = NULL; + int i; + u8 tmp; + + WAN_ASSERT(hw == NULL); + WAN_ASSERT(hw->hwcard == NULL); + card = hw->hwcard; + switch (card->type) { + case SDLA_S502E: + /* Note thar interrupt control operations on S502E are allowed + * only if CPU is enabled (bit 0 of status register is set). + */ + sdla_isa_read_1(hw, 0x00, &tmp); + if (tmp & 0x01) { + sdla_isa_write_1(hw, 0x00, 0x02); /* bit1 = 1, bit2 = 0 */ + sdla_isa_write_1(hw, 0x00, 0x06); /* bit1 = 1, bit2 = 1 */ + hw->regs[0] = 0x06; + } + else return -EIO; + break; + + case SDLA_S503: + tmp = hw->regs[0] | 0x04; + sdla_isa_write_1(hw, 0x00, tmp); + hw->regs[0] = tmp; /* update mirror */ + for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ + sdla_isa_read_1(hw, 0x00, &tmp); + if (!(tmp & 0x02)) /* verify */ + return -EIO; + break; + + case SDLA_S508: + tmp = hw->regs[0] | 0x10; + sdla_isa_write_1(hw, 0x00, tmp); + hw->regs[0] = tmp; /* update mirror */ + for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ + sdla_isa_read_1(hw, 0x01, &tmp); + if (!(tmp & 0x10)) /* verify */ + return -EIO; + break; + + case SDLA_S502A: + case SDLA_S507: + break; + + case SDLA_S514: + case SDLA_ADSL: + case SDLA_AFT: + break; + + default: + return -EINVAL; + + } + return 0; +} + +/*============================================================================ + * Disable interrupt generation. + */ +#if 0 +static int sdla_intde (sdlahw_t* hw) +{ + sdlahw_card_t* card = NULL; + int i; + u8 tmp; + + WAN_ASSERT(hw == NULL); + WAN_ASSERT(hw->hwcard == NULL); + card = hw->hwcard; + switch (card->type){ + case SDLA_S502E: + /* Notes: + * 1) interrupt control operations are allowed only if CPU is + * enabled (bit 0 of status register is set). + * 2) disabling interrupts using bit 1 of control register + * causes IRQ line go high, therefore we are going to use + * 0x04 instead: lower it to inhibit interrupts to PC. + */ + sdla_isa_read_1(hw, 0x00, &tmp); + if (tmp & 0x01) { + sdla_isa_write_1(hw, 0x00, hw->regs[0] & ~0x04); + hw->regs[0] &= ~0x04; + } + else return -EIO; + break; + + case SDLA_S503: + tmp = hw->regs[0] & ~0x04; + sdla_isa_write_1(hw, 0x00, tmp); + hw->regs[0] = tmp; /* update mirror */ + for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ + sdla_isa_read_1(hw, 0x00, &tmp); + if (tmp & 0x02) /* verify */ + return -EIO; + break; + + case SDLA_S508: + tmp = hw->regs[0] & ~0x10; + sdla_isa_write_1(hw, 0x00, tmp); + hw->regs[0] = tmp; /* update mirror */ + for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ + sdla_isa_read_1(hw, 0x00, &tmp); + if (tmp & 0x10) /* verify */ + return -EIO; + break; + + case SDLA_S502A: + case SDLA_S507: + break; + + default: + return -EINVAL; + } + return 0; +} +#endif +/*============================================================================ + * Read the hardware interrupt status. + */ +static int sdla_read_int_stat (void* phw, u32* int_status) +{ + sdlahw_card_t* card = NULL; + sdlahw_t* hw = (sdlahw_t*)phw; + + WAN_ASSERT(hw == NULL); + SDLA_MAGIC(hw); + WAN_ASSERT(hw->hwcard == NULL); + card = hw->hwcard; + switch(card->type){ + case SDLA_S514: + case SDLA_ADSL: + case SDLA_AFT: + sdla_pci_read_config_dword(hw, PCI_INT_STATUS, int_status); + } + return 0; +} + +/*============================================================================ + * Acknowledge SDLA hardware interrupt. + */ +static int sdla_intack (void* phw, u32 int_status) +{ + sdlahw_card_t* card = NULL; + sdlahw_t* hw = (sdlahw_t*)phw; + u8 tmp; + + WAN_ASSERT(hw == NULL); + SDLA_MAGIC(hw); + WAN_ASSERT(hw->hwcard == NULL); + card = hw->hwcard; + switch (card->type){ + case SDLA_S502E: + /* To acknoledge hardware interrupt we have to toggle bit 3 of + * control register: \_/ + * Note that interrupt control operations on S502E are allowed + * only if CPU is enabled (bit 1 of status register is set). + */ + sdla_isa_read_1(hw, 0x00, &tmp); + if (tmp & 0x01) { + tmp = hw->regs[0] & ~0x04; + sdla_isa_write_1(hw, 0x00, tmp); + tmp |= 0x04; + sdla_isa_write_1(hw, 0x00, tmp); + hw->regs[0] = tmp; + } + else return -EIO; + break; + + case SDLA_S503: + sdla_isa_read_1(hw, 0x00, &tmp); + if (tmp & 0x04) { + tmp = hw->regs[0] & ~0x08; + sdla_isa_write_1(hw, 0x00, tmp); + tmp |= 0x08; + sdla_isa_write_1(hw, 0x00, tmp); + hw->regs[0] = tmp; + } + break; + + case SDLA_S502A: + case SDLA_S507: + case SDLA_S508: + break; + + case SDLA_S514: + case SDLA_ADSL: + case SDLA_AFT: + sdla_pci_write_config_dword(hw, PCI_INT_STATUS, int_status); + break; + + default: + return -EINVAL; + } + return 0; +} + +/*============================================================================ + * Generate an interrupt to adapter's CPU. + */ +#if 0 +static int sdla_intr (sdlahw_t* hw) +{ + sdlahw_card_t* card = NULL; + u8 tmp; + + WAN_ASSERT(hw == NULL); + WAN_ASSERT(hw->hwcard == NULL); + card = hw->hwcard; + switch (card->type) { + case SDLA_S502A: + sdla_isa_read_1(hw, 0x00, &tmp); + if (!(tmp & 0x40)) { + sdla_isa_write_1(hw, 0x00, 0x10); /* issue NMI to CPU */ + hw->regs[0] = 0x10; + } + else return -EIO; + break; + + case SDLA_S507: + sdla_isa_read_1(hw, 0x00, &tmp); + if ((tmp & 0x06) == 0x06) { + sdla_isa_write_1(hw, 0x03, 0); + } + else return -EIO; + break; + + case SDLA_S508: + sdla_isa_read_1(hw, 0x01, &tmp); + if (tmp & 0x02) { + sdla_isa_write_1(hw, 0x00, 0x08); + } + else return -EIO; + break; + + case SDLA_S502E: + case SDLA_S503: + default: + return -EINVAL; + } + return 0; +} +#endif + +static int sdla_cmd (void* phw, unsigned long offset, wan_mbox_t* mbox) +{ + sdlahw_t* hw = (sdlahw_t*)phw; + int len = sizeof(wan_cmd_t); + int err = 0; + u8 value; + + SDLA_MAGIC(hw); + len += mbox->wan_data_len; + + /* Sangoma ISA card -> sdla_bus_read_1(hw, offset, &value); */ + sdla_peek(hw, offset, (void*)&value, 1); + if (value != 0x00){ + DEBUG_EVENT("%s: opp flag set on entry to sdla_exec!\n", + hw->devname); + return 0; + } + mbox->wan_opp_flag = 0x00; + sdla_poke(hw, offset, (void*)mbox, len); + + err = sdla_exec(hw, offset); + if (!err){ + DEBUG_EVENT("%s: Command 0x%02X failed!\n", + hw->devname, mbox->wan_command); + return WAN_CMD_TIMEOUT; + } + sdla_peek(hw, offset, (void*)mbox, sizeof(wan_cmd_t)); + if (mbox->wan_data_len < (sizeof(wan_mbox_t) - sizeof(wan_cmd_t))){ + sdla_peek(hw, offset+offsetof(wan_mbox_t, wan_data), + mbox->wan_data, mbox->wan_data_len); + }else{ + DEBUG_EVENT("%s: Error: sdla_cmd() data_len=%d\n", + hw->devname,mbox->wan_data_len); + return WAN_CMD_TIMEOUT; + } + + return mbox->wan_return_code; +} + +/*============================================================================ + * Execute Adapter Command. + * o Set exec flag. + * o Busy-wait until flag is reset. + * o Return number of loops made, or 0 if command timed out. + */ +static int sdla_exec (sdlahw_t* hw, unsigned long offset) +{ + volatile unsigned long tstop; + volatile unsigned long nloops; + u8 value; + +#if 0 + /* Sangoma ISA card -> sdla_bus_read_1(hw, offset, &value); */ + sdla_peek(hw, offset, (void*)&value, 1); + if (value != 0x00){ + DEBUG_EVENT("%s: opp flag set on entry to sdla_exec!\n", + hw->devname); + return 0; + } +#endif + /* Sangoma ISA card -> sdla_bus_write_1(hw, offset, 0x01); */ + value = 0x01; + sdla_poke(hw, offset, (void*)&value, 1); + tstop = SYSTEM_TICKS + EXEC_TIMEOUT; + + /* Sangoma ISA card -> sdla_bus_read_1(hw, offset, &value); */ + sdla_peek(hw, offset, (void*)&value, 1); + for (nloops = 1; value == 0x01; ++ nloops){ + WP_DELAY(EXEC_DELAY); + if (SYSTEM_TICKS > tstop || nloops > MAX_NLOOPS){ + DEBUG_EVENT("%s: Timeout %lu (%lu>%lu) Ticks (max=%lu) Loops %lu (max=%u)\n", + __FUNCTION__, + (SYSTEM_TICKS-tstop+EXEC_TIMEOUT), + (unsigned long)SYSTEM_TICKS, + tstop, + (unsigned long)EXEC_TIMEOUT, + nloops, + MAX_NLOOPS); + + /* NC: May 26 2004 + * Reset the opp flag, in order to attempt + * to recover from this critical error. + * Otherwise, every subsequen call will be + * blocked with opp flag set condition */ + value = 0x00; + sdla_poke(hw, offset, (void*)&value, 1); + + return 0; /* time is up! */ + } + + /* Sangoma ISA card -> sdla_bus_read_1(hw, offset, &value); */ + sdla_peek(hw, offset, (void*)&value, 1); + } + + return nloops; +} + + +/*============================================================================ + * Read absolute adapter memory. + * Transfer data from adapter's memory to data buffer. + * + * Note: + * Care should be taken when crossing dual-port memory window boundary. + * This function is not atomic, so caller must disable interrupt if + * interrupt routines are accessing adapter shared memory. + */ +static int sdla_peek (void* phw, unsigned long addr, void* pbuf, unsigned len) +{ + sdlahw_card_t* card = NULL; + sdlahw_t* hw = (sdlahw_t*)phw; + unsigned char* buf = (unsigned char*)pbuf; + int err = 0; + + + WAN_ASSERT(hw == NULL); + SDLA_MAGIC(hw); + WAN_ASSERT(hw->hwcard == NULL); + card = hw->hwcard; + if (addr + len > hw->memory) /* verify arguments */ + return -EINVAL; + + switch(card->type){ + + case SDLA_S508: + { + unsigned long oldvec = (unsigned long)hw->vector; + unsigned long curvec; /* current DPM window vector */ + unsigned winsize = hw->dpmsize; + unsigned curpos, curlen; /* current offset and block size */ + + while (len && !err) { + curpos = addr % winsize; /* current window offset */ + curvec = addr - curpos; /* current window vector */ + curlen = (len > (winsize - curpos)) ? + (winsize - curpos) : len; + /* Relocate window and copy block of data */ + err = sdla_mapmem(hw, curvec); + sdla_peek_by_4 (hw, curpos, buf, curlen); + addr += curlen; + buf += curlen; + len -= curlen; + } + + /* Restore DPM window position */ + sdla_mapmem(hw, oldvec); + break; + } + + case SDLA_S514: + case SDLA_ADSL: + case SDLA_AFT: + sdla_peek_by_4(hw, addr, buf, len); + break; + + default: + DEBUG_EVENT("%s: Invalid card type 0x%X\n", + __FUNCTION__,card->type); + err = -EINVAL; + break; + } + return err; +} + + +/*============================================================================ + * Read data from adapter's memory to a data buffer in 4-byte chunks. + * Note that we ensure that the SDLA memory address is on a 4-byte boundary + * before we begin moving the data in 4-byte chunks. +*/ +static void sdla_peek_by_4 (sdlahw_t* hw, unsigned long offset, void* pbuf, unsigned int len) +{ + unsigned char *buf=(unsigned char*)pbuf; + u32* u32_buf; + + /* byte copy data until we get to a 4-byte boundary */ + while (len && (offset & 0x03)){ + sdla_bus_read_1(hw, offset++, buf); + buf ++; + len --; + } + + /* copy data in 4-byte chunks */ + while (len >= 4){ + u32_buf=(u32*)buf; + sdla_bus_read_4(hw, offset, u32_buf); + buf += 4; + offset += 4; + len -= 4; + } + + /* byte copy any remaining data */ + while (len){ + sdla_bus_read_1(hw, offset++, buf); + buf ++; + len --; + } +} + +/*============================================================================ + * Write Absolute Adapter Memory. + * Transfer data from data buffer to adapter's memory. + * + * Note: + * Care should be taken when crossing dual-port memory window boundary. + * This function is not atomic, so caller must disable interrupt if + * interrupt routines are accessing adapter shared memory. + */ +static int sdla_poke (void* phw, unsigned long addr, void* pbuf, unsigned len) +{ + sdlahw_card_t* card = NULL; + sdlahw_t* hw = (sdlahw_t*)phw; + unsigned char * buf = pbuf; + int err = 0; + + WAN_ASSERT(hw == NULL); + SDLA_MAGIC(hw); + WAN_ASSERT(hw->hwcard == NULL); + card = hw->hwcard; + if (addr + len > hw->memory){ /* verify arguments */ + return -EINVAL; + } + + switch (card->type){ + + case SDLA_S508: + { + unsigned long oldvec = (unsigned long)hw->vector; + unsigned long curvec; /* current DPM window vector */ + unsigned winsize = hw->dpmsize; + unsigned curpos, curlen; /* current offset and block size */ + + while (len && !err) { + curpos = addr % winsize; /* current window offset */ + curvec = addr - curpos; /* current window vector */ + curlen = (len > (winsize - curpos)) ? + (winsize - curpos) : len; + /* Relocate window and copy block of data */ + sdla_mapmem(hw, curvec); + sdla_poke_by_4 (hw, curpos, buf, curlen); + addr += curlen; + buf += curlen; + len -= curlen; + } + + /* Restore DPM window position */ + sdla_mapmem(hw, oldvec); + break; + } + case SDLA_S514: + case SDLA_ADSL: + case SDLA_AFT: + sdla_poke_by_4(hw, addr, buf, len); + break; + + default: + DEBUG_EVENT("%s: Invalid card type 0x%X\n", + __FUNCTION__,card->type); + err = -EINVAL; + break; + } + return err; +} + + +/*============================================================================ + * Write from a data buffer to adapter's memory in 4-byte chunks. + * Note that we ensure that the SDLA memory address is on a 4-byte boundary + * before we begin moving the data in 4-byte chunks. +*/ +static void sdla_poke_by_4 (sdlahw_t* hw, unsigned long offset, void* pbuf, unsigned int len) +{ + u32* u32_buf; + unsigned char *buf=(unsigned char*)pbuf; + + /* byte copy data until we get to a 4-byte boundary */ + while (len && (offset & 0x03)){ + sdla_bus_write_1(hw, offset++, *buf); + buf ++; + len --; + } + + /* copy data in 4-byte chunks */ + while (len >= 4){ + u32_buf=(u32*)buf; + sdla_bus_write_4(hw, offset, *u32_buf); + offset += 4; + buf += 4; + len -= 4; + } + + /* byte copy any remaining data */ + while (len){ + sdla_bus_write_1(hw, offset++, *buf); + buf ++; + len --; + } +} + +static int sdla_poke_byte (void* phw, unsigned long offset, u8 value) +{ + sdlahw_t* hw = (sdlahw_t*)phw; + + SDLA_MAGIC(hw); + /* Sangoma ISA card sdla_bus_write_1(hw, offset, value); */ + sdla_poke(hw, offset, (void*)&value, 1); + return 0; +} + +static int sdla_set_bit (void* phw, unsigned long offset, u8 value) +{ + sdlahw_t* hw = (sdlahw_t*)phw; + u8 tmp; + + SDLA_MAGIC(hw); + /* Sangoma ISA card -> sdla_bus_read_1(hw, offset, &tmp); */ + sdla_peek(hw, offset, (void*)&tmp, 1); + tmp |= value; + /* Sangoma ISA card -> sdla_bus_write_1(hw, offset, tmp); */ + sdla_poke(hw, offset, (void*)&tmp, 1); + return 0; +} + + +static int sdla_clear_bit (void* phw, unsigned long offset, u8 value) +{ + sdlahw_t* hw = (sdlahw_t*)phw; + u8 tmp; + + SDLA_MAGIC(hw); + /* Sangoma ISA card -> sdla_bus_read_1(hw, offset, &tmp); */ + sdla_peek(hw, offset, (void*)&tmp, 1); + tmp &= ~value; + /* Sangoma ISA card -> sdla_bus_write_1(hw, offset, tmp); */ + sdla_poke(hw, offset, (void*)&tmp, 1); + return 0; +} + + +/****** Hardware-Specific Functions *****************************************/ + +/* +***************************************************************************** +***************************************************************************** +*** S A N G O M A H A R D W A R E D E T E C T I O N ***** +***************************************************************************** +***************************************************************************** +*/ +static int sdla_init_pci_slot(sdlahw_t *hw) +{ + sdlahw_card_t* card = NULL; + u32 int_status; + int volatile found=0; + int i=0; + + WAN_ASSERT(hw == NULL); + WAN_ASSERT(hw->hwcard == NULL); + card = hw->hwcard; + /* Check if this is a very first load for a specific + * pci card. If it is, clear the interrput bits, and + * set the flag indicating that this card was initialized. + */ + + for (i=0; (islot_no){ + found=1; + break; + } + if (pci_slot_ar[i] == 0xFF){ + break; + } + } + + if (!found){ + sdla_read_int_stat(hw,&int_status); + sdla_intack(hw,int_status); + if (i == MAX_S514_CARDS){ + DEBUG_EVENT( "%s: Critical Error !!!\n",hw->devname); + DEBUG_EVENT( + "%s: Number of Sangoma PCI cards exceeded maximum limit.\n", + hw->devname); + DEBUG_EVENT( "Please contact Sangoma Technologies\n"); + return 1; + } + pci_slot_ar[i] = card->slot_no; + } + return 0; +} + + +/* + * ============================================================================ + * Check memory region to see if it's available. + * Return: 0 ok. + */ +static unsigned int sdla_check_memregion(sdlahw_t* hw) +{ + unsigned int offset = 0x0; + unsigned int len = hw->dpmsize; + u8 value; + + sdla_bus_read_1(hw, offset, &value); + for(; len && (value == 0xFF); --len){ + /* attempt to write 0 */ + sdla_bus_write_1(hw, offset, 0); + sdla_bus_read_1(hw, offset, &value); + if (value != 0xFF){ /* still has to read 0xFF */ + /* restore orig. value */ + sdla_bus_write_1(hw, offset, 0xFF); + break; /* not good */ + } + ++offset; + sdla_bus_read_1(hw, offset, &value); + } + return len; + +} + +/*============================================================================ + * Autoselect memory region. + * o try all available DMP address options from the top down until success. + */ +static int sdla_autodpm (sdlahw_t* hw) +{ + sdlahw_card_t* card; + int i, err = -EINVAL; + unsigned* opt; + + WAN_ASSERT(hw == NULL); + WAN_ASSERT(hw->hwcard == NULL); + card = hw->hwcard; + switch (card->type){ + case SDLA_S502A: + opt = s502a_dpmbase_options; + break; + + case SDLA_S502E: + case SDLA_S503: + case SDLA_S508: + opt = s508_dpmbase_options; + break; + + case SDLA_S507: + opt = s507_dpmbase_options; + break; + + default: + return -EINVAL; + } + + /* Start testing from 8th position, address + * 0xC8000 from the 508 address table. + * We don't want to test A**** addresses, since + * they are usually used for Video */ + for (i = 8; i <= opt[0] && err; i++) { + hw->dpmbase = (sdla_mem_handle_t)phys_to_virt(opt[i]); + err = sdla_setdpm(hw); + } + return err; +} + +/*============================================================================ + * Initialize SDLA hardware: setup memory window, IRQ, etc. + */ +static int sdla_init (sdlahw_t* hw) +{ + sdlahw_card_t* card = NULL; + int i; + + WAN_ASSERT(hw == NULL); + WAN_ASSERT(hw->hwcard == NULL); + card = hw->hwcard; + for (i = 0; i < SDLA_MAXIORANGE; ++i){ + hw->regs[i] = 0; + } + + switch (card->type) { + case SDLA_S502A: return sdla_init_s502a(hw); + case SDLA_S502E: return sdla_init_s502e(hw); + case SDLA_S503: return sdla_init_s503(hw); + case SDLA_S507: return sdla_init_s507(hw); + case SDLA_S508: return sdla_init_s508(hw); + } + return -EINVAL; +} + +/*============================================================================ + * Map shared memory window into SDLA address space. + */ +static int sdla_mapmem (void* phw, unsigned long addr) +{ + sdlahw_card_t* card = NULL; + sdlahw_t* hw = (sdlahw_t*)phw; + u8 tmp; + + WAN_ASSERT(hw == NULL); + SDLA_MAGIC(hw); + WAN_ASSERT(hw->hwcard == NULL); + card = hw->hwcard; + switch (card->type){ + case SDLA_S502A: + case SDLA_S502E: + if (addr < S502_MAXMEM) { /* verify parameter */ + tmp = addr >> 13; /* convert to register mask */ + sdla_isa_write_1(hw, 0x02, tmp); + hw->regs[2] = tmp; + } + else return -EINVAL; + break; + + case SDLA_S503: + if (addr < S503_MAXMEM) { /* verify parameter */ + tmp = (hw->regs[0] & 0x8F) | ((addr >> 9) & 0x70); + sdla_isa_write_1(hw, 0x00, tmp); + hw->regs[0] = tmp; + } + else return -EINVAL; + break; + + case SDLA_S507: + if (addr < S507_MAXMEM) { + sdla_isa_read_1(hw, 0x00, &tmp); + if (!(tmp & 0x02)) + return -EIO; + tmp = addr >> 13; /* convert to register mask */ + sdla_isa_write_1(hw, 0x02, tmp); + hw->regs[2] = tmp; + } + else return -EINVAL; + break; + + case SDLA_S508: + if (addr < S508_MAXMEM) { + tmp = addr >> 13; /* convert to register mask */ + sdla_isa_write_1(hw, 0x02, tmp); + hw->regs[2] = tmp; + } + else return -EINVAL; + break; + + case SDLA_S514: + case SDLA_ADSL: + case SDLA_AFT: + return 0; + + default: + return -EINVAL; + } + hw->vector = (sdla_mem_handle_t)(addr & 0xFFFFE000L); + return 0; +} + +/*============================================================================ + * Test memory region. + * Return: size of the region that passed the test. + * Note: Region size must be multiple of 2 ! + */ +static unsigned sdla_test_memregion (sdlahw_t* hw, unsigned len) +{ + unsigned len_w = len >> 1; /* region len in words */ + unsigned offset, i; /* offset in char */ + u16 value; + + for (i = 0, offset = 0; i < len_w; ++i, offset += 2){ + sdla_bus_write_2(hw, offset, 0xAA55); + } + + for (i = 0, offset = 0; i < len_w; ++i, offset += 2){ + sdla_bus_read_2(hw, offset, &value); + if (value != 0xAA55){ + len_w = i; + break; + } + } + + for (i = 0, offset = 0; i < len_w; ++i, offset += 2){ + sdla_bus_write_2(hw, offset, 0x55AA); + } + + for (i = 0, offset = 0; i < len_w; ++i, offset += 2){ + sdla_bus_read_2(hw, offset, &value); + if (value != 0x55AA){ + len_w = i; + break; + } + } + + for (i = 0, offset = 0; i < len_w; ++i, offset += 2){ + sdla_bus_write_2(hw, offset, 0x0); + } + + return len_w << 1; +#if 0 + volatile unsigned long w_ptr; + unsigned len_w = len >> 1; /* region len in words */ + unsigned i; + + for (i = 0, w_ptr = hw->dpmbase; i < len_w; ++i, ++w_ptr) + writew (0xAA55, w_ptr); + + for (i = 0, w_ptr = hw->dpmbase; i < len_w; ++i, ++w_ptr) + if (readw (w_ptr) != 0xAA55) { + len_w = i; + break; + } + + for (i = 0, w_ptr = hw->dpmbase; i < len_w; ++i, ++w_ptr) + writew (0x55AA, w_ptr); + + for (i = 0, w_ptr = hw->dpmbase; i < len_w; ++i, ++w_ptr) + if (readw(w_ptr) != 0x55AA) { + len_w = i; + break; + } + + for (i = 0, w_ptr = hw->dpmbase; i < len_w; ++i, ++w_ptr) + writew (0, w_ptr); + + return len_w << 1; +#endif +} + +/*============================================================================ + * Test adapter on-board memory. + * o slide DPM window from the bottom up and test adapter memory segment by + * segment. + * Return adapter memory size. + */ +static unsigned long sdla_memtest (sdlahw_t* hw) +{ + unsigned long memsize; + unsigned winsize; + + for (memsize = 0, winsize = hw->dpmsize; + !sdla_mapmem(hw, memsize) && + (sdla_test_memregion(hw, winsize) == winsize) + ; + memsize += winsize) + ; + hw->memory = memsize; + return memsize; +} + + +/*============================================================================ + * Set up adapter dual-port memory window. + * o shut down adapter + * o make sure that no physical memory exists in this region, i.e entire + * region reads 0xFF and is not writable when adapter is shut down. + * o initialize adapter hardware + * o make sure that region is usable with SDLA card, i.e. we can write to it + * when adapter is configured. + */ +static int sdla_setdpm (sdlahw_t* hw) +{ + int err; + + /* Shut down card and verify memory region */ + sdla_down(hw); + if (sdla_check_memregion(hw)) + return -EINVAL; + + /* Initialize adapter and test on-board memory segment by segment. + * If memory size appears to be less than shared memory window size, + * assume that memory region is unusable. + */ + err = sdla_init(hw); + if (err) return err; + + if (sdla_memtest(hw) < hw->dpmsize) { /* less than window size */ + sdla_down(hw); + return -EIO; + } + + sdla_mapmem(hw, 0L); /* set window vector at bottom */ + return 0; +} + +/*============================================================================ + * Detect S502A adapter. + * Following tests are used to detect S502A adapter: + * 1. All registers other than status (BASE) should read 0xFF + * 2. After writing 00001000b to control register, status register should + * read 01000000b. + * 3. After writing 0 to control register, status register should still + * read 01000000b. + * 4. After writing 00000100b to control register, status register should + * read 01000100b. + * Return 1 if detected o.k. or 0 if failed. + * Note: This test is destructive! Adapter will be left in shutdown + * state after the test. + */ +static int sdla_detect_s502a (sdlahw_t* hw) +{ + sdlahw_card_t* card; + int i, j; + u8 tmp; + + WAN_ASSERT(hw == NULL); + WAN_ASSERT(hw->hwcard == NULL); + card = hw->hwcard; + if (!sdla_get_option_index(s502_port_options, card->ioport)) + return 0; + + for (j = 1; j < SDLA_MAXIORANGE; ++j) { + sdla_isa_read_1(hw, j, &tmp); + if (tmp != 0xFF) + return 0; + for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ + } + + sdla_isa_write_1(hw, 0x00, 0x08); /* halt CPU */ + sdla_isa_write_1(hw, 0x00, 0x08); /* halt CPU */ + sdla_isa_write_1(hw, 0x00, 0x08); /* halt CPU */ + for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ + sdla_isa_read_1(hw, 0x00, &tmp); + if (tmp != 0x40) + return 0; + sdla_isa_write_1(hw, 0x00, 0x00); + for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ + sdla_isa_read_1(hw, 0x00, &tmp); + if (tmp != 0x40) + return 0; + sdla_isa_write_1(hw, 0x00, 0x04); + for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ + sdla_isa_read_1(hw, 0x00, &tmp); + if (tmp != 0x44) + return 0; + + /* Reset adapter */ + sdla_isa_write_1(hw, 0x00, 0x08); /* halt CPU */ + sdla_isa_write_1(hw, 0x00, 0x08); /* halt CPU */ + sdla_isa_write_1(hw, 0x00, 0x08); /* halt CPU */ + sdla_isa_write_1(hw, 0x01, 0xFF); + return 1; +} + +/*============================================================================ + * Initialize S502A adapter. + */ +static int sdla_init_s502a (sdlahw_t* hw) +{ + int tmp, i; + + if (!sdla_detect_s502a(hw)) + return -ENODEV; + + hw->regs[0] = 0x08; + hw->regs[1] = 0xFF; + + /* Verify configuration options */ + i = sdla_get_option_index(s502a_dpmbase_options, virt_to_phys((void*)hw->dpmbase)); + if (i == 0) + return -EINVAL; + + tmp = s502a_hmcr[i - 1]; + switch (hw->dpmsize) { + case 0x2000: + tmp |= 0x01; + break; + + case 0x10000L: + break; + + default: + return -EINVAL; + } + + /* Setup dual-port memory window (this also enables memory access) */ + sdla_isa_write_1(hw, 0x01, tmp); + hw->regs[1] = tmp; + hw->regs[0] = 0x08; + return 0; +} + +/*============================================================================ + * Detect S502E adapter. + * Following tests are used to verify adapter presence: + * 1. All registers other than status (BASE) should read 0xFF. + * 2. After writing 0 to CPU control register (BASE+3), status register + * (BASE) should read 11111000b. + * 3. After writing 00000100b to port BASE (set bit 2), status register + * (BASE) should read 11111100b. + * Return 1 if detected o.k. or 0 if failed. + * Note: This test is destructive! Adapter will be left in shutdown + * state after the test. + */ +static int sdla_detect_s502e (sdlahw_t* hw) +{ + sdlahw_card_t* card; + int i, j; + u8 tmp; + + WAN_ASSERT(hw == NULL); + WAN_ASSERT(hw->hwcard == NULL); + card = hw->hwcard; + if (!sdla_get_option_index(s502_port_options, card->ioport)) + return 0; + for (j = 1; j < SDLA_MAXIORANGE; ++j) { + sdla_isa_read_1(hw, j, &tmp); + if (tmp != 0xFF) + return 0; + for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ + } + + sdla_isa_write_1(hw, 0x03, 0x00); /* CPU control reg. */ + for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ + sdla_isa_read_1(hw, 0x00, &tmp); /* read status */ + if (tmp != 0xF8) /* read status */ + return 0; + sdla_isa_write_1(hw, 0x00, 0x04); /* set bit 2 */ + for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ + sdla_isa_read_1(hw, 0x00, &tmp); /* verify */ + if (tmp != 0xFC) /* verify */ + return 0; + + /* Reset adapter */ + sdla_isa_write_1(hw, 0x00, 0x00); + return 1; +} + +/*============================================================================ + * Initialize S502E adapter. + */ +static int sdla_init_s502e (sdlahw_t* hw) +{ + int i; + u8 tmp; + + if (!sdla_detect_s502e(hw)) + return -ENODEV; + + /* Verify configuration options */ + i = sdla_get_option_index(s508_dpmbase_options, virt_to_phys((void*)hw->dpmbase)); + if (i == 0) + return -EINVAL; + + tmp = s502e_hmcr[i - 1]; + switch (hw->dpmsize) { + case 0x2000: + tmp |= 0x01; + break; + + case 0x10000L: + break; + + default: + return -EINVAL; + } + + /* Setup dual-port memory window */ + sdla_isa_write_1(hw, 0x01, tmp); + hw->regs[1] = tmp; + + /* Enable memory access */ + sdla_isa_write_1(hw, 0x00, 0x02); + hw->regs[0] = 0x02; + for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ + sdla_isa_read_1(hw, 0x00, &tmp); + return (tmp & 0x02) ? 0 : -EIO; +} + +/*============================================================================ + * Detect s503 adapter. + * Following tests are used to verify adapter presence: + * 1. All registers other than status (BASE) should read 0xFF. + * 2. After writing 0 to control register (BASE), status register (BASE) + * should read 11110000b. + * 3. After writing 00000100b (set bit 2) to control register (BASE), + * status register should read 11110010b. + * Return 1 if detected o.k. or 0 if failed. + * Note: This test is destructive! Adapter will be left in shutdown + * state after the test. + */ +static int sdla_detect_s503 (sdlahw_t* hw) +{ + sdlahw_card_t* card; + int i, j; + u8 tmp; + + WAN_ASSERT(hw == NULL); + WAN_ASSERT(hw->hwcard == NULL); + card = hw->hwcard; + if (!sdla_get_option_index(s503_port_options, card->ioport)) + return 0; + for (j = 1; j < SDLA_MAXIORANGE; ++j) { + sdla_isa_read_1(hw, j, &tmp); + if (tmp != 0xFF) + return 0; + for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ + } + + sdla_isa_write_1(hw, 0x00, 0x00); /* reset control reg.*/ + for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ + sdla_isa_read_1(hw, 0x00, &tmp); + if (tmp != 0xF0) /* read status */ + return 0; + sdla_isa_write_1(hw, 0x00, 0x04); /* set bit 2 */ + for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ + sdla_isa_read_1(hw, 0x00, &tmp); + if (tmp != 0xF2) /* verify */ + return 0; + + /* Reset adapter */ + sdla_isa_write_1(hw, 0x00, 0x00); + return 1; +} + +/*============================================================================ + * Initialize S503 adapter. + * --------------------------------------------------------------------------- + */ +static int sdla_init_s503 (sdlahw_t* hw) +{ + int tmp, i; + + if (!sdla_detect_s503(hw)) + return -ENODEV; + + /* Verify configuration options */ + i = sdla_get_option_index(s508_dpmbase_options, virt_to_phys((void*)hw->dpmbase)); + if (i == 0) + return -EINVAL; + + tmp = s502e_hmcr[i - 1]; + switch (hw->dpmsize) { + case 0x2000: + tmp |= 0x01; + break; + + case 0x10000L: + break; + + default: + return -EINVAL; + } + + /* Setup dual-port memory window */ + sdla_isa_write_1(hw, 0x01, tmp); + hw->regs[1] = tmp; + + /* Enable memory access */ + sdla_isa_write_1(hw, 0x00, 0x02); + hw->regs[0] = 0x02; /* update mirror */ + return 0; +} + +/*============================================================================ + * Detect s507 adapter. + * Following tests are used to detect s507 adapter: + * 1. All ports should read the same value. + * 2. After writing 0x00 to control register, status register should read + * ?011000?b. + * 3. After writing 0x01 to control register, status register should read + * ?011001?b. + * Return 1 if detected o.k. or 0 if failed. + * Note: This test is destructive! Adapter will be left in shutdown + * state after the test. + */ +static int sdla_detect_s507 (sdlahw_t* hw) +{ + sdlahw_card_t* card; + int i, j; + u8 tmp, tmp1; + + WAN_ASSERT(hw == NULL); + WAN_ASSERT(hw->hwcard == NULL); + card = hw->hwcard; + if (!sdla_get_option_index(s508_port_options, card->ioport)) + return 0; + sdla_isa_read_1(hw, 0x00, &tmp); + for (j = 1; j < S507_IORANGE; ++j) { + sdla_isa_read_1(hw, j, &tmp1); + if (tmp1 != tmp) + return 0; + for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ + } + + sdla_isa_write_1(hw, 0x00, 0x00); + for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ + sdla_isa_read_1(hw, 0x00, &tmp); + if ((tmp & 0x7E) != 0x30) + return 0; + sdla_isa_write_1(hw, 0x00, 0x01); + for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ + sdla_isa_read_1(hw, 0x00, &tmp); + if ((tmp & 0x7E) != 0x32) + return 0; + + /* Reset adapter */ + sdla_isa_write_1(hw, 0x00, 0x00); + return 1; +} + +/*============================================================================ + * Initialize S507 adapter. + */ +static int sdla_init_s507 (sdlahw_t* hw) +{ + int i; + u8 tmp; + + if (!sdla_detect_s507(hw)) + return -ENODEV; + + /* Verify configuration options */ + i = sdla_get_option_index(s507_dpmbase_options, virt_to_phys((void*)hw->dpmbase)); + if (i == 0) + return -EINVAL; + + tmp = s507_hmcr[i - 1]; + switch (hw->dpmsize) { + case 0x2000: + tmp |= 0x01; + break; + + case 0x10000L: + break; + + default: + return -EINVAL; + } + + /* Enable adapter's logic */ + sdla_isa_write_1(hw, 0x00, 0x01); + hw->regs[0] = 0x01; + for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ + sdla_isa_read_1(hw, 0x00, &tmp); + if (!(tmp & 0x20)) + return -EIO; + + /* Setup dual-port memory window */ + sdla_isa_write_1(hw, 0x01, tmp); + hw->regs[1] = tmp; + + /* Enable memory access */ + tmp = hw->regs[0] | 0x04; + if (hw->irq) { + i = sdla_get_option_index(s508_irq_options, hw->irq); + if (i) tmp |= s507_irqmask[i - 1]; + } + sdla_isa_write_1(hw, 0x00, tmp); + hw->regs[0] = tmp; /* update mirror */ + for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ + sdla_isa_read_1(hw, 0x00, &tmp); + return (tmp & 0x08) ? 0 : -EIO; +} + + +/* + * ============================================================================ + * Initialize S508 adapter. + */ +static int sdla_init_s508 (sdlahw_t* hw) +{ + int i; + u8 tmp; + + if (sdla_detect_s508(hw)){ + return -ENODEV; + } + + /* Verify configuration options */ + i = sdla_get_option_index(s508_dpmbase_options, virt_to_phys((void*)hw->dpmbase)); + if (i == 0){ + return -EINVAL; + } + + /* Setup memory configuration */ + tmp = s508_hmcr[i - 1]; + sdla_isa_write_1(hw, 0x01, tmp); + hw->regs[1] = tmp; + + /* Enable memory access */ + sdla_isa_write_1(hw, 0x00, 0x04); + hw->regs[0] = 0x04; /* update mirror */ + for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ + sdla_isa_read_1(hw, 0x01, &tmp); + return (tmp & 0x04) ? 0 : -EIO; +} + + +/* + * ============================================================================ + * Detect s508 adapter. + * Following tests are used to detect s508 adapter: + * 1. After writing 0x00 to control register, status register should read + * ??000000b. + * 2. After writing 0x10 to control register, status register should read + * ??010000b + * Return 1 if detected o.k. or 0 if failed. + * Note: This test is destructive! Adapter will be left in shutdown + * state after the test. + */ +static int sdla_detect_s508 (sdlahw_t* hw) +{ + sdlahw_card_t* card; + int i; + u8 tmp; + + WAN_ASSERT(hw == NULL); + WAN_ASSERT(hw->hwcard == NULL); + card = hw->hwcard; + /* Sangoma ISa card */ + hw->status |= SDLA_MEM_MAPPED; + hw->status |= SDLA_IO_MAPPED; + if (!sdla_get_option_index(s508_port_options, card->ioport)){ + return -EINVAL; + } + sdla_isa_write_1(hw, 0x0, 0x00); + for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ + sdla_isa_read_1(hw, 0x1, &tmp); + if ((tmp & 0x3F) != 0x00){ + return -EINVAL; + } + sdla_isa_write_1(hw, 0x0, 0x10); + for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ + sdla_isa_read_1(hw, 0x01, &tmp); + if ((tmp & 0x3F) != 0x10){ + return -EINVAL; + } + /* Reset adapter */ + sdla_isa_write_1(hw, 0x0, 0x00); + return 0; +} + +/*============================================================================ + * Detect s514 PCI adapter. + * Return 1 if detected o.k. or 0 if failed. + * Note: This test is destructive! Adapter will be left in shutdown + * state after the test. + */ +static int sdla_detect_s514 (sdlahw_t* hw) +{ + sdlahw_card_t* card; + u32 ut_u32; + u8 ut_u8; + + WAN_ASSERT(hw == NULL); + WAN_ASSERT(hw->hwcard == NULL); + card = hw->hwcard; + + sdla_pci_read_config_dword(hw, + (hw->cpu_no == SDLA_CPU_A) ? PCI_MEM_BASE0_DWORD : + PCI_MEM_BASE1_DWORD, (u32*)&hw->mem_base_addr); + if (!hw->mem_base_addr){ + if(hw->cpu_no == SDLA_CPU_B){ + DEBUG_EVENT( "%s: CPU #B not present on the card\n", + hw->devname); + }else{ + DEBUG_EVENT( "%s: No PCI memory allocated to card\n", + hw->devname); + } + return -EINVAL; + } + DEBUG_EVENT( "%s: S514 PCI memory at 0x%lX\n", + hw->devname, (unsigned long)hw->mem_base_addr); + + /* enable the PCI memory */ + sdla_pci_read_config_dword(hw, + (hw->cpu_no == SDLA_CPU_A) ? PCI_MAP0_DWORD : PCI_MAP1_DWORD, &ut_u32); + sdla_pci_write_config_dword(hw, + (hw->cpu_no == SDLA_CPU_A) ? PCI_MAP0_DWORD : PCI_MAP1_DWORD, + (ut_u32 | PCI_MEMORY_ENABLE)); + + /* check the IRQ allocated and enable IRQ usage */ + /* the INTPIN must not be 0 - if it is, then the S514 adapter is not */ + /* configured for IRQ usage */ + + sdla_pci_read_config_byte(hw, PCI_INT_PIN_BYTE, &ut_u8); + if(!ut_u8) { + DEBUG_EVENT("%s: invalid setting for INTPIN on S514 card\n", + hw->devname); + DEBUG_EVENT("Please contact your Sangoma representative\n"); + return 0; + } + + sdla_pci_read_config_byte(hw, PCI_INT_LINE_BYTE, (u8*)&hw->irq); + if(hw->irq == PCI_IRQ_NOT_ALLOCATED) { + DEBUG_EVENT("%s: IRQ not allocated to S514 adapter\n", + hw->devname); + return -EINVAL; + } +#if defined(__LINUX__) + hw->irq = card->pci_dev->irq; +#endif + + /* BUG FIX : Mar 6 2000 + * On a initial loading of the card, we must check + * and clear PCI interrupt bits, due to a reset + * problem on some other boards. i.e. An interrupt + * might be pending, even after system bootup, + * in which case, when starting wanrouter the machine + * would crash. + */ + if (sdla_init_pci_slot(hw)){ + return 0; + } + + sdla_pci_read_config_dword(hw, PCI_INT_CONFIG, &ut_u32); + ut_u32 |= (hw->cpu_no == SDLA_CPU_A) ? + PCI_ENABLE_IRQ_CPU_A : PCI_ENABLE_IRQ_CPU_B; + sdla_pci_write_config_dword(hw, PCI_INT_CONFIG, ut_u32); + + if (sdla_pci_enable_device(hw)){ + DEBUG_EVENT( "%s: Error: S514 PCI enable failed\n", + hw->devname); + return -EINVAL; + } + + sdla_pci_set_master(hw); + + /* Linux uses new irq routing mechanism, where + * the value of the irq is not valid until pci_enable_device() + * is executied */ +#if defined(__LINUX__) + hw->irq = card->pci_dev->irq; +#endif + + DEBUG_EVENT( "%s: IRQ %d allocated to the S514 card\n", + hw->devname, hw->irq); + + hw->status |= SDLA_PCI_ENABLE; + + /* map the physical PCI memory to virtual memory */ + sdla_bus_space_map(hw, 0x0, MAX_SIZEOF_S514_MEMORY, &hw->dpmbase); + if (!hw->dpmbase){ + DEBUG_EVENT("%s: PCI virtual memory allocation failed\n", + hw->devname); + return -EINVAL; + } + + /* map the physical control register memory to virtual memory */ + sdla_bus_space_map(hw, S514_CTRL_REG_BYTE, 16, &hw->vector); + if (!hw->vector){ + sdla_bus_space_unmap(hw, hw->dpmbase, MAX_SIZEOF_S514_MEMORY); + DEBUG_EVENT("%s: PCI virtual memory allocation failed\n", + hw->devname); + hw->dpmbase=0; + return -EINVAL; + } + + hw->status |= SDLA_MEM_MAPPED; + + +#if defined(__NetBSD__) || defined(__OpenBSD__) + hw->ioh = hw->vector; +#endif + hw->status |= SDLA_IO_MAPPED; + + /* halt the adapter */ + sdla_io_write_1(hw, 0x0, S514_CPU_HALT); + + return 0; +} + + + +/*============================================================================ + * Find the S514 PCI adapter in the PCI bus. + * Return the number of S514 adapters found (0 if no adapter found). + */ +static int sdla_detect_pulsar(sdlahw_t* hw) +{ + sdlahw_card_t *hwcard; + int err; + + WAN_ASSERT(hw == NULL); + WAN_ASSERT(hw->hwcard == NULL); + hwcard = hw->hwcard; + + if ((err = sdla_memory_map(hw, SDLA_CPU_A))){ + return err; + } +#if 0 + sdla_pci_read_config_dword(hw, PCI_IO_BASE_DWORD, (u32*)&hw->mem_base_addr); + if(!hw->mem_base_addr) { + DEBUG_EVENT( "%s: No PCI memory allocated to card!\n", + hw->devname); + return -EINVAL; + } +#endif + DEBUG_EVENT( "%s: ADSL PCI memory at 0x%lX\n", + hw->devname, (unsigned long)hw->mem_base_addr); + + sdla_pci_read_config_byte(hw, PCI_INT_LINE_BYTE, (u8*)&hw->irq); + if(hw->irq == PCI_IRQ_NOT_ALLOCATED) { + DEBUG_EVENT( "%s: IRQ not allocated to S514 adapter\n", + hw->devname); + return -EINVAL; + } + +#if defined(__LINUX__) + hw->irq = hwcard->pci_dev->irq; +#endif + DEBUG_EVENT( "%s: IRQ %d allocated to the ADSL card\n", + hw->devname, hw->irq); + +#if 0 + if (sdla_pci_enable_device(hw)){ + DEBUG_EVENT( "%s: Error: S518 ADSL PCI enable failed\n", + hw->devname); + return -EINVAL; + } + hw->status |= SDLA_PCI_ENABLE; + + sdla_pci_set_master(hw); + + hw->status |= SDLA_MEM_MAPPED; + + if (sdla_request_mem_region(hw, hw->mem_base_addr, + GSI_PCI_MEMORY_SIZE, "WANPIPE ADSL", &presource)){ + + DEBUG_EVENT("%s: Error: Unable to reserve S518 ADSL pci bar0 memory\n", + hw->devname); + return -EINVAL; + } + + hw->status |= SDLA_MEM_RESERVED; + + hw->memory=GSI_PCI_MEMORY_SIZE; + + /* map the physical PCI memory to virtual memory */ + sdla_bus_space_map(hw, 0x0, GSI_PCI_MEMORY_SIZE, &hw->dpmbase); + if(!hw->dpmbase) { + DEBUG_EVENT( "%s: Error: S518 ADSL PCI virtual memory ioremap failed\n", + hw->devname); + return -EINVAL; + } +#endif + return 0; + +} + +/*============================================================================ + * Map memory for AFT HDLC PCI adapter in the PCI bus. + */ +static int sdla_memory_map(sdlahw_t* hw, int cpu_no) +{ + sdlahw_card_t *hwcard; + void *presource; + int err=-EINVAL; + unsigned char reserve_name[50]; + + + + WAN_ASSERT(hw == NULL); + WAN_ASSERT(hw->hwcard == NULL); + hwcard = hw->hwcard; + presource =NULL; + + switch (hwcard->type){ + + case SDLA_S508: + err=0; + break; + + case SDLA_ADSL: + hw->memory=GSI_PCI_MEMORY_SIZE; + cpu_no=SDLA_CPU_A; + sprintf(reserve_name,"WANPIPE ADSL"); + break; + + case SDLA_AFT: + sprintf(reserve_name,"WANPIPE AFT"); + switch(hw->hwcard->adptr_type){ + case A104_ADPTR_4TE1: + case A200_ADPTR_ANALOG: + hw->memory = AFT4_PCI_MEM_SIZE; + break; + case A108_ADPTR_8TE1: + hw->memory = AFT8_PCI_MEM_SIZE; + break; + default: + hw->memory = AFT_PCI_MEM_SIZE; + break; + } + break; + + default: + DEBUG_EVENT("%s:%d Error: Invalid hw adapter type (0x%X)\n", + __FUNCTION__,__LINE__,hwcard->type); + return -EINVAL; + } + + DEBUG_TEST("NCDEBUG: MEMORY MAPPING AFT\n"); + + if (sdla_pci_enable_device(hw)){ + DEBUG_EVENT( "%s: Error: AFT PCI enable failed\n", + hw->devname); + return -EINVAL; + } + hw->status |= SDLA_PCI_ENABLE; + + if (!(hw->status & SDLA_MEM_RESERVED)){ +#if defined(__LINUX__) + err = pci_request_region(hw->hwcard->pci_dev, (cpu_no == SDLA_CPU_A)?0:1 ,reserve_name); +#else + err = sdla_request_mem_region( + hw, + hw->mem_base_addr, + hw->memory, + reserve_name, + &presource); +#endif + if (err){ + + DEBUG_EVENT("%s: Error: Unable to reserve AFT pci bar%i memory\n", + hw->devname,(cpu_no == SDLA_CPU_A)?0:1); + + err = -EINVAL; + goto aft_pci_error; + } + hw->status |= SDLA_MEM_RESERVED; + } + +#if defined(__LINUX__) && defined(DMA_32BIT_MASK) + if((err = pci_set_dma_mask(hw->hwcard->pci_dev, DMA_32BIT_MASK))) { + DEBUG_EVENT("%s: Error: No usable DMA configuration, aborting.\n", + hw->devname); + err = -EINVAL; + goto aft_pci_error; + } +#endif + sdla_get_pci_base_resource_addr(hw, + (cpu_no == SDLA_CPU_A) ? + PCI_IO_BASE_DWORD : + PCI_MEM_BASE0_DWORD, + &hw->mem_base_addr); + + if (!hw->mem_base_addr){ + if(cpu_no == SDLA_CPU_B){ + DEBUG_EVENT( "%s: Error: CPU #B not present on adapter\n", + hw->devname); + }else{ + DEBUG_EVENT( "%s: Error: Failed to allocate PCI memory on AFT/ADSL card\n", + hw->devname); + } + err = -EINVAL; + goto aft_pci_error; + } + + if (!(hw->status & SDLA_MEM_MAPPED)){ + /* map the physical PCI memory to virtual memory */ + sdla_bus_space_map(hw, + 0x0, + hw->memory, + &hw->dpmbase); + if (!hw->dpmbase){ + DEBUG_EVENT( "%s: Error: AFT PCI virtual memory ioremap failed\n", + hw->devname); + err = -EINVAL; + goto aft_pci_error; + } + hw->status |= SDLA_MEM_MAPPED; + } + + sdla_pci_set_master(hw); + err=0; + + return err; + + +aft_pci_error: + sdla_memory_unmap(hw); + return err; +} + +/*============================================================================ + * Map memory for AFT HDLC PCI adapter in the PCI bus. + */ +static int sdla_memory_unmap(sdlahw_t* hw) +{ + sdlahw_card_t *hwcard; + + WAN_ASSERT(hw == NULL); + WAN_ASSERT(hw->hwcard == NULL); + hwcard = hw->hwcard; + switch (hwcard->type){ + case SDLA_S508: + break; + + case SDLA_ADSL: + case SDLA_AFT: + + DEBUG_TEST("NCDEBUG: MEMORY UNMAPPING AFT\n"); + + /* free up the allocated virtual memory */ + if (hw->status & SDLA_MEM_MAPPED){ + sdla_bus_space_unmap( + hw, + hw->dpmbase, + hw->memory); + hw->status &= ~SDLA_MEM_MAPPED; + } + + if (hw->status & SDLA_MEM_RESERVED){ +#if defined(__LINUX__) + pci_release_region(hw->hwcard->pci_dev,(hw->cpu_no == SDLA_CPU_A)?0:1); +#else + sdla_release_mem_region( + hw, + hw->mem_base_addr, + hw->memory); +#endif + hw->status &= ~SDLA_MEM_RESERVED; + } + + if (hw->status & SDLA_PCI_ENABLE){ + /* FIXME: No allowed to do this because bar1 might + * still be used. Need a pci dev counter */ + /* sdla_pci_disable_device(hw); */ + hw->status &= ~SDLA_PCI_ENABLE; + } + + break; + } + return 0; +} +/*============================================================================ + * Find the AFT HDLC PCI adapter in the PCI bus. + * Return the number of AFT adapters found (0 if no adapter found). + */ +static int sdla_detect_aft(sdlahw_t* hw) +{ + sdlahw_card_t *hwcard; + int err; + + WAN_ASSERT(hw == NULL); + WAN_ASSERT(hw->hwcard == NULL); + hwcard = hw->hwcard; + + if ((err = sdla_memory_map(hw, hw->cpu_no))){ + return err; + } + + DEBUG_EVENT( "%s: AFT PCI memory at 0x%lX\n", + hw->devname, (unsigned long)hw->mem_base_addr); + +#if defined(__LINUX__) + hw->irq = hwcard->pci_dev->irq; +#else + sdla_pci_read_config_byte(hw, PCI_INT_LINE_BYTE, (u8*)&hw->irq); +#endif + if(hw->irq == PCI_IRQ_NOT_ALLOCATED) { + sdla_memory_unmap(hw); + DEBUG_EVENT( "%s: IRQ not allocated to AFT adapter\n", + hw->devname); + return -EINVAL; + } + + DEBUG_EVENT( "%s: IRQ %d allocated to the AFT PCI card\n", + hw->devname, hw->irq); + + /* Set PCI Latency of 0xFF*/ + sdla_pci_write_config_dword(hw, XILINX_PCI_LATENCY_REG, XILINX_PCI_LATENCY); + + return 0; +} + + + +/*============================================================================ + * Find the S514 PCI adapter in the PCI bus. + * If conf argument is NULL, return fisrt not used adapter (CONFIG_PRODUCT_WANPIPE_GENERIC) + * Return the number of S514 adapters found (0 if no adapter found). + */ +static sdlahw_t* sdla_find_adapter(wandev_conf_t* conf, char* devname) +{ + sdlahw_t* hw = NULL; + int cpu_no = SDLA_CPU_A; + + if (conf && conf->S514_CPU_no[0] == 'B'){ + cpu_no = SDLA_CPU_B; + }else if (conf && conf->S514_CPU_no[0] == 'A'){ + cpu_no = SDLA_CPU_A; + } + + WAN_LIST_FOREACH(hw, &sdlahw_head, next){ + + if (conf == NULL){ + if (hw->used < hw->max_ports){ + return hw; + } + continue; + } + switch(conf->card_type){ + case WANOPT_S50X: + if (hw->hwcard->ioport == conf->ioport){ + goto adapter_found; + } + break; + + case WANOPT_S51X: + case WANOPT_ADSL: + case WANOPT_AFT: + case WANOPT_AFT300: + case WANOPT_AFT_ANALOG: + if (conf->auto_pci_cfg){ + if (hw->cpu_no == cpu_no && + hw->hwcard->cfg_type == conf->card_type){ + goto adapter_found; + } + }else{ + + if ((hw->hwcard->slot_no == conf->PCI_slot_no) && + (hw->hwcard->bus_no == conf->pci_bus_no) && + (hw->cpu_no == cpu_no) && + (hw->hwcard->cfg_type == conf->card_type)){ + goto adapter_found; + } + } + break; + + case WANOPT_AFT104: + case WANOPT_AFT108: + if (conf->auto_pci_cfg){ + + switch (hw->hwcard->cfg_type){ + case WANOPT_AFT104: + case WANOPT_AFT108: + goto adapter_found; + break; + default: + break; + } + }else{ + + if ((hw->hwcard->slot_no == conf->PCI_slot_no) && + (hw->hwcard->bus_no == conf->pci_bus_no)){ + + switch (hw->hwcard->cfg_type){ + case WANOPT_AFT104: + case WANOPT_AFT108: + goto adapter_found; + break; + default: + break; + } + } + } + break; + + + default: + DEBUG_EVENT("%s: Unknown card type (%x) requested by user!\n", + devname, conf->card_type); + return NULL; + } + } + +adapter_found: + if (hw){ + switch(hw->hwcard->adptr_type){ + case S5144_ADPTR_1_CPU_T1E1: + case S5147_ADPTR_2_CPU_T1E1: + case A101_ADPTR_1TE1: + case A101_ADPTR_2TE1: + case A200_ADPTR_ANALOG: + conf->comm_port = 0; + conf->fe_cfg.line_no = 0; + break; + case A104_ADPTR_4TE1: + if (conf->fe_cfg.line_no < 1 || conf->fe_cfg.line_no > 4){ + DEBUG_EVENT("%s: Error, Invalid port selected %d (Min=1 Max=4)\n", + devname, conf->fe_cfg.line_no); + return NULL; + } + conf->fe_cfg.line_no--; + conf->comm_port = conf->fe_cfg.line_no; + break; + case A108_ADPTR_8TE1: + if (conf->fe_cfg.line_no < 1 || conf->fe_cfg.line_no > 8){ + DEBUG_EVENT("%s: Error, Invalid port selected %d (Min=1 Max=8)\n", + devname, conf->fe_cfg.line_no); + return NULL; + } + conf->fe_cfg.line_no--; + conf->comm_port = conf->fe_cfg.line_no; + break; + } + if (hw->hwport[conf->comm_port].used == 0){ + return hw; + } + switch(conf->card_type){ + case WANOPT_S50X: + DEBUG_EVENT( + "%s: Error, Sangoma ISA resource busy: (ioport #%x, %s)\n", + devname, conf->ioport, COMPORT_DECODE(conf->comm_port)); + break; + + case WANOPT_S51X: + case WANOPT_ADSL: + case WANOPT_AFT: + case WANOPT_AFT104: + case WANOPT_AFT108: + case WANOPT_AFT300: + case WANOPT_AFT_ANALOG: + switch(hw->hwcard->adptr_type){ + case A104_ADPTR_4TE1: + case A108_ADPTR_8TE1: + DEBUG_EVENT( + "%s: Error, %s resources busy: (bus #%d, slot #%d, cpu %c, line %d)\n", + devname, + SDLA_DECODE_CARDTYPE(conf->card_type), + conf->pci_bus_no, + conf->PCI_slot_no, + conf->S514_CPU_no[0], + conf->fe_cfg.line_no); + break; + + default: + DEBUG_EVENT( + "%s: Error, %s resources busy: (bus #%d, slot #%d, cpu %c)\n", + devname, + SDLA_DECODE_CARDTYPE(conf->card_type), + conf->pci_bus_no, + conf->PCI_slot_no, + conf->S514_CPU_no[0]); + break; + } + break; + default: + DEBUG_EVENT( + "%s: Error, %s resources busy: (bus #%d, slot #%d, cpu %c)\n", + devname, + SDLA_DECODE_CARDTYPE(conf->card_type), + conf->pci_bus_no, + conf->PCI_slot_no, + conf->S514_CPU_no[0]); + break; + } + return NULL; + } + + if (conf){ + switch(conf->card_type){ + case WANOPT_S50X: + DEBUG_EVENT( + "%s: Error, Sangoma ISA card not found on ioport #%x, %s\n", + devname, conf->ioport, COMPORT_DECODE(conf->comm_port)); + break; + case WANOPT_S51X: + DEBUG_EVENT( + "%s: Error, %s card not found on bus #%d, slot #%d, cpu %c, %s\n", + devname, + SDLA_DECODE_CARDTYPE(conf->card_type), + conf->pci_bus_no, + conf->PCI_slot_no, + conf->S514_CPU_no[0], + COMPORT_DECODE(conf->comm_port)); + break; + case WANOPT_ADSL: + DEBUG_EVENT( + "%s: Error, %s card not found on bus #%d, slot #%d\n", + devname, + SDLA_DECODE_CARDTYPE(conf->card_type), + conf->pci_bus_no, + conf->PCI_slot_no); + break; + case WANOPT_AFT: + case WANOPT_AFT104: + case WANOPT_AFT300: + case WANOPT_AFT108: + case WANOPT_AFT_ANALOG: + DEBUG_EVENT( + "%s: Error, %s card not found on bus #%d, slot #%d, cpu %c, line %d\n", + devname, + SDLA_DECODE_CARDTYPE(conf->card_type), + conf->pci_bus_no, + conf->PCI_slot_no, + conf->S514_CPU_no[0], + conf->fe_cfg.line_no); + break; + default: + DEBUG_EVENT( + "%s: Error, %s card not found!\n", + devname, + SDLA_DECODE_CARDTYPE(conf->card_type)); + break; + } + }else{ + DEBUG_EVENT("%s: Error, Failed to find new Sangoma card!\n", + devname); + } + + return NULL; +} + +/* + * ============================================================================ + * Detect adapter type. + * o if adapter type is specified then call detection routine for that adapter + * type. Otherwise call detection routines for every adapter types until + * adapter is detected. + * + * Notes: + * 1) Detection tests are destructive! Adapter will be left in shutdown state + * after the test. + */ +static int sdla_detect (sdlahw_t* hw) +{ + sdlahw_card_t *hwcard = NULL; + int err = 0; + + WAN_ASSERT(hw == NULL); + WAN_ASSERT(hw->hwcard == NULL); + hwcard = hw->hwcard; + switch (hwcard->type){ + case SDLA_S508: + err = sdla_detect_s508(hw); + break; + + case SDLA_S514: + err = sdla_detect_s514(hw); + break; + + case SDLA_ADSL: + err = sdla_detect_pulsar(hw); + break; + + case SDLA_AFT: + err = sdla_detect_aft(hw); + break; + } + if (err){ + sdla_down(hw); + } + return err; +} + + + + +/* +***************************************************************************** +***************************************************************************** +*** H A R D W A R E C O N F I G U R A T I O N ***** +***************************************************************************** +***************************************************************************** +*/ + +static int sdla_is_te1(void* phw) +{ + sdlahw_card_t* hwcard = NULL; + sdlahw_t* hw = (sdlahw_t*)phw; + + WAN_ASSERT(hw == NULL); + SDLA_MAGIC(hw); + WAN_ASSERT(hw->hwcard == NULL); + hwcard = hw->hwcard; + switch(hwcard->adptr_type){ + case S5144_ADPTR_1_CPU_T1E1: + case S5147_ADPTR_2_CPU_T1E1: + case S5148_ADPTR_1_CPU_T1E1: + case A101_ADPTR_1TE1: + case A101_ADPTR_2TE1: + case A104_ADPTR_4TE1: + case A108_ADPTR_8TE1: + return 0; + } + return -EINVAL; + + +} +static int sdla_is_56k(void* phw) +{ + sdlahw_card_t* hwcard = NULL; + sdlahw_t* hw = (sdlahw_t*)phw; + + WAN_ASSERT(hw == NULL); + SDLA_MAGIC(hw); + WAN_ASSERT(hw->hwcard == NULL); + hwcard = hw->hwcard; + if (hwcard->adptr_type == S5145_ADPTR_1_CPU_56K){ + return 0; + } + return -EINVAL; +} + +/*FIXME: Take it out of here and put it in sdladrv +** Args: HW structure not card +*/ +static int sdla_check_mismatch(void* phw, unsigned char media) +{ + sdlahw_card_t* hwcard = NULL; + sdlahw_t* hw = (sdlahw_t*)phw; + + WAN_ASSERT(hw == NULL); + SDLA_MAGIC(hw); + WAN_ASSERT(hw->hwcard == NULL); + hwcard = hw->hwcard; + if (media == WAN_MEDIA_T1 || + media == WAN_MEDIA_E1){ + if (hwcard->adptr_type != S5144_ADPTR_1_CPU_T1E1 && + hwcard->adptr_type != S5147_ADPTR_2_CPU_T1E1 && + hwcard->adptr_type != S5148_ADPTR_1_CPU_T1E1){ + DEBUG_EVENT("%s: Error: Card type mismatch: User=T1/E1 Actual=%s\n", + hw->devname, + hwcard->adptr_name); + return -EIO; + } + hwcard->adptr_type = S5144_ADPTR_1_CPU_T1E1; + + }else if (media == WAN_MEDIA_56K){ + if (hwcard->adptr_type != S5145_ADPTR_1_CPU_56K){ + DEBUG_EVENT("%s: Error: Card type mismatch: User=56K Actual=%s\n", + hw->devname, + hwcard->adptr_name); + return -EIO; + } + }else{ + if (hwcard->adptr_type == S5145_ADPTR_1_CPU_56K || + hwcard->adptr_type == S5144_ADPTR_1_CPU_T1E1 || + hwcard->adptr_type == S5147_ADPTR_2_CPU_T1E1 || + hwcard->adptr_type == S5148_ADPTR_1_CPU_T1E1){ + DEBUG_EVENT("%s: Error: Card type mismatch: User=S514(1/2/3) Actual=%s\n", + hw->devname, + hwcard->adptr_name); + return -EIO; + } + } + return 0; +} + +static int sdla_is_same_hwcard(void* phw1, void *phw2) +{ + sdlahw_t* hw1 = (sdlahw_t*)phw1; + sdlahw_t* hw2 = (sdlahw_t*)phw2; + + if (hw1->hwcard == hw2->hwcard){ + return 1; + } + return 0; +} + +/* + ***************************************************************************** + * sdla_set_intrhand() - Change interrupt handler for ISA devices. + * o For S508, use local structure for store pointer to real interrupt handler. + * o For S514, register new interrupt handler for each CPU. + */ +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) +static int +sdla_set_intrhand(void* phw, void (*isr_func)(void*), void* arg, int line_no) +{ + sdlahw_t* hw = (sdlahw_t*)phw; + sdladev_t* adapter = NULL; +#if defined(__FreeBSD__) && (__FreeBSD_version >= 450000) + int error = 0; +#endif + + SDLA_MAGIC(hw); + adapter = (sdladev_t*)hw->dev; + WAN_ASSERT(adapter == NULL); + WAN_ASSERT(adapter->sc == NULL); + +#if defined(__FreeBSD__) && (__FreeBSD_version >= 450000) + + error = bus_setup_intr( + adapter->dev, + adapter->sc->irq_res, + INTR_TYPE_NET, + isr_func, + arg, + &hw->irqh[line_no]); + if (error){ + DEBUG_EVENT("%s: Failed set interrupt handler for CPU A!\n", + device_get_name(adapter->dev)); + return error; + } + +#else + if (adapter->intr_arg[line_no].ready){ + adapter->intr_arg[line_no].isr = isr_func; + adapter->intr_arg[line_no].arg = arg; + }else{ + return -EINVAL; + } +#endif + return 0; +} +#endif + +/* + ***************************************************************************** + * restore_intrhand() - Restore interrupt handler for ISA/PCI devices. + * o For S508, set to NULL pointer to interrupt handler in local structure. + * o For S514, call pci_unmap_int(). + */ +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) +static int sdla_restore_intrhand(void* phw, int line_no) +{ + sdlahw_t* hw = (sdlahw_t*)phw; + sdladev_t* adapter = NULL; + + SDLA_MAGIC(hw); + adapter = (sdladev_t*)hw->dev; + WAN_ASSERT(adapter == NULL); + WAN_ASSERT(adapter->sc == NULL); + +#if defined(__FreeBSD__) && (__FreeBSD_version >= 450000) + + if (bus_teardown_intr(adapter->dev, adapter->sc->irq_res, hw->irqh[line_no])){ + DEBUG_EVENT("%s: Failed unregister interrupt handler!\n", + device_get_name(adapter->dev)); + return -EINVAL; + + } +#else + /* Restore local vector */ + adapter->intr_arg[line_no].isr = NULL; + adapter->intr_arg[line_no].arg = NULL; +#endif + return 0; +} +#endif + + + +static int sdla_getcfg(void* phw, int type, void* value) +{ + sdlahw_t* hw = (sdlahw_t*)phw; + sdlahw_card_t* hwcard; + + WAN_ASSERT(hw == NULL); + SDLA_MAGIC(hw); + WAN_ASSERT(hw->hwcard == NULL); + hwcard = hw->hwcard; + switch(type){ + case SDLA_HWTYPE: + *(u16*)value = hwcard->hw_type; + break; + case SDLA_CARDTYPE: + *(u16*)value = hwcard->type; + break; + case SDLA_MEMBASE: + *(sdla_mem_handle_t*)value = hw->dpmbase; + break; + case SDLA_MEMEND: + *(u32*)value = ((unsigned long)hw->dpmbase + hw->dpmsize - 1); + break; + case SDLA_MEMSIZE: + *(u16*)value = hw->dpmsize; + break; + case SDLA_MEMORY: + *(u32*)value = hw->memory; + break; + case SDLA_IRQ: + *(u16*)value = hw->irq; + break; + case SDLA_IOPORT: + *(u16*)value = hwcard->ioport; + break; + case SDLA_IORANGE: + *(u16*)value = hw->io_range; + break; + case SDLA_ADAPTERTYPE: + *(u16*)value = hwcard->adptr_type; + break; + case SDLA_CPU: + *(u16*)value = hw->cpu_no; + break; + case SDLA_SLOT: + *(u16*)value = hwcard->slot_no; + break; + case SDLA_BUS: + *(u16*)value = hwcard->bus_no; + break; + case SDLA_DMATAG: +#if defined(__NetBSD__) || defined(__OpenBSD__) + if (hwcard->pci_dev){ + *(bus_dma_tag_t*)value = hwcard->pci_dev->pa_dmat; + } +#endif + break; + case SDLA_PCIEXTRAVER: + *(u8*)value = hwcard->pci_extra_ver; + break; + case SDLA_BASEADDR: + *(u32*)value = hw->mem_base_addr; + break; + case SDLA_COREREV: + *(u8*)value = hwcard->core_rev; + break; + case SDLA_USEDCNT: + *(u32*)value = hw->used; + break; + case SDLA_ADAPTERSUBTYPE: + *(u8*)value = hwcard->adptr_subtype; + break; + case SDLA_HWEC_NO: + *(u16*)value = hwcard->hwec_chan_no; + break; + } + return 0; +} + + +static int sdla_get_hwcard(void* phw, void** phwcard) +{ + sdlahw_t* hw = (sdlahw_t*)phw; + + WAN_ASSERT(hw == NULL); + SDLA_MAGIC(hw); + + *phwcard = hw->hwcard; + return 0; +} + + +static int sdla_get_hwprobe(void* phw, int port, void** hwinfo) +{ + sdlahw_t* hw = (sdlahw_t*)phw; + + WAN_ASSERT(hw == NULL); + SDLA_MAGIC(hw); + + if (hw->hwport[port].hwprobe){ + *hwinfo = hw->hwport[port].hwprobe->hw_info; + } + return 0; +} + +/* +***************************************************************************** +***************************************************************************** +*** M I S C E L L A N E O U S ***** +***************************************************************************** +***************************************************************************** +*/ + +/*============================================================================ + * Get option's index into the options list. + * Return option's index (1 .. N) or zero if option is invalid. + */ +static int sdla_get_option_index (unsigned* optlist, unsigned optval) +{ + int i; + + for (i = 1; i <= optlist[0]; ++i) + if ( optlist[i] == optval) + return i; + return 0; +} + +/*============================================================================ + * Calculate 16-bit CRC using CCITT polynomial. + */ +static unsigned short sdla_checksum (unsigned char* buf, unsigned len) +{ + unsigned short crc = 0; + unsigned mask, flag; + + for (; len; --len, ++buf) { + for (mask = 0x80; mask; mask >>= 1) { + flag = (crc & 0x8000); + crc <<= 1; + crc |= ((*buf & mask) ? 1 : 0); + if (flag) crc ^= 0x1021; + } + } + return crc; +} + + + + +static int sdla_io_read_1(void* phw, unsigned int offset, u8* value) +{ + sdlahw_t* hw = (sdlahw_t*)phw; + + WAN_ASSERT2(hw == NULL, 0); + if (!(hw->status & SDLA_IO_MAPPED)) return 0; +#if defined(__FreeBSD__) + *value = readb ((u8*)hw->vector + offset); +#elif defined(__NetBSD__) || defined(__OpenBSD__) + *value = bus_space_read_1(hw->hwcard->memt, hw->vector, offset); +#elif defined(__LINUX__) + *value = wp_readb((hw->vector + offset)); +#else +# warning "sdla_io_read_1: Not supported yet!" +#endif + return 0; +} + +static int sdla_io_write_1(void* phw, unsigned int offset, u8 value) +{ + sdlahw_t* hw = (sdlahw_t*)phw; + + WAN_ASSERT(hw == NULL); + if (!(hw->status & SDLA_IO_MAPPED)) return 0; +#if defined(__FreeBSD__) + writeb ((u8*)hw->vector+offset, value); +#elif defined(__NetBSD__) || defined(__OpenBSD__) + bus_space_write_1(hw->hwcard->memt, hw->vector, offset, value); +#elif defined(__LINUX__) + wp_writeb(value, hw->vector + offset); +#else +# warning "sdla_io_write_1: Not supported yet!" +#endif + return 0; +} + +static int sdla_bus_write_1(void* phw, unsigned int offset, u8 value) +{ + sdlahw_t* hw = (sdlahw_t*)phw; + + WAN_ASSERT(hw == NULL); + SDLA_MAGIC(hw); + if (!(hw->status & SDLA_MEM_MAPPED)) return 0; +#if defined(__FreeBSD__) + writeb(((u8*)hw->dpmbase + offset), value); +#elif defined(__NetBSD__) || defined(__OpenBSD__) + bus_space_write_1(hw->hwcard->memt, hw->dpmbase, offset, value); +#elif defined(__LINUX__) + wp_writeb(value, hw->dpmbase + offset); +#else +# warning "sdla_bus_write_1: Not supported yet!" +#endif + return 0; +} + +static int sdla_bus_write_2(void* phw, unsigned int offset, u16 value) +{ + sdlahw_t* hw = (sdlahw_t*)phw; + + WAN_ASSERT(hw == NULL); + SDLA_MAGIC(hw); + if (!(hw->status & SDLA_MEM_MAPPED)) return 0; +#if defined(__FreeBSD__) + writew(((u8*)hw->dpmbase + offset), value); +#elif defined(__NetBSD__) || defined(__OpenBSD__) + bus_space_write_2(hw->hwcard->memt, hw->dpmbase, offset, value); +#elif defined(__LINUX__) + wp_writew(value,hw->dpmbase+offset); +#else +# warning "sdla_bus_write_2: Not supported yet!" +#endif + return 0; +} + +static int sdla_bus_write_4(void* phw, unsigned int offset, u32 value) +{ + sdlahw_t* hw = (sdlahw_t*)phw; + + WAN_ASSERT(hw == NULL); + SDLA_MAGIC(hw); + if (!(hw->status & SDLA_MEM_MAPPED)) return 0; +#if defined(__FreeBSD__) + writel(((u8*)hw->dpmbase + offset), value); +#elif defined(__NetBSD__) || defined(__OpenBSD__) + bus_space_write_4(hw->hwcard->memt, hw->dpmbase, offset, value); +#elif defined(__LINUX__) + wp_writel(value,(u8*)hw->dpmbase + offset); +#else +# warning "sdla_bus_write_4: Not supported yet!" +#endif + return 0; +} + +static int sdla_bus_read_1(void* phw, unsigned int offset, u8* value) +{ + sdlahw_t* hw = (sdlahw_t*)phw; + + WAN_ASSERT2(hw == NULL, 0); + SDLA_MAGIC(hw); + if (!(hw->status & SDLA_MEM_MAPPED)) return 0; +#if defined(__FreeBSD__) + *value = readb(((u8*)hw->dpmbase + offset)); +#elif defined(__NetBSD__) || defined(__OpenBSD__) + *value = bus_space_read_1(hw->hwcard->memt, hw->dpmbase, offset); +#elif defined(__LINUX__) + *value = wp_readb((hw->dpmbase + offset)); +#else +# warning "sdla_bus_read_1: Not supported yet!" +#endif + return 0; +} + +static int sdla_bus_read_2(void* phw, unsigned int offset, u16* value) +{ + sdlahw_t* hw = (sdlahw_t*)phw; + + WAN_ASSERT2(hw == NULL, 0); + SDLA_MAGIC(hw); + if (!(hw->status & SDLA_MEM_MAPPED)) return 0; +#if defined(__FreeBSD__) + *value = readw(((u8*)hw->dpmbase + offset)); +#elif defined(__NetBSD__) || defined(__OpenBSD__) + *value = bus_space_read_2(hw->hwcard->memt, hw->dpmbase, offset); +#elif defined(__LINUX__) + *value = readw(((unsigned char*)hw->dpmbase+offset)); +#else +# warning "sdla_bus_read_2: Not supported yet!" +#endif + return 0; +} + +static int sdla_bus_read_4(void* phw, unsigned int offset, u32* value) +{ + sdlahw_t* hw = (sdlahw_t*)phw; + + WAN_ASSERT2(hw == NULL, 0); + WAN_ASSERT2(hw->dpmbase == 0, 0); + SDLA_MAGIC(hw); + if (!(hw->status & SDLA_MEM_MAPPED)) return 0; +#if defined(__FreeBSD__) + *value = readl(((u8*)hw->dpmbase + offset)); +#elif defined(__NetBSD__) || defined(__OpenBSD__) + *value = bus_space_read_4(hw->hwcard->memt, hw->dpmbase, offset); +#elif defined(__LINUX__) + *value = wp_readl((unsigned char*)hw->dpmbase + offset); +#else +# warning "sdla_bus_read_4: Not supported yet!" +#endif + return 0; +} + +static int sdla_pci_read_config_dword(void* phw, int reg, u32* value) +{ + sdlahw_t* hw = (sdlahw_t*)phw; + sdlahw_card_t* card; + + WAN_ASSERT(hw == NULL); + SDLA_MAGIC(hw); + WAN_ASSERT(hw->hwcard == NULL); + card = hw->hwcard; +#if defined(__FreeBSD__) +# if (__FreeBSD_version > 400000) + *value = pci_read_config(card->pci_dev, reg, 4); +# else + *value = ci_cfgread(card->pci_dev, reg, 4); +# endif +#elif defined(__NetBSD__) || defined(__OpenBSD__) + *value = pci_conf_read(card->pci_dev->pa_pc, card->pci_dev->pa_tag, reg); +#elif defined(__LINUX__) + pci_read_config_dword(card->pci_dev, reg, value); +#else +# warning "sdla_pci_read_config_dword: Not supported yet!" +#endif + return 0; +} + +static int sdla_pci_read_config_word(void* phw, int reg, u16* value) +{ + sdlahw_t* hw = (sdlahw_t*)phw; + sdlahw_card_t* card; +#if defined(__NetBSD__) || defined(__OpenBSD__) + u32 tmp = 0x00; +#endif + + WAN_ASSERT(hw == NULL); + SDLA_MAGIC(hw); + WAN_ASSERT(hw->hwcard == NULL); + card = hw->hwcard; +#if defined(__FreeBSD__) +# if (__FreeBSD_version > 400000) + *value = pci_read_config(card->pci_dev, reg, 2); +# else + *value = pci_cfgread(card->pci_dev, reg, 2); +# endif +#elif defined(__NetBSD__) || defined(__OpenBSD__) + tmp = pci_conf_read(card->pci_dev->pa_pc, card->pci_dev->pa_tag, reg); + *value = (u16)((tmp >> 16) & 0xFFFF); +#elif defined(__LINUX__) + pci_read_config_word(card->pci_dev, reg, value); +#else +# warning "sdla_pci_read_config_word: Not supported yet!" +#endif + return 0; +} + +static int sdla_pci_read_config_byte(void* phw, int reg, u8* value) +{ + sdlahw_t* hw = (sdlahw_t*)phw; + sdlahw_card_t* card; +#if defined(__NetBSD__) || defined(__OpenBSD__) + u32 tmp = 0x00; +#endif + + WAN_ASSERT(hw == NULL); + SDLA_MAGIC(hw); + WAN_ASSERT(hw->hwcard == NULL); + card = hw->hwcard; +#if defined(__FreeBSD__) +# if (__FreeBSD_version > 400000) + *value = pci_read_config(card->pci_dev, reg, 1); +# else + *value = pci_cfgread(card->pci_dev, reg, 1); +# endif +#elif defined(__NetBSD__) || defined(__OpenBSD__) + tmp = pci_conf_read(card->pci_dev->pa_pc, card->pci_dev->pa_tag, reg); + *value = (u8)(tmp & 0xFF); +#elif defined(__LINUX__) + pci_read_config_byte(card->pci_dev, reg, value); +#else +# warning "sdla_pci_read_config_byte: Not supported yet!" +#endif + return 0; +} + +static int sdla_pci_write_config_dword(void* phw, int reg, u32 value) +{ + sdlahw_t* hw = (sdlahw_t*)phw; + sdlahw_card_t* card; + + WAN_ASSERT(hw == NULL); + SDLA_MAGIC(hw); + WAN_ASSERT(hw->hwcard == NULL); + card = hw->hwcard; +#if defined(__FreeBSD__) +# if (__FreeBSD_version > 400000) + pci_write_config(card->pci_dev, reg, value, 4); +# else + pci_conf_write(card->pci_dev, reg, 4); +# endif +#elif defined(__NetBSD__) || defined(__OpenBSD__) + pci_conf_write(card->pci_dev->pa_pc, card->pci_dev->pa_tag, reg, value); +#elif defined(__LINUX__) + pci_write_config_dword(card->pci_dev, reg, value); +#else +# warning "sdla_pci_write_config_dword: Not supported yet!" +#endif + return 0; +} + +static int sdla_pci_write_config_word(void* phw, int reg, u16 value) +{ + sdlahw_t* hw = (sdlahw_t*)phw; + sdlahw_card_t* card; + + WAN_ASSERT(hw == NULL); + SDLA_MAGIC(hw); + WAN_ASSERT(hw->hwcard == NULL); + card = hw->hwcard; +#if defined(__FreeBSD__) +# if (__FreeBSD_version > 400000) + pci_write_config(card->pci_dev, reg, value, 2); +# else + pci_conf_write(card->pci_dev, reg, value, 2); +# endif +#elif defined(__NetBSD__) || defined(__OpenBSD__) + pci_conf_write(card->pci_dev->pa_pc, card->pci_dev->pa_tag, reg, value); +#elif defined(__LINUX__) + pci_write_config_word(card->pci_dev, reg, value); +#else +# warning "sdla_pci_write_config_word: Not supported yet!" +#endif + return 0; +} + +static int sdla_pci_write_config_byte(void* phw, int reg, u8 value) +{ + sdlahw_t* hw = (sdlahw_t*)phw; + sdlahw_card_t* card; + + WAN_ASSERT(hw == NULL); + SDLA_MAGIC(hw); + WAN_ASSERT(hw->hwcard == NULL); + card = hw->hwcard; +#if defined(__FreeBSD__) +# if (__FreeBSD_version > 400000) + pci_write_config(card->pci_dev, reg, value, 1); +# else + pci_conf_write(card->pci_dev, reg, value, 1); +# endif +#elif defined(__NetBSD__) || defined(__OpenBSD__) + pci_conf_write(card->pci_dev->pa_pc, card->pci_dev->pa_tag, reg, value); +#elif defined(__LINUX__) + pci_write_config_byte(card->pci_dev, reg, value); +#else +# warning "sdla_pci_write_config_byte: Not supported yet!" +#endif + return 0; +} + +static int sdla_isa_read_1(void* phw, unsigned int offset, u8* value) +{ + sdlahw_t* hw = (sdlahw_t*)phw; + sdlahw_card_t* card; + + WAN_ASSERT(hw == NULL); + SDLA_MAGIC(hw); + WAN_ASSERT(hw->hwcard == NULL); + card = hw->hwcard; +#if defined(__FreeBSD__) + *value = inb (card->ioport + offset); +#elif defined(__NetBSD__) || defined(__OpenBSD__) + *value = bus_space_read_1(card->iot, hw->ioh, offset); +#elif defined(__LINUX__) + *value = inb(card->ioport + offset); +#else +# warning "sdla_isa_read_1: Not supported yet!" +#endif + return 0; +} + +static int sdla_isa_write_1(void* phw, unsigned int offset, u8 value) +{ + sdlahw_t* hw = (sdlahw_t*)phw; + sdlahw_card_t* card; + + WAN_ASSERT(hw == NULL); + SDLA_MAGIC(hw); + WAN_ASSERT(hw->hwcard == NULL); + card = hw->hwcard; + hw->regs[offset] = value; +#if defined(__FreeBSD__) + outb (card->ioport + offset, value); +#elif defined(__NetBSD__) || defined(__OpenBSD__) + bus_space_write_1(card->iot, hw->ioh, offset, value); +#elif defined(__LINUX__) + outb(value, card->ioport + offset); +#else +# warning "sdla_isa_write_1: Not supported yet!" +#endif + return 0; +} + +static int sdla_hw_lock(void *phw, wan_smp_flag_t *flag) +{ + sdlahw_t* hw = (sdlahw_t*)phw; + sdlahw_card_t* hwcard; + + WAN_ASSERT(hw == NULL); + SDLA_MAGIC(hw); + WAN_ASSERT(hw->hwcard == NULL); + hwcard = hw->hwcard; + wan_spin_lock(&hwcard->pcard_lock); + return 0; +} + +static int sdla_hw_unlock(void *phw, wan_smp_flag_t *flag) +{ + sdlahw_t* hw = (sdlahw_t*)phw; + sdlahw_card_t* hwcard; + + WAN_ASSERT(hw == NULL); + SDLA_MAGIC(hw); + WAN_ASSERT(hw->hwcard == NULL); + hwcard = hw->hwcard; + wan_spin_unlock(&hwcard->pcard_lock); + return 0; +} + +static sdla_dma_addr_t sdla_pci_map_dma(void *phw, void *buf, int len, int ctrl) +{ + sdlahw_t* hw = (sdlahw_t*)phw; + sdlahw_card_t* hwcard; + + WAN_ASSERT(hw == NULL); + SDLA_MAGIC(hw); + WAN_ASSERT(hw->hwcard == NULL); + hwcard = hw->hwcard; + +#if defined(__LINUX__) + return pci_map_single(hwcard->pci_dev, buf, len, ctrl); +#else + return virt_to_phys(buf); +#endif +} + +static int sdla_pci_unmap_dma(void *phw, sdla_dma_addr_t buf, int len, int ctrl) +{ + sdlahw_t* hw = (sdlahw_t*)phw; + sdlahw_card_t* hwcard; + + WAN_ASSERT(hw == NULL); + SDLA_MAGIC(hw); + WAN_ASSERT(hw->hwcard == NULL); + hwcard = hw->hwcard; + +#if defined(__LINUX__) + pci_unmap_single(hwcard->pci_dev, buf, len, ctrl); +#endif + return 0; +} + + +static int sdla_hw_fe_test_and_set(void *phw) +{ + sdlahw_t* hw = (sdlahw_t*)phw; + sdlahw_card_t* hwcard; + + WAN_ASSERT(hw == NULL); + SDLA_MAGIC(hw); + WAN_ASSERT(hw->hwcard == NULL); + hwcard = hw->hwcard; + return wan_test_and_set_bit(0, &hwcard->fe_rw_flag); +} + +static int sdla_hw_fe_clear(void *phw) +{ + sdlahw_t* hw = (sdlahw_t*)phw; + sdlahw_card_t* hwcard; + + WAN_ASSERT(hw == NULL); + SDLA_MAGIC(hw); + WAN_ASSERT(hw->hwcard == NULL); + hwcard = hw->hwcard; + wan_clear_bit(0, &hwcard->fe_rw_flag); + return 0; +} + +static int sdla_hw_read_cpld(void *phw, u16 off, u8 *data) +{ + sdlahw_t* hw = (sdlahw_t*)phw; + u16 org_off; + + switch(hw->hwcard->adptr_type){ + case A101_ADPTR_1TE1: + case A101_ADPTR_2TE1: + off &= ~AFT_BIT_DEV_ADDR_CLEAR; + off |= AFT_BIT_DEV_ADDR_CPLD; + /* Save current original address */ + sdla_bus_read_2(hw, AFT_MCPU_INTERFACE_ADDR, &org_off); + sdla_bus_write_2(hw, AFT_MCPU_INTERFACE_ADDR, off); + sdla_bus_read_1(hw, AFT_MCPU_INTERFACE, data); + /* Restore the original address */ + sdla_bus_write_2(hw, AFT_MCPU_INTERFACE_ADDR, org_off); + break; + + case A104_ADPTR_4TE1: + off &= ~AFT4_BIT_DEV_ADDR_CLEAR; + off |= AFT4_BIT_DEV_ADDR_CPLD; + /* Save current original address */ + sdla_bus_read_2(hw, AFT_MCPU_INTERFACE_ADDR, &org_off); + WP_DELAY(5); + sdla_bus_write_2(hw, AFT_MCPU_INTERFACE_ADDR, off); + WP_DELAY(5); + sdla_bus_read_1(hw, AFT_MCPU_INTERFACE, data); + /* Restore the original address */ + sdla_bus_write_2(hw, AFT_MCPU_INTERFACE_ADDR, org_off); + break; + + case A108_ADPTR_8TE1: + off &= ~AFT8_BIT_DEV_ADDR_CLEAR; + off |= AFT8_BIT_DEV_ADDR_CPLD; + + /* Save current original address */ + sdla_bus_read_2(hw, AFT_MCPU_INTERFACE_ADDR, &org_off); + WP_DELAY(5); + sdla_bus_write_2(hw, AFT_MCPU_INTERFACE_ADDR, off); + WP_DELAY(5); + sdla_bus_read_1(hw, AFT_MCPU_INTERFACE, data); + /* Restore the original address */ + sdla_bus_write_2(hw, AFT_MCPU_INTERFACE_ADDR, org_off); + break; + + case A200_ADPTR_ANALOG: + off &= ~AFT4_BIT_DEV_ADDR_CLEAR; + off |= AFT4_BIT_DEV_ADDR_CPLD; + /* Save current original address */ + sdla_bus_read_2(hw, AFT_MCPU_INTERFACE_ADDR, &org_off); + WP_DELAY(5); + sdla_bus_write_2(hw, AFT_MCPU_INTERFACE_ADDR, off); + WP_DELAY(5); + sdla_bus_read_1(hw, AFT_MCPU_INTERFACE, data); + /* Restore the original address */ + sdla_bus_write_2(hw, AFT_MCPU_INTERFACE_ADDR, org_off); + break; + + default: + DEBUG_EVENT("%s: ERROR: Invalid read access to cpld!\n", + hw->devname); + return -EINVAL; + } + return 0; +} + +static int sdla_hw_write_cpld(void *phw, u16 off, u8 data) +{ + sdlahw_t* hw = (sdlahw_t*)phw; + u16 org_off; + + switch(hw->hwcard->adptr_type){ + case A101_ADPTR_1TE1: + case A101_ADPTR_2TE1: + off &= ~AFT_BIT_DEV_ADDR_CLEAR; + off |= AFT_BIT_DEV_ADDR_CPLD; + /* Save current original address */ + sdla_bus_read_2(hw, AFT_MCPU_INTERFACE_ADDR, &org_off); + sdla_bus_write_2(hw, AFT_MCPU_INTERFACE_ADDR, off); + sdla_bus_write_1(hw, AFT_MCPU_INTERFACE, data); + /* Restore the original address */ + sdla_bus_write_2(hw, AFT_MCPU_INTERFACE_ADDR, org_off); + break; + + case A104_ADPTR_4TE1: + off &= ~AFT4_BIT_DEV_ADDR_CLEAR; + off |= AFT4_BIT_DEV_ADDR_CPLD; + /* Save current original address */ + sdla_bus_read_2(hw, AFT_MCPU_INTERFACE_ADDR, &org_off); + WP_DELAY(5); + sdla_bus_write_2(hw, AFT_MCPU_INTERFACE_ADDR, off); + WP_DELAY(5); + sdla_bus_write_1(hw, AFT_MCPU_INTERFACE, data); + /* Restore the original address */ + sdla_bus_write_2(hw, AFT_MCPU_INTERFACE_ADDR, org_off); + break; + + case A108_ADPTR_8TE1: + off &= ~AFT8_BIT_DEV_ADDR_CLEAR; + off |= AFT8_BIT_DEV_ADDR_CPLD; + /* Save current original address */ + sdla_bus_read_2(hw, AFT_MCPU_INTERFACE_ADDR, &org_off); + WP_DELAY(5); + sdla_bus_write_2(hw, AFT_MCPU_INTERFACE_ADDR, off); + WP_DELAY(5); + sdla_bus_write_1(hw, AFT_MCPU_INTERFACE, data); + /* Restore the original address */ + sdla_bus_write_2(hw, AFT_MCPU_INTERFACE_ADDR, org_off); + break; + + case A200_ADPTR_ANALOG: + off &= ~AFT4_BIT_DEV_ADDR_CLEAR; + off |= AFT4_BIT_DEV_ADDR_CPLD; + /* Save current original address */ + sdla_bus_read_2(hw, AFT_MCPU_INTERFACE_ADDR, &org_off); + WP_DELAY(5); + sdla_bus_write_2(hw, AFT_MCPU_INTERFACE_ADDR, off); + WP_DELAY(5); + sdla_bus_write_1(hw, AFT_MCPU_INTERFACE, data); + /* Restore the original address */ + sdla_bus_write_2(hw, AFT_MCPU_INTERFACE_ADDR, org_off); + break; + + default: + DEBUG_EVENT("%s: ERROR: Invalid write access to cpld!\n", + hw->devname); + return -EINVAL; + } + return 0; +} diff -Nur linux.org/drivers/net/wan/sdladrv.mod.c linux-2.6.17/drivers/net/wan/sdladrv.mod.c --- linux.org/drivers/net/wan/sdladrv.mod.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/drivers/net/wan/sdladrv.mod.c 2006-08-30 10:07:16.000000000 +0000 @@ -0,0 +1,30 @@ +#include +#include +#include + +MODULE_INFO(vermagic, VERMAGIC_STRING); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,6) || defined(WANPIPE_MOD_266_FORCE_UPDATE) +#undef unix +struct module __this_module +__attribute__((section(".gnu.linkonce.this_module"))) = { + .name = __stringify(KBUILD_MODNAME), + .init = init_module, +#ifdef CONFIG_MODULE_UNLOAD + .exit = cleanup_module, +#endif +}; +#endif + +static const struct modversion_info ____versions[] +__attribute_used__ +__attribute__((section("__versions"))) = { + +}; + +static const char __module_depends[] +__attribute_used__ +__attribute__((section(".modinfo"))) = +"depends="; + + diff -Nur linux.org/drivers/net/wan/sdla_ec.c linux-2.6.17/drivers/net/wan/sdla_ec.c --- linux.org/drivers/net/wan/sdla_ec.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/drivers/net/wan/sdla_ec.c 2006-08-30 10:07:16.000000000 +0000 @@ -0,0 +1,945 @@ +/*************************************************************************** + * sdla_ec.c WANPIPE(tm) Multiprotocol WAN Link Driver. + * TDM voice hardware echo cancler. + * + * Author: Alex Feldman + * + * + * Copyright: (c) 1995-2005 Sangoma Technologies Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * ============================================================================ + * Aug 25, 2005 Alex Feldman Initial version. + ****************************************************************************** + */ +/******************************************************************************* +** INCLUDE FILES +*******************************************************************************/ +#if defined (__FreeBSD__) || defined(__OpenBSD__) +# include +# include +# include +# include +# include +# include +# include +# if defined(WAN_OCT6100_DAEMON) +# include +# endif +#elif (defined __WINDOWS__) +# include +#else +# include +# include +# include +# include +# if defined(WAN_OCT6100_DAEMON) +# include +# endif +#endif + +#define WAN_OCT6100_MOD + +extern void aft_fe_intr_ctrl(sdla_t *card, int status); + +/******************************************************************************* +** DEFINES AND MACROS +*******************************************************************************/ +#define WAN_OCT6100_READ_LIMIT 0x10000 + + +/***************************************************************************** +** STRUCTURES AND TYPEDEFS +*****************************************************************************/ + + + +/***************************************************************************** +** GLOBAL VARIABLES +*****************************************************************************/ +#if defined(WAN_OCT6100_DAEMON) +static int wan_ec_no = 0; +WAN_LIST_HEAD(wan_ec_head_, wan_ec_) wan_ec_head = + WAN_LIST_HEAD_INITIALIZER(wan_ec_head); +#endif + +/***************************************************************************** +** FUNCTION PROTOTYPES +*****************************************************************************/ +#if defined(WAN_OCT6100_DAEMON) +static int wan_ec_reset(wan_ec_dev_t*, sdla_t*, int); +static int wan_ec_action(void *pcard, int enable, int channel); +#endif + +extern unsigned char aft_read_cpld(sdla_t*, unsigned short); +extern int aft_write_cpld(void*, unsigned short,unsigned char); + +extern void *wanpipe_eclip_register(void*, int); +extern int wanpipe_eclip_unregister(void*,void*); + +/***************************************************************************** +** FUNCTION DEFINITIONS +*****************************************************************************/ +#if defined(WAN_OCT6100_DAEMON) +#define my_isdigit(c) ((c) >= '0' && (c) <= '9') +static int wan_ec_devnum(char *ptr) +{ + int num = 0, base = 1; + int i = 0; + + while(!my_isdigit(*ptr)) ptr++; + while(my_isdigit(ptr[i])){ + i++; + base = base * 10; + } + if (i){ + i=0; + do { + base = base / 10; + num = num + (ptr[i]-'0') * base; + i++; + }while(my_isdigit(ptr[i])); + } + return num; +} +#endif + +void *wan_ec_config(void *pcard, int max_channels) +{ + sdla_t *card = (sdla_t*)pcard; + + +#if defined(WAN_OCT6100_DAEMON) + wan_ec_t *ec = NULL; + wan_ec_dev_t *ec_dev = NULL, *ec_dev_new = NULL; + int err; + + WAN_LIST_FOREACH(ec, &wan_ec_head, next){ + WAN_LIST_FOREACH(ec_dev, &ec->ec_dev, next){ + if (ec_dev->card == NULL || ec_dev->card == card){ + DEBUG_EVENT("%s: Internal Error (%s:%d)\n", + card->devname, + __FUNCTION__,__LINE__); + return NULL; + } + } + } + WAN_LIST_FOREACH(ec, &wan_ec_head, next){ + WAN_LIST_FOREACH(ec_dev, &ec->ec_dev, next){ + if (card->hw_iface.hw_same(ec_dev->card->hw, card->hw)){ + /* Current OCT6100 chip is already in use */ + break; + } + } + if (ec_dev){ + break; + } + } + ec_dev_new = wan_malloc(sizeof(wan_ec_dev_t)); + if (ec_dev_new == NULL){ + DEBUG_EVENT("%s: ERROR: Failed to allocate memory (%s:%d)!\n", + card->devname, + __FUNCTION__,__LINE__); + return NULL; + } + memset(ec_dev_new, 0, sizeof(wan_ec_dev_t)); + + if (ec_dev == NULL){ + + /* First device for current Oct6100 chip */ + ec = wan_malloc(sizeof(wan_ec_t)); + if (ec == NULL){ + DEBUG_EVENT("%s: ERROR: Failed to allocate memory (%s:%d)!\n", + card->devname, + __FUNCTION__,__LINE__); + return NULL; + } + memset(ec, 0, sizeof(wan_ec_t)); + ec->chip_no = ++wan_ec_no; + ec->state = WAN_OCT6100_STATE_RESET; + ec->ec_channels_no = 0; + ec->max_channels = max_channels; + sprintf(ec->name, "wp_ec%d", ec->chip_no); + + WAN_LIST_INIT(&ec->ec_dev); + + WAN_LIST_INSERT_HEAD(&wan_ec_head, ec, next); + + }else{ + ec = ec_dev->ec; + } + ec->usage++; + ec_dev_new->ecdev_no = wan_ec_devnum(card->devname); + ec_dev_new->ec = ec; + ec_dev_new->name = ec->name; + ec_dev_new->card = card; + /* Initialize hwec_bypass pointer */ + card->wandev.ec_action = wan_ec_action; + card->wandev.ec_map = 0; + memcpy(ec_dev_new->devname, card->devname, sizeof(card->devname)); + sprintf(ec_dev_new->ecdev_name, "wp%dec", ec_dev_new->ecdev_no); +#if defined(__LINUX__) + err=wanpipe_ecdev_reg(ec, ec_dev_new->ecdev_name, ec_dev_new->ecdev_no); + if (err){ + DEBUG_EVENT( + "%s: ERROR: Failed to create device (%s:%d)!\n", + card->devname, + __FUNCTION__,__LINE__); + return NULL; + } +#else + err=wp_cdev_reg(ec, ec_dev_new->ecdev_name, wan_ec_dev_ioctl); + if (err){ + DEBUG_EVENT( + "%s: ERROR: Failed to create device (%s:%d)!\n", + card->devname, + __FUNCTION__,__LINE__); + return NULL; + } +#endif + WAN_LIST_INSERT_HEAD(&ec->ec_dev, ec_dev_new, next); + + DEBUG_EVENT("%s: Register EC interface %s (usage %d, max ec channels %d)!\n", + ec_dev_new->devname, + ec->name, + ec->usage, + ec->max_channels); + return (void*)ec_dev_new; +#else + return wanpipe_eclip_register(card, max_channels); +#endif +} + +int wan_ec_remove(void *arg, void *pcard) +{ +#if defined(WAN_OCT6100_DAEMON) + sdla_t *card = (sdla_t*)pcard; + wan_ec_t *ec = NULL; + wan_ec_dev_t *ec_dev = (wan_ec_dev_t*)arg; + + WAN_ASSERT(ec_dev == NULL); + ec = ec_dev->ec; + DEBUG_EVENT("%s: Unregister EC interface %s (chip id %d, usage %d)!\n", + card->devname, + ec->name, + ec->chip_no, + ec->usage); + ec_dev->card = NULL; + ec->usage--; + if (WAN_LIST_FIRST(&ec->ec_dev) == ec_dev){ + WAN_LIST_FIRST(&ec->ec_dev) = + WAN_LIST_NEXT(ec_dev, next); + WAN_LIST_NEXT(ec_dev, next) = NULL; + }else{ + WAN_LIST_REMOVE(ec_dev, next); + } +#if defined(__LINUX__) + wanpipe_ecdev_unreg(ec_dev->ecdev_no); +#else + wp_cdev_unreg(ec_dev->ecdev_name); +#endif + if (!ec->usage){ + ec_dev->ec = NULL; + wan_free(ec_dev); + if (WAN_LIST_FIRST(&wan_ec_head) == ec){ + WAN_LIST_FIRST(&wan_ec_head) = + WAN_LIST_NEXT(ec, next); + WAN_LIST_NEXT(ec, next) = NULL; + }else{ + WAN_LIST_REMOVE(ec, next); + } + wan_free(ec); + }else{ + ec_dev->ec = NULL; + wan_free(ec_dev); + } + return 0; +#else + return wanpipe_eclip_unregister(arg, pcard); +#endif +} + +#if defined(WAN_OCT6100_DAEMON) +static wan_ec_dev_t *wan_ec_search(char *devname) +{ + wan_ec_t *ec; + wan_ec_dev_t *ec_dev = NULL; + + WAN_LIST_FOREACH(ec, &wan_ec_head, next){ + WAN_LIST_FOREACH(ec_dev, &ec->ec_dev, next){ + if (strcmp(ec_dev->devname, devname) == 0){ + return ec_dev; + } + } + } + return NULL; +} + +static int +wan_ec_reset(wan_ec_dev_t *ec_dev, sdla_t *card, int cmd) +{ + wan_ec_t *ec; + int err = -EINVAL; + + WAN_ASSERT(ec_dev == NULL); + ec = ec_dev->ec; + + if (card->wandev.hwec_reset){ + err = card->wandev.hwec_reset( + card, + (cmd==WAN_OCT6100_CMD_SET_RESET) ? + AFT_HWEC_SET_RESET : + AFT_HWEC_CLEAR_RESET); + if (!err){ + if (cmd == WAN_OCT6100_CMD_SET_RESET){ + ec->state = WAN_OCT6100_STATE_RESET; + }else{ + ec->state = WAN_OCT6100_STATE_READY; + } + } + } + return err; +} + +static int wan_ec_action(void *pcard, int enable, int channel) +{ + sdla_t *card = (sdla_t*)pcard; + wan_ec_t *ec = NULL; + wan_ec_dev_t *ec_dev = NULL; + int err = -ENODEV; + + ec_dev = wan_ec_search(card->devname); + WAN_ASSERT(ec_dev == NULL); + WAN_ASSERT(ec_dev->ec == NULL); + ec = ec_dev->ec; + + DEBUG_HWEC("[HWEC]: %s: %s bypass mode for channel %d!\n", + card->devname, + (enable) ? "Enable" : "Disable", + channel); + + if (card->wandev.hwec_enable){ + if (enable){ + if (ec->ec_channels_no >= ec->max_channels){ + DEBUG_EVENT("%s: Exceeded maximum number of Echo Canceller channels (max=%d)!\n", + ec->name, + ec->max_channels); + return -ENODEV; + } + } + err = card->wandev.hwec_enable(card, enable, channel); + if (!err){ + if (enable){ + ec->ec_channels_no++; + }else{ + ec->ec_channels_no--; + } + } + } + return err; +} + +static int wan_ec_tone_detection(void *pcard, wan_ec_api_t *ec_api) +{ + sdla_t *card = (sdla_t*)pcard; + + WAN_ASSERT(card == NULL); + + DEBUG_EVENT("[HWEC]: %s: Received tone event on channel %d: %s %s!\n", + card->devname, + ec_api->u_tone.fe_chan, + WAN_EC_DECODE_TONE_TYPE(ec_api->u_tone.type), + WAN_EC_DECODE_DTMF_ID(ec_api->u_tone.id)); + + return 0; +} + +static u32 convert_addr(u32 addr) +{ + addr &= 0xFFFF; + switch(addr){ + case 0x0000: + return 0x60; + case 0x0002: + return 0x64; + case 0x0004: + return 0x68; + case 0x0008: + return 0x70; + case 0x000A: + return 0x74; + } + return 0x00; +} + +/*===========================================================================*\ + ReadInternalDword +\*===========================================================================*/ +static int +wan_ec_read_internal_dword(wan_ec_dev_t *ec_dev, u32 addr1, u32 *data) +{ + sdla_t *card = ec_dev->card; + u32 addr; + int err; + + WAN_ASSERT(card == NULL); + addr = convert_addr(addr1); + if (addr == 0x00){ + DEBUG_EVENT("%s: %s:%d: Internal Error (EC off %X)\n", + card->devname, + __FUNCTION__,__LINE__, + addr1); + return -EINVAL; + } + + err = card->hw_iface.bus_read_4(card->hw, addr, data); + + WP_DELAY(5); + return err; +} + + +/*===========================================================================*\ + WriteInternalDword +\*===========================================================================*/ +static int +wan_ec_write_internal_dword(wan_ec_dev_t *ec_dev, u32 addr1, u32 data) +{ + sdla_t *card = ec_dev->card; + u32 addr; + int err; + + WAN_ASSERT(card == NULL); + addr = convert_addr(addr1); + if (addr == 0x00){ + DEBUG_EVENT("%s: %s:%d: Internal Error (EC off %X)\n", + card->devname, + __FUNCTION__,__LINE__, + addr1); + return -EINVAL; + } + + + err = card->hw_iface.bus_write_4(card->hw, addr, data); + + WP_DELAY(5); + return err; +} + +/*===========================================================================*\ + Oct6100Read +\*===========================================================================*/ + +static int +wan_ec_read(wan_ec_dev_t *ec_dev, u32 read_addr, u16 *read_data) +{ + u32 data; + wan_ec_read_internal_dword(ec_dev, read_addr, &data); + *read_data = (u16)(data & 0xFFFF); + return 0; +} + +/*===========================================================================*\ + Oct6100Write +\*===========================================================================*/ + +static int +wan_ec_write(wan_ec_dev_t *ec_dev, u32 write_addr, u32 write_data) +{ + return wan_ec_write_internal_dword(ec_dev, write_addr, write_data); +} + + +/*===========================================================================*\ + Oct6100WriteSequenceSub +\*===========================================================================*/ +static u32 +wan_ec_write_seq(wan_ec_dev_t *ec_dev, u32 write_addr, u16 write_data) +{ + u32 ulResult; + u32 ulData; + u16 usData; + u32 ulWordAddress; + u32 i; + + /* Create the word address from the provided byte address. */ + ulWordAddress = write_addr >> 1; + + /* 16-bit indirect access. */ + + /* First write to the address indirection registers. */ + ulData = ( ulWordAddress >> 19 ) & 0x1FFF; + ulResult = wan_ec_write( ec_dev, 0x8, ulData ); + if (ulResult) + return ulResult; + + ulData = ( ulWordAddress >> 3 ) & 0xFFFF; + ulResult = wan_ec_write( ec_dev, 0xA, ulData ); + if (ulResult) + return ulResult; + + /* Next, write data word to read/write data registers. */ + ulData = write_data & 0xFFFF; + ulResult = wan_ec_write( ec_dev, 0x4, ulData ); + if ( ulResult ) + return ulResult; + + + /* Write the parities and write enables, as well as last three bits + ** of wadd and request the write access. */ + ulData = ( ( 0x0 & 0x3 ) << 14 ) | ( ( 0x3 & 0x3 ) << 12 ) | ( ( ulWordAddress & 0x7 ) << 9 ) | 0x0100; + ulResult = wan_ec_write( ec_dev, 0x0, ulData ); + if ( ulResult ) + return ulResult; + + /* Keep polling register contol0 for the access_req bit to go low. */ + for ( i = 0; i < WAN_OCT6100_READ_LIMIT; i++ ) + { + ulResult = wan_ec_read( ec_dev, 0, &usData ); + if ( ulResult ) + return ulResult; + + if ( ( ( usData >> 8 ) & 0x1 ) == 0x0 ) + break; + } + + if ( i == WAN_OCT6100_READ_LIMIT ){ + DEBUG_EVENT("%s: EC write command reached limit!\n", + ec_dev->name); + return WAN_OCT6100_RC_CPU_INTERFACE_NO_RESPONSE; + } + return 0; +} + + +/*===========================================================================*\ + HandleReqWriteOct6100 +\*===========================================================================*/ +EXPORT_SYMBOL(wan_ec_req_write); +u32 wan_ec_req_write(void *arg, u32 write_addr, u16 write_data) +{ + wan_ec_dev_t *ec_dev = (wan_ec_dev_t*)arg; + u32 ulResult; + + DEBUG_TEST(": %s: EC WRITE API addr=%X data=%X\n", + ec_dev->ec->name, write_addr, write_data); + ulResult = wan_ec_write_seq(ec_dev, write_addr, write_data); + if (ulResult){ + DEBUG_EVENT("%s: Failed to write %04X to addr %08X\n", + ec_dev->name, + write_addr, + write_data); + } + return ulResult; +} + + +/*===========================================================================*\ + HandleReqWriteSmearOct6100 +\*===========================================================================*/ +EXPORT_SYMBOL(wan_ec_req_write_smear); +u32 wan_ec_req_write_smear(void *arg, u32 addr, u16 data, u32 len) +{ + wan_ec_dev_t *ec_dev = (wan_ec_dev_t*)arg; + u32 i, ulResult = WAN_OCT6100_RC_OK; + + WAN_ASSERT(ec_dev == NULL); + for ( i = 0; i < len; i++ ){ + ulResult = wan_ec_write_seq(ec_dev, addr + (i*2), data); + if (ulResult){ + DEBUG_EVENT("%s: Failed to write %04X to addr %08X\n", + ec_dev->name, + addr + (i*2), + data); + break; + } + } + return ulResult; +} + + +/*===========================================================================*\ + HandleReqWriteBurstOct6100 +\*===========================================================================*/ +EXPORT_SYMBOL(wan_ec_req_write_burst); +u32 wan_ec_req_write_burst(void *arg, u32 addr, u16 *data, u32 len) +{ + wan_ec_dev_t *ec_dev = (wan_ec_dev_t*)arg; + u32 i, ulResult = WAN_OCT6100_RC_OK; + + WAN_ASSERT(ec_dev == NULL); + + for ( i = 0; i < len; i++ ){ + ulResult = wan_ec_write_seq(ec_dev, addr + (i * 2), data[i]); + if (ulResult){ + DEBUG_EVENT("%s: Failed to write %04X to addr %08X\n", + ec_dev->name, + addr + (i*2), + data[i]); + break; + } + } + return ulResult; +} + + +/*===========================================================================*\ + Oct6100ReadSequenceSub +\*===========================================================================*/ +static u32 +wan_ec_read_seq(wan_ec_dev_t *ec_dev, u32 read_addr, u16 *read_data, u32 read_len) +{ + u32 ulResult; + u32 ulData; + u32 ulWordAddress; + u32 ulReadBurstLength; + u16 usData; + u32 i; + + /* Create the word address from the provided byte address. */ + ulWordAddress = read_addr >> 1; + + /* Indirect accesses. */ + + /* First write to the address indirection registers. */ + ulData = ( ulWordAddress >> 19 ) & 0x1FFF; + ulResult = wan_ec_write( ec_dev, 0x8, ulData ); + if (ulResult) + return ulResult; + + ulData = ( ulWordAddress >> 3 ) & 0xFFFF; + ulResult = wan_ec_write( ec_dev, 0xA, ulData ); + if (ulResult) + return ulResult; + + /* Request access. */ + if ( read_len >= 128 ) + { + ulData = 0x100 | ( ( ulWordAddress & 0x7 ) << 9); + ulReadBurstLength = 0; + } + else + { + ulData = 0x100 | ( ( ulWordAddress & 0x7 ) << 9) | read_len; + ulReadBurstLength = read_len; + } + ulResult = wan_ec_write( ec_dev, 0x0, ulData ); + if (ulResult) + return ulResult; + + /* Keep polling register contol0 for the access_req bit to go low. */ + for ( i = 0; i < WAN_OCT6100_READ_LIMIT; i++ ) + { + ulResult = wan_ec_read( ec_dev, 0x0, &usData ); + if (ulResult) + return ulResult; + + if ( ( ( usData >> 8 ) & 0x1 ) == 0x0 ) + break; + } + if ( i == WAN_OCT6100_READ_LIMIT ){ + DEBUG_EVENT("%s: EC read command reached limit!\n", + ec_dev->name); + return WAN_OCT6100_RC_CPU_INTERFACE_NO_RESPONSE; + } + + if ( ( usData & 0xFF ) == 0x1 ) + { + i = 0; + } + + /* Retrieve read data. */ + ulResult = wan_ec_read( ec_dev, 0x4, &usData ); + if (ulResult) + return ulResult; + + if ( ( usData & 0xFF ) == 0x1 ) + { + i = 0; + } + + *read_data = usData; + return 0; +} + +EXPORT_SYMBOL(wan_ec_req_read); +u32 wan_ec_req_read(void *arg, u32 addr, u16 *data) +{ + wan_ec_dev_t *ec_dev = (wan_ec_dev_t*)arg; + u32 ulResult; + + WAN_ASSERT(ec_dev == NULL); + DEBUG_TEST("%s: EC READ API addr=%X data=????\n", + ec_dev->ec->name, addr); + ulResult = wan_ec_read_seq( + ec_dev, + addr, + data, + 1); + if (ulResult){ + DEBUG_EVENT("%s: Failed to read data from addr %08X\n", + ec_dev->name, + addr); + } + DEBUG_TEST("%s: EC READ API addr=%X data=%X\n", + ec_dev->ec->name, + addr, *data); + return ulResult; +} + + +EXPORT_SYMBOL(wan_ec_req_read_burst); +u32 wan_ec_req_read_burst(void *arg, u32 addr, u16 *data, u32 len) +{ + wan_ec_dev_t *ec_dev = (wan_ec_dev_t*)arg; + u32 i, ulResult = WAN_OCT6100_RC_OK; + u16 read_data; + + for ( i = 0; i < len; i++ ){ + ulResult = wan_ec_read_seq(ec_dev, addr, &read_data, 1); + if (ulResult){ + DEBUG_EVENT("%s: Failed to read from addr %X\n", + ec_dev->name, + addr); + break; + } + data[i] = (u16)read_data; + addr += 2; + } + return ulResult; +} + +static int +wan_ec_req_write_burst_prepare(wan_ec_dev_t *ec_dev, wan_ec_api_t *ec_api) +{ + u32 len = ec_api->u_oct6100_write_burst.ulWriteLength; + u16 *user_space = (u16*)ec_api->u_oct6100_write_burst.pWriteData, + *data = NULL; + u32 ulResult = WAN_OCT6100_RC_OK; + int err = 0; + + WAN_ASSERT(ec_dev == NULL); + data = wan_malloc(len * sizeof(u16)); + if (data == NULL){ + DEBUG_EVENT("%s: Failed to allocate memory space [%s:%d]!\n", + ec_dev->name, + __FUNCTION__,__LINE__); + return WAN_OCT6100_RC_MEMORY; + } + err = WAN_COPY_FROM_USER(data, user_space, len * sizeof(u16)); + if (err){ + DEBUG_EVENT("%s: Failed to copy data from user space [%s:%d]!\n", + ec_dev->ec->name, + __FUNCTION__,__LINE__); + wan_free(data); + return WAN_OCT6100_RC_MEMORY; + } + ulResult = wan_ec_req_write_burst( + ec_dev, + ec_api->u_oct6100_write_burst.ulWriteAddress, + data, + ec_api->u_oct6100_write_burst.ulWriteLength); + + if (data) wan_free(data); + return ulResult; +} + +static int +wan_ec_req_read_burst_prepare(wan_ec_dev_t *ec_dev, wan_ec_api_t *ec_api) +{ + u32 len = ec_api->u_oct6100_read_burst.ulReadLength; + u16 *user_space = (u16*)ec_api->u_oct6100_read_burst.pReadData, + *data = NULL; + u32 ulResult = WAN_OCT6100_RC_OK; + int err; + + WAN_ASSERT(ec_dev == NULL); + data = wan_malloc(len * sizeof(u16)); + if (data == NULL){ + DEBUG_EVENT("%s: Failed allocate memory (%d bytes)\n", + ec_dev->name, + len * sizeof(u16)); + return WAN_OCT6100_RC_MEMORY; + } + + ulResult = wan_ec_req_read_burst( + ec_dev, + ec_api->u_oct6100_read_burst.ulReadAddress, + data, + ec_api->u_oct6100_read_burst.ulReadLength); + if (ulResult == WAN_OCT6100_RC_OK){ + err = WAN_COPY_TO_USER( user_space, + data, + len * sizeof(u16)); + if (err){ + DEBUG_EVENT("%s: Failed to copy data to user space [%s:%d]!\n", + ec_dev->ec->name, + __FUNCTION__,__LINE__); + ulResult = WAN_OCT6100_RC_MEMORY; + } + } + if (data) wan_free(data); + return ulResult; +} + +static int wan_ec_getinfo(wan_ec_dev_t *ec_dev, wan_ec_api_t *ec_api) +{ + sdla_t *card = ec_dev->card; + wan_ec_t *ec = NULL; + + if (strcmp(card->devname, ec_api->devname)){ + DEBUG_EVENT("%s:%s: Failed to find %s device!\n", + card->devname, ec_api->if_name, + ec_api->devname); + return -EINVAL; + } + ec = ec_dev->ec; + + memcpy(ec_api->name, ec->name, strlen(ec->name)); + ec_api->u_ecd.state = ec->state; + ec_api->u_ecd.chip_no = ec->chip_no; + ec_api->u_ecd.fe_media = WAN_FE_MEDIA(&card->fe); + ec_api->u_ecd.fe_lineno = WAN_FE_LINENO(&card->fe); + ec_api->u_ecd.fe_max_channels = WAN_FE_MAX_CHANNELS(&card->fe); + ec_api->u_ecd.fe_tdmv_law = WAN_FE_TDMV_LAW(&card->fe); + ec_api->u_ecd.max_channels = ec->max_channels; + ec_api->u_ecd.max_ec_channels = ec->max_ec_channels; + ec_api->u_ecd.ulApiInstanceSize = ec->ulApiInstanceSize; + + return 0; +} +#endif + + +int wan_ec_dev_ioctl(void *ec_arg, void *data) +{ +#if defined(WAN_OCT6100_DAEMON) + sdla_t *card = NULL; + wan_ec_t *ec = (wan_ec_t*)ec_arg; + wan_ec_dev_t *ec_dev = NULL; + wan_ec_api_t *ec_api = NULL; + int err = 0; + + ec_dev = WAN_LIST_FIRST(&ec->ec_dev); + if (ec_dev == NULL){ + DEBUG_EVENT("%s: Internal Error (%s:%d)\n", + ec->name, + __FUNCTION__,__LINE__); + return -EINVAL; + } + card = ec_dev->card; +#if defined(__LINUX__) + ec_api = wan_malloc(sizeof(wan_ec_api_t)); + if (ec_api == NULL){ + DEBUG_EVENT("%s: Failed allocate memory (%d) [%s:%d]!\n", + ec->name, + sizeof(wan_ec_api_t), + __FUNCTION__,__LINE__); + return -EINVAL; + } + err = WAN_COPY_FROM_USER( + ec_api, + data, + sizeof(wan_ec_api_t)); + if (err){ + DEBUG_EVENT("%s: Failed to copy data from user space [%s:%d]!\n", + ec->name, + __FUNCTION__,__LINE__); + wan_free(ec_api); + return -EINVAL; + } +#else + ec_api = (wan_ec_api_t*)data; +#endif + + DEBUG_TEST("%s: EC DEV cmd %s\n", + ec->name, + WAN_OCT6100_CMD_DECODE(ec_api->cmd)); + switch(ec_api->cmd){ + case WAN_OCT6100_CMD_GET_INFO: + err = wan_ec_getinfo(ec_dev, ec_api); + break; + + case WAN_OCT6100_CMD_CLEAR_RESET: + case WAN_OCT6100_CMD_SET_RESET: + err = wan_ec_reset(ec_dev, card, ec_api->cmd); + break; + + case WAN_OCT6100_CMD_BYPASS_ENABLE: + err = wan_ec_action(card, 1, ec_api->u_ecd.channel); + break; + + case WAN_OCT6100_CMD_BYPASS_DISABLE: + err = wan_ec_action(card, 0, ec_api->u_ecd.channel); + break; + + case WAN_OCT6100_CMD_API_WRITE: + ec_api->ulResult = + wan_ec_req_write( + ec_dev, + ec_api->u_oct6100_write.ulWriteAddress, + ec_api->u_oct6100_write.usWriteData); + break; + + case WAN_OCT6100_CMD_API_WRITE_SMEAR: + ec_api->ulResult = + wan_ec_req_write_smear( + ec_dev, + ec_api->u_oct6100_write_swear.ulWriteAddress, + ec_api->u_oct6100_write_swear.usWriteData, + ec_api->u_oct6100_write_swear.ulWriteLength); + break; + + case WAN_OCT6100_CMD_API_WRITE_BURST: + ec_api->ulResult = + wan_ec_req_write_burst_prepare(ec_dev, ec_api); + break; + + case WAN_OCT6100_CMD_API_READ: + ec_api->ulResult = + wan_ec_req_read( + ec_dev, + ec_api->u_oct6100_read.ulReadAddress, + &ec_api->u_oct6100_read.usReadData); + break; + + case WAN_OCT6100_CMD_API_READ_BURST: + ec_api->ulResult = + wan_ec_req_read_burst_prepare(ec_dev, ec_api); + break; + + case WAN_OCT6100_CMD_TONE_DETECTION: + err = wan_ec_tone_detection(card, ec_api); + break; + + default: + DEBUG_EVENT("%s: Unsupported EC DEV IOCTL command for %s (%X)\n", + card->devname, ec->name, ec_api->cmd); + err = -EINVAL; + break; + } +#if 0 + aft_fe_intr_ctrl(card, 1); + card->hw_iface.hw_unlock(card->hw,&smp_flags); +#endif + +#if defined(__LINUX__) + err = WAN_COPY_TO_USER( + data, + ec_api, + sizeof(wan_ec_api_t)); + if (err){ + DEBUG_EVENT("%s: Failed to copy data to user space [%s:%d]!\n", + ec->name, + __FUNCTION__,__LINE__); + wan_free(ec_api); + return -EINVAL; + } + wan_free(ec_api); +#endif +#endif + return 0; +} diff -Nur linux.org/drivers/net/wan/sdla_ec_dev.c linux-2.6.17/drivers/net/wan/sdla_ec_dev.c --- linux.org/drivers/net/wan/sdla_ec_dev.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/drivers/net/wan/sdla_ec_dev.c 2006-08-30 10:07:16.000000000 +0000 @@ -0,0 +1,341 @@ +/***************************************************************************** +* sdla_ec_dev.c +* +* WANPIPE(tm) EC Device +* +* Authors: Nenad Corbic +* +* Copyright: (c) 2003-2006 Sangoma Technologies Inc. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version +* 2 of the License, or (at your option) any later version. +* ============================================================================ +* Jan 16, 2006 Nenad Corbic Initial version. +*****************************************************************************/ + +#include +#include +#include +#include +#include + + +#if defined(__x86_64__) +#if defined(CONFIG_COMPAT) && defined(WP_CONFIG_COMPAT) +# include +#else +# warning "Wanpipe Warning: Kernel IOCTL32 Not supported!" +# warning "Wanpipe A104D Hardware Echo Cancellation will not be supported!" +#endif +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) +# define WP_ECDEV_UDEV 1 +# undef WP_CONFIG_DEVFS_FS +#else +# undef WP_ECDEV_UDEV +# ifdef CONFIG_DEVFS_FS +# include +# define WP_CONFIG_DEVFS_FS +# else +# undef WP_CONFIG_DEVFS_FS +# warning "Error: Hardware EC Device requires DEVFS: HWEC Will not be supported!" +# endif +#endif + +#define WP_ECDEV_MAJOR 242 +#define WP_ECDEV_MINOR_OFFSET 0 + +#ifdef WP_ECDEV_UDEV + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15) +#define WP_CLASS_DEV_CREATE(class, devt, device, name) \ + class_device_create(class, NULL, devt, device, name) +#else +#define WP_CLASS_DEV_CREATE(class, devt, device, name) \ + class_device_create(class, devt, device, name) +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13) +static struct class *wp_ecdev_class = NULL; +#else +static struct class_simple *wp_ecdev_class = NULL; +#define class_create class_simple_create +#define class_destroy class_simple_destroy +#define class_device_create class_simple_device_add +#define class_device_destroy(a, b) class_simple_device_remove(b) +#endif + +#endif + +#define UNIT(file) MINOR(file->f_dentry->d_inode->i_rdev) + +#define WP_ECDEV_MAX_CHIPS 255 + +typedef struct ecdev_element { + void *ec; + int open; +#ifdef WP_CONFIG_DEVFS_FS + devfs_handle_t devfs_handle; +#endif +} ecdev_element_t; + +static ecdev_element_t wp_ecdev_hash[WP_ECDEV_MAX_CHIPS]; +static wan_spinlock_t wp_ecdev_hash_lock; +static int wp_ecdev_global_cnt=0; + + +static int wp_ecdev_open(struct inode*, struct file*); +static int wp_ecdev_release(struct inode*, struct file*); +static int wp_ecdev_ioctl(struct inode*, struct file*, unsigned int, unsigned long); +#if defined(__x86_64__) && defined(CONFIG_COMPAT) && defined(WP_CONFIG_COMPAT) +static int wp_ecdev_ioctl32(unsigned int, unsigned int, unsigned long,struct file*); +#endif + +/*============================================================== + Global Variables + */ +static struct file_operations wp_ecdev_fops = { + owner: THIS_MODULE, + llseek: NULL, + open: wp_ecdev_open, + release: wp_ecdev_release, + ioctl: wp_ecdev_ioctl, + read: NULL, + write: NULL, + poll: NULL, + mmap: NULL, + flush: NULL, + fsync: NULL, + fasync: NULL, +}; + + +static int wp_ecdev_reg_globals(void) +{ + int err; + + wan_spin_lock_init(&wp_ecdev_hash_lock); + memset(wp_ecdev_hash,0,sizeof(wp_ecdev_hash)); + + DEBUG_EVENT("%s: Registering Wanpipe ECDEV Device!\n",__FUNCTION__); +#ifdef WP_ECDEV_UDEV + wp_ecdev_class = class_create(THIS_MODULE, "wp_ec"); +#endif + +#ifdef WP_CONFIG_DEVFS_FS + err=devfs_register_chrdev(WP_ECDEV_MAJOR, "wp_ec", &wp_ecdev_fops); + if (err) { + DEBUG_EVENT("Unable to register tor device on %d\n", WP_ECDEV_MAJOR); + return err; + } +#else + if ((err = register_chrdev(WP_ECDEV_MAJOR, "wp_ec", &wp_ecdev_fops))) { + DEBUG_EVENT("Unable to register tor device on %d\n", WP_ECDEV_MAJOR); + return err; + } +#endif + +#if defined(__x86_64__) && defined(CONFIG_COMPAT) && defined(WP_CONFIG_COMPAT) + register_ioctl32_conversion(WAN_OCT6100_CMD_GET_INFO, wp_ecdev_ioctl32); + register_ioctl32_conversion(WAN_OCT6100_CMD_SET_INFO, wp_ecdev_ioctl32); + register_ioctl32_conversion(WAN_OCT6100_CMD_CLEAR_RESET, wp_ecdev_ioctl32); + register_ioctl32_conversion(WAN_OCT6100_CMD_SET_RESET, wp_ecdev_ioctl32); + register_ioctl32_conversion(WAN_OCT6100_CMD_BYPASS_ENABLE, wp_ecdev_ioctl32); + register_ioctl32_conversion(WAN_OCT6100_CMD_BYPASS_DISABLE, wp_ecdev_ioctl32); + register_ioctl32_conversion(WAN_OCT6100_CMD_API_WRITE, wp_ecdev_ioctl32); + register_ioctl32_conversion(WAN_OCT6100_CMD_API_WRITE_SMEAR, wp_ecdev_ioctl32); + register_ioctl32_conversion(WAN_OCT6100_CMD_API_WRITE_BURST, wp_ecdev_ioctl32); + register_ioctl32_conversion(WAN_OCT6100_CMD_API_READ, wp_ecdev_ioctl32); + register_ioctl32_conversion(WAN_OCT6100_CMD_API_READ_BURST, wp_ecdev_ioctl32); +#endif + return err; +} + +static int wp_ecdev_unreg_globals(void) +{ + DEBUG_EVENT("%s: Unregistering Wanpipe ECDEV Device!\n",__FUNCTION__); +#if defined(__x86_64__) && defined(CONFIG_COMPAT) && defined(WP_CONFIG_COMPAT) + unregister_ioctl32_conversion(WAN_OCT6100_CMD_GET_INFO); + unregister_ioctl32_conversion(WAN_OCT6100_CMD_SET_INFO); + unregister_ioctl32_conversion(WAN_OCT6100_CMD_CLEAR_RESET); + unregister_ioctl32_conversion(WAN_OCT6100_CMD_SET_RESET); + unregister_ioctl32_conversion(WAN_OCT6100_CMD_BYPASS_ENABLE); + unregister_ioctl32_conversion(WAN_OCT6100_CMD_BYPASS_DISABLE); + unregister_ioctl32_conversion(WAN_OCT6100_CMD_API_WRITE); + unregister_ioctl32_conversion(WAN_OCT6100_CMD_API_WRITE_SMEAR); + unregister_ioctl32_conversion(WAN_OCT6100_CMD_API_WRITE_BURST); + unregister_ioctl32_conversion(WAN_OCT6100_CMD_API_READ); + unregister_ioctl32_conversion(WAN_OCT6100_CMD_API_READ_BURST); +#endif + +#ifdef WP_ECDEV_UDEV + class_destroy(wp_ecdev_class); +#endif + +#ifdef WP_CONFIG_DEVFS_FS + devfs_unregister_chrdev(WP_ECDEV_MAJOR, "wp_ec"); +#else + unregister_chrdev(WP_ECDEV_MAJOR, "wp_ec"); +#endif + return 0; +} + +int wanpipe_ecdev_reg(void *ec, char *ec_name, int ec_chip_no) +{ + + if (wp_ecdev_global_cnt == 0){ + wp_ecdev_reg_globals(); + } + wp_ecdev_global_cnt++; + + if (ec_chip_no > WP_ECDEV_MAX_CHIPS){ + return -EINVAL; + } + + if (wp_ecdev_hash[ec_chip_no].ec){ + wp_ecdev_global_cnt--; + if (wp_ecdev_global_cnt == 0){ + wp_ecdev_unreg_globals(); + } + return -EBUSY; + } + + wp_ecdev_hash[ec_chip_no].ec=ec; + wp_ecdev_hash[ec_chip_no].open=0; + +#ifdef WP_ECDEV_UDEV + WP_CLASS_DEV_CREATE( wp_ecdev_class, + MKDEV(WP_ECDEV_MAJOR, ec_chip_no), + NULL, + ec_name); +#endif + +#ifdef WP_CONFIG_DEVFS_FS + { + umode_t mode = S_IFCHR|S_IRUGO|S_IWUGO; + wp_ecdev_hash[ec_chip_no].devfs_handle = + devfs_register(NULL, ec_name, DEVFS_FL_DEFAULT, WP_ECDEV_MAJOR, + ec_chip_no, mode, &wp_ecdev_fops, NULL); + } +#endif + + return 0; +} + +int wanpipe_ecdev_unreg(int ec_chip_no) +{ + + if (ec_chip_no > WP_ECDEV_MAX_CHIPS){ + return -EINVAL; + } + + if (wp_ecdev_hash[ec_chip_no].ec){ + wp_ecdev_hash[ec_chip_no].ec=NULL; + } + wan_clear_bit(0,&wp_ecdev_hash[ec_chip_no].open); + +#ifdef WP_ECDEV_UDEV + class_device_destroy( wp_ecdev_class, + MKDEV(WP_ECDEV_MAJOR, + ec_chip_no)); +#endif + +#ifdef WP_CONFIG_DEVFS_FS + devfs_unregister(wp_ecdev_hash[ec_chip_no].devfs_handle); +#endif + + wp_ecdev_global_cnt--; + if (wp_ecdev_global_cnt == 0){ + wp_ecdev_unreg_globals(); + } + + return 0; +} + +static int wp_ecdev_open(struct inode *inode, struct file *file) +{ + wan_smp_flag_t flags; + void *ec; + u32 minor = UNIT(file); + + DEBUG_TEST ("%s: GOT Index %i\n",__FUNCTION__, minor); + + if (minor > WP_ECDEV_MAX_CHIPS){ + return -EINVAL; + } + + wan_spin_lock_irq(&wp_ecdev_hash_lock,&flags); + if (wan_test_and_set_bit(0,&wp_ecdev_hash[minor].open)){ + wan_spin_unlock_irq(&wp_ecdev_hash_lock,&flags); + return -EBUSY; + } + ec=wp_ecdev_hash[minor].ec; + wan_spin_unlock_irq(&wp_ecdev_hash_lock,&flags); + + + file->private_data = ec; + + DEBUG_TEST ("%s: DRIVER OPEN Chip %i %p\n", + __FUNCTION__, minor, ec); + + return 0; +} + + +static int wp_ecdev_release(struct inode *inode, struct file *file) +{ + wan_smp_flag_t flags; + void *ec = file->private_data; + u32 minor = UNIT(file); + + DEBUG_EVENT ("%s: GOT Chip=%i Ptr=%p\n", + __FUNCTION__, minor, ec); + + if (ec == NULL){ + return -ENODEV; + } + + + wan_spin_lock_irq(&wp_ecdev_hash_lock,&flags); + wan_clear_bit(0,&wp_ecdev_hash[minor].open); + wan_spin_unlock_irq(&wp_ecdev_hash_lock,&flags); + + file->private_data=NULL; + return 0; +} + +extern int wan_ec_dev_ioctl(void*, void*); +static int wp_ecdev_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long data) +{ + void *ec = file->private_data; + + if (ec == NULL){ + return -ENODEV; + } + if (data == 0){ + return -EINVAL; + } + + return wan_ec_dev_ioctl(ec,(void*)data); +} + +#if defined(__x86_64__) && defined(CONFIG_COMPAT) && defined(WP_CONFIG_COMPAT) +static int +wp_ecdev_ioctl32(unsigned int fd, unsigned int cmd, unsigned long data, struct file *file) +{ + void *ec = file->private_data; + + if (ec == NULL){ + return -ENODEV; + } + if (data == 0){ + return -EINVAL; + } + + return wan_ec_dev_ioctl(ec,(void*)data); +} +#endif diff -Nur linux.org/drivers/net/wan/sdla_edac.c linux-2.6.17/drivers/net/wan/sdla_edac.c --- linux.org/drivers/net/wan/sdla_edac.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/drivers/net/wan/sdla_edac.c 2006-08-30 10:07:16.000000000 +0000 @@ -0,0 +1,102 @@ +/*************************************************************************** + * sdla_edac.c WANPIPE(tm) Multiprotocol WAN Link Driver. + * Implementation of EchoMaster algorithm. + * + * Author: David Rokhvarg + * + * Copyright: (c) 1995-2005 Sangoma Technologies Inc. + * + * ============================================================================ + * Jul 07, 2005 David Rokhvarg Initial version. + * Jul 26, 2005 David Rokhvarg V1.00 + * Added ALAW support. + ****************************************************************************** + */ + +/* + ****************************************************************************** + INCLUDE FILES + ****************************************************************************** +*/ + +#if (defined __FreeBSD__) | (defined __OpenBSD__) +# include +# include +# include +# include +# include +# include +# include /* WANPIPE TDM Voice definitions */ +# include +# include + +#elif (defined __WINDOWS__) +# include +#else + +#if 0 +# define CONFIG_ZAPATA_BRI_DCHANS +#endif + +# include +# include +# include +# include /* WANPIPE TDM Voice definitions */ +# include +# include +#endif + +/* + ****************************************************************************** + DEFINES AND MACROS + ****************************************************************************** +*/ +#define DEBUG_ECHO if(0) DEBUG_EVENT + + +/****************************************************************************** +** wp_tdmv_echo_check() - check the channel for echo +** +*/ +int wp_tdmv_echo_check(wan_tdmv_t *wan_tdmv, void *current_ztchan, int channo) +{ + struct zt_chan *thechan = (struct zt_chan *)current_ztchan; + wan_tdmv_rxtx_pwr_t *pwr_rxtx = &wan_tdmv->chan_pwr[channo]; + + if(thechan->echo_detect_struct.echo_detection_state != + thechan->echo_detect_struct.echo_detection_state_old){ + + DEBUG_ECHO("%s(): chan:%d, new ed_state: %d\n", __FUNCTION__, channo, + thechan->echo_detect_struct.echo_detection_state); + + /* there was a state change */ + switch(thechan->echo_detect_struct.echo_detection_state) + { + case ECHO_DETECT_ON: + case ECHO_DETECT_OFF: + init_ed_state(pwr_rxtx, channo); + thechan->echo_detect_struct.echo_detection_state_old = + thechan->echo_detect_struct.echo_detection_state; + break; + default: + DEBUG_EVENT("%s(): channo:%d: Invalid echo_detection_state: %d\n", __FUNCTION__, + channo, thechan->echo_detect_struct.echo_detection_state); + return 1; + } + } + + if(thechan->echo_detect_struct.echo_detection_state != ECHO_DETECT_ON){ + return 0; + } + + /* As soon is Echo state is known, do NOT run the ED algorithm. */ + if(pwr_rxtx->current_state != INDETERMINATE){ + return 0; + } + + wp_tdmv_calc_echo(pwr_rxtx, (thechan->xlaw == __zt_mulaw), + channo, thechan->readchunk, thechan->writechunk, + ZT_CHUNKSIZE); + + return 0; +} diff -Nur linux.org/drivers/net/wan/sdla_edu.c linux-2.6.17/drivers/net/wan/sdla_edu.c --- linux.org/drivers/net/wan/sdla_edu.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/drivers/net/wan/sdla_edu.c 2006-08-30 10:07:16.000000000 +0000 @@ -0,0 +1,939 @@ +/***************************************************************************** +* sdla_edu.c WANPIPE(tm) Multiprotocol WAN Link Driver. Educational kit module. +* +* Authors: David Rokhvarg +* +* +* Copyright: (c) 2001 Sangoma Technologies Inc. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version +* 2 of the License, or (at your option) any later version. +* ============================================================================ +* Sep 18, 2001 David Rokhvarg Initial version. +* +* Jul 30, 2003 David Rokhvarg v 1.0 +* 1. sdla_load() is not used anymore, +* all the loading is done from user mode instead. +* All IOCTLs used for loading are not valid anymore. +* 2. New IOCTLs added for starting and stopping +* the card. +* +* Nov 17, 2004 David Rokhvarg v 2.0 +* 1. Removed globals and put into private area +* 2. New IOCTLs added for TCP/IP handling. +* +******************************************************************************/ + +#include +#include +#include // sdla_t + +#include // for 'edu_kit.sfm' (which is actually CHDLC) firmware API definitions +#include // educational package definitions +#include // S514_CPU_START + +#include // Socket Driver common area +#include // Socket Driver common area + +/****** Defines & Macros ****************************************************/ +//#define DEBUG //define this to get output when running general IOCTLs +//#define DEBUG_RW //define this to get output when reading/writing + +/******Data Structures*****************************************************/ +typedef struct edu_private_area +{ + sdla_t* card; + unsigned char mc; /* Mulitcast support on/off */ + unsigned long update_comms_stats; /* updating comms stats */ + unsigned long router_start_time; + unsigned long interface_down; + unsigned long tick_counter; /* For 5s timeout counter */ + + u8 gateway; + u8 true_if_encoding; + + /* Entry in proc fs per each interface */ + struct proc_dir_entry* dent; + + char if_name[WAN_IFNAME_SZ+1]; + + //the one and only network interface created + netdevice_t *net_dev; + + //these 2 used to copy data from/to user mode + unsigned char data_buffer[MAX_TX_RX_DATA_SIZE]; + edu_exec_cmd_t ioctl_cmd; + + //temporary buffer for tx data. stored until 'EduKit' or + //if_tx_timeout() frees it. + TX_RX_DATA tmp_tx_data; + unsigned char tmp_tx_buff_state; //0 - free, 1 - busy + +}edu_private_area_t; + + +/******** Globals *********************************************************/ + + +/****** Function Prototypes *************************************************/ +/* WAN link driver entry points. These are called by the WAN router module. */ +static int wpedu_exec (struct sdla *card, void *u_cmd, void *u_data); + +static void DoIoctl(sdla_t *card); +static void read_block(sdla_t *card); +static void write_block(sdla_t * card); + + +/* Network device interface */ +static int if_init (netdevice_t* dev); +static int if_open (netdevice_t* dev); +static int if_close (netdevice_t* dev); +static int if_do_ioctl(netdevice_t *dev, struct ifreq *ifr, int cmd); +static struct net_device_stats* if_stats (netdevice_t* dev); +static int if_send (struct sk_buff* skb, netdevice_t* dev); +static void if_tx_timeout (netdevice_t *dev); + +static int new_if (wan_device_t* wandev, netdevice_t* dev, wanif_conf_t* conf); +static int del_if (wan_device_t* wandev, netdevice_t* dev); + +static int edu_send ( sdla_t* card, edu_private_area_t *edu_priv_area, + void* data, unsigned len, unsigned char tx_bits); + +static void handle_rx_data(sdla_t* card, TX_RX_DATA* rx_data); + +/****** Public Functions ****************************************************/ + +/*============================================================================ + * Module initialization routine. + * + * This routine is called by the main WANPIPE module during setup. At this + * point adapter is completely initialized and CHDLC firmware is running. + * o read firmware version (to make sure it's alive) + * o configure adapter + * o initialize protocol-specific fields of the adapter data space. + * + * Return: 0 o.k. + * < 0 failure. + */ +int wpedu_init (sdla_t* card, wandev_conf_t* conf) +{ + unsigned char port_num; +#ifdef DEBUG + volatile wan_mbox_t* mb; + wan_mbox_t* mb1; + + DEBUG_CFG("%s: %s\n", __FUNCTION__, card->devname); +#endif + /* Verify configuration ID */ + if (conf->config_id != WANCONFIG_EDUKIT) { + DEBUG_EVENT("%s: invalid configuration ID %u!\n", + card->devname, conf->config_id); + return -EINVAL; + } + + /* runs only on S514, check it */ + if(card->type != SDLA_S514){ + DEBUG_EVENT("%s:Invalid card type! 0x%X\n", + card->devname , card->type); + return -EFAULT; + } + + /* Use primary port */ + card->u.c.comm_port = 0; + +#ifdef DEBUG + /* Initialize protocol-specific fields */ + card->mbox_off = PRI_BASE_ADDR_MB_STRUCT; + mb = mb1 = &card->wan_mbox; +#endif + + card->isr = NULL; + card->poll = NULL; + card->exec = &wpedu_exec; + card->wandev.update = NULL; + card->wandev.new_if = &new_if; + card->wandev.del_if = &del_if; + card->wandev.state = WAN_DUALPORT; + card->wandev.udp_port = conf->udp_port; + + card->wandev.new_if_cnt = 0; + + /* This is for the ports link state */ + card->u.c.state = WAN_DISCONNECTED; + + /* reset the number of times the 'update()' proc has been called */ + card->u.c.update_call_count = 0; + + DEBUG_CFG("conf->ttl: %d\n", conf->ttl); + DEBUG_CFG("conf->mtu: %d\n", conf->mtu); + + if(conf->ttl == 0){ + card->wandev.ttl = 0x7F; + }else{ + card->wandev.ttl = conf->ttl; + } + + if(conf->mtu == 0){ + card->wandev.mtu = 1500; + }else{ + card->wandev.mtu = conf->mtu; + } + card->wandev.interface = 0; + card->wandev.clocking = 0; + + port_num = card->u.c.comm_port; + + /* Setup Port Bps */ + card->wandev.bps = 0; + + card->wandev.state = WAN_FT1_READY; + DEBUG_EVENT("%s: Educational Kit Module Ready!\n",card->devname); + + return 0; +} + +/*============================================================================ + * new_if - Create new logical channel. + * + * &wandev: Wanpipe device pointer + * &dev: Network device pointer + * &conf: User configuration options pointer + * + * This routine is called by the ROUTER_IFNEW ioctl, + * in wanmain.c. The ioctl passes us the user configuration + * options which we use to configure the driver and + * firmware. + * + * This functions main purpose is to allocate the + * private structure for CHDLC protocol and bind it + * to dev->priv pointer. + * + * Also the dev->init pointer should also be initialized + * to the if_init() function. + * + * Any allocation necessary for the private strucutre + * should be done here, as well as proc/ file initializetion + * for the network interface. + * + * o parse media- and hardware-specific configuration + * o make sure that a new channel can be created + * o allocate resources, if necessary + * o prepare network device structure for registaration. + * o add network interface to the /proc/net/wanrouter + * + * The opposite of this function is del_if() + * + * Return: 0 o.k. + * < 0 failure (channel will not be created) + */ +static int new_if (wan_device_t* wandev, netdevice_t* dev, wanif_conf_t* conf) +{ + sdla_t* card = wandev->private; + edu_private_area_t* edu_private_area; + int err = 0; + + DEBUG_CFG("%s: Configuring Card: %s, Interface: %s\n", + __FUNCTION__, card->devname, conf->name); + + if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) { + DEBUG_EVENT("%s: Invalid interface name!\n", card->devname); + return -EINVAL; + } + + /* allocate and initialize private data */ + edu_private_area = kmalloc(sizeof(edu_private_area_t), GFP_KERNEL); + + if(edu_private_area == NULL){ + WAN_MEM_ASSERT(card->devname); + return -ENOMEM; + } + + memset(edu_private_area, 0, sizeof(edu_private_area_t)); + + edu_private_area->card = card; + strcpy(edu_private_area->if_name, conf->name); + //edukit always has only one interface, re-use 'tty_buf' + //to keep the pointer to the private area. + card->tty_buf = (unsigned char*)edu_private_area; + + if (atomic_read(&card->wandev.if_cnt) > 0){ + err=-EEXIST; + goto new_if_error; + } + + /* Setup wanpipe as a router (WANPIPE) or as an API */ + if( strcmp(conf->usedby, "WANPIPE") == 0) { + DEBUG_EVENT("%s: Running in WANPIPE mode!\n", wandev->name); + }else if( strcmp(conf->usedby, "API") == 0) { + DEBUG_EVENT("%s: Running in API mode!\n", wandev->name); + }else{ + DEBUG_EVENT("%s:%s: Error: Invalid operation mode should be one of: [WANPIPE|API]\n", + card->devname,edu_private_area->if_name); + err=-EINVAL; + goto new_if_error; + } + + /* + * Create interface file in proc fs. + * Once the proc file system is created, the new_if() function + * should exit successfuly. + * + * DO NOT place code under this function that can return + * anything else but 0. + */ + err = wanrouter_proc_add_interface(wandev, + &edu_private_area->dent, + edu_private_area->if_name, + dev); + if (err){ + DEBUG_EVENT("%s: can't create /proc/net/router/edu/%s entry!\n", + card->devname, edu_private_area->if_name); + goto new_if_error; + } + + /* Only setup the dev pointer once the new_if function has + * finished successfully. DO NOT place any code below that + * can return an error */ + + dev->init = &if_init; + dev->priv = edu_private_area; + edu_private_area->net_dev = dev;//pointer back to network device + + atomic_inc(&card->wandev.if_cnt); + + DEBUG_EVENT("\n"); + + return 0; + +new_if_error: + + kfree(edu_private_area); + + dev->priv=NULL; + + return err; +} + +/*============================================================================ + * del_if - Delete logical channel. + * + * @wandev: Wanpipe private device pointer + * @dev: Netowrk interface pointer + * + * This function is called by ROUTER_DELIF ioctl call + * to deallocate the network interface. + * + * The network interface and the private structure are + * about to be deallocated by the upper layer. + * We have to clean and deallocate any allocated memory. + * + */ +static int del_if (wan_device_t* wandev, netdevice_t* dev) +{ + edu_private_area_t* edu_priv_area = dev->priv; + sdla_t* card = edu_priv_area->card; + + DEBUG_CFG("%s: deleting: %s, %s\n", __FUNCTION__, + card->devname, dev->name); + + /* Delete interface name from proc fs. */ + wanrouter_proc_delete_interface(wandev, edu_priv_area->if_name); + + atomic_dec(&card->wandev.if_cnt); + return 0; +} + +/*============================================================================ + * if_init - Initialize Linux network interface. + * + * @dev: Network interface pointer + * + * During "ifconfig up" the upper layer calls this function + * to initialize dev access pointers. Such as transmit, + * stats and header. + * + * It is called only once for each interface, + * during Linux network interface registration. + * + * Returning anything but zero will fail interface + * registration. + */ +static int if_init (netdevice_t* dev) +{ + edu_private_area_t* edu_private_area = dev->priv; + sdla_t* card = edu_private_area->card; + //wan_device_t* wandev = &card->wandev; + + DEBUG_CFG("%s: initializing %s, %s\n", __FUNCTION__, + card->devname, dev->name); + + /* Initialize device driver entry points */ + dev->open = &if_open; + dev->stop = &if_close; + dev->hard_header = NULL; + dev->rebuild_header = NULL; + dev->hard_start_xmit = &if_send; + dev->get_stats = &if_stats; +#if defined(LINUX_2_4)||defined(LINUX_2_6) + dev->tx_timeout = &if_tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; +#endif + dev->do_ioctl = if_do_ioctl; + + /* Initialize media-specific parameters */ + dev->flags |= IFF_POINTOPOINT; + dev->flags |= IFF_NOARP; + + /* Enable Mulitcasting if user selected */ + if (edu_private_area->mc == WANOPT_YES){ + dev->flags |= (IFF_MULTICAST|IFF_ALLMULTI); + } + + if (edu_private_area->true_if_encoding){ + dev->type = ARPHRD_HDLC; /* This breaks the tcpdump */ + }else{ + dev->type = ARPHRD_PPP; + } + + dev->mtu = card->wandev.mtu; + dev->hard_header_len = 0; + dev->tx_queue_len = 100; + + return 0; +} + +/*============================================================================ + * if_open - Open network interface. + * + * @dev: Network device pointer + * + * On ifconfig up, this function gets called in order + * to initialize and configure the private area. + * Driver should be configured to send and receive data. + * + * This functions starts a timer that will call + * chdlc_config() function. This function must be called + * because the IP addresses could have been changed + * for this interface. + * + * Return 0 if O.k. or errno. + */ +static int if_open (netdevice_t* dev) +{ + edu_private_area_t* edu_priv_area = dev->priv; + sdla_t* card = edu_priv_area->card; + struct timeval tv; + int err = 0; + + DEBUG_CFG("%s: opening %s, %s\n", __FUNCTION__, + card->devname, dev->name); + + /* Only one open per interface is allowed */ + if (open_dev_check(dev)){ + DEBUG_CFG("%s: if_open(): open_dev_check() failed!\n", dev->name); + return -EBUSY; + } + + do_gettimeofday(&tv); + edu_priv_area->router_start_time = tv.tv_sec; + + netif_start_queue(dev); + + /* Increment the module usage count */ + wanpipe_open(card); + + return err; +} + +/*============================================================================ + * if_close - Close network interface. + * + * @dev: Network device pointer + * + * On ifconfig down, this function gets called in order + * to cleanup interace private area. + * + * IMPORTANT: + * + * No deallocation or unconfiguration should ever occur in this + * function, because the interface can come back up + * (via ifconfig up). + * + * Furthermore, in dynamic interfacace configuration mode, the + * interface will come up and down to reflect the protocol state. + * + * Any private deallocation and cleanup can occur in del_if() + * function. That function is called before the dev interface + * itself is deallocated. + * + * Thus, we should only stop the net queue and decrement + * the wanpipe usage counter via wanpipe_close() function. + */ + +static int if_close (netdevice_t* dev) +{ + edu_private_area_t* edu_priv_area = dev->priv; + sdla_t* card = edu_priv_area->card; + + DEBUG_CFG("%s: closing %s, %s\n", __FUNCTION__, + card->devname, dev->name); + + stop_net_queue(dev); + +#if defined(LINUX_2_1) + dev->start=0; +#endif + wanpipe_close(card); + + return 0; +} + + +/** + * if_do_ioctl - Ioctl handler for fr + * @dev: Device subject to ioctl + * @ifr: Interface request block from the user + * @cmd: Command that is being issued + * + * This function handles the ioctls that may be issued by the user + * to control the settings of a FR. It does both busy + * and security checks. This function is intended to be wrapped by + * callers who wish to add additional ioctl calls of their own. + */ +/* SNMP */ +static int if_do_ioctl(netdevice_t *dev, struct ifreq *ifr, int cmd) +{ + int err=0; + + DEBUG_EVENT("%s: ioctl for: %s - Not implemented.\n", + __FUNCTION__, dev->name); + + return err; +} + +/*============================================================================ + * Get ethernet-style interface statistics. + * Return a pointer to struct enet_statistics. + */ +static struct net_device_stats* if_stats (netdevice_t* dev) +{ + sdla_t *my_card; + edu_private_area_t* edu_priv_area; + + DEBUG_CFG("%s: stats for: %s\n", __FUNCTION__, dev->name); + + if ((edu_priv_area=dev->priv) == NULL){ + return NULL; + } + + my_card = edu_priv_area->card; + return &my_card->wandev.stats; +} + +/*============================================================================ + * if_send - Send a packet on a network interface. + * + * @dev: Network interface pointer + * @skb: Packet obtained from the stack or API + * that should be sent out the port. + * + * o set tbusy flag (marks start of the transmission) to + * block a timer-based transmit from overlapping. + * o check link state. If link is not up, then drop the packet. + * o execute adapter send command. + * o free socket buffer if the send is successful, otherwise + * return non zero value and push the packet back into + * the stack. Also set the tx interrupt to wake up the + * stack when the firmware is able to send. + * + * Return: 0 complete (socket buffer must be freed) + * non-0 packet may be re-transmitted (tbusy must be set) + * + * Notes: + * 1. This routine is called either by the protocol stack or by the "net + * bottom half" (with interrupts enabled). + * 2. Setting tbusy flag will inhibit further transmit requests from the + * protocol stack and can be used for flow control with protocol layer. + */ +static int if_send (struct sk_buff* skb, netdevice_t* dev) +{ + edu_private_area_t *edu_priv_area = dev->priv; + sdla_t *card = edu_priv_area->card; + int err = 0; + unsigned char misc_Tx_bits = 0; + void* data = skb->data; + unsigned len = skb->len; + + DEBUG_TX("%s: tx called for: %s: interface %s.\n", __FUNCTION__, + card->devname, dev->name); + +#if defined(LINUX_2_4)||defined(LINUX_2_6) + netif_stop_queue(dev); +#endif + + if (skb == NULL){ + /* If we get here, some higher layer thinks we've missed an + * tx-done interrupt. + */ + DEBUG_EVENT("%s: interface %s got kicked!\n", + card->devname, dev->name); + + wake_net_dev(dev); + return 0; + } + +#if defined(LINUX_2_1) + if (dev->tbusy){ + ++card->wandev.stats.collisions; + if((jiffies - edu_priv_area->tick_counter) < (5 * HZ)) { + return 1; + } + + if_tx_timeout (dev); + } +#endif + + if(test_and_set_bit(SEND_CRIT, (void*)&card->wandev.critical)) { + + DEBUG_EVENT("%s: Critical in if_send: %lx\n", + card->wandev.name,card->wandev.critical); + ++card->wandev.stats.tx_dropped; + goto if_send_exit_crit; + } + + err = edu_send(card, edu_priv_area, data, len, misc_Tx_bits); + + if(err) { + err=-1; + }else{ +#if defined(LINUX_2_4)||defined(LINUX_2_6) + dev->trans_start = jiffies; +#endif + } + +if_send_exit_crit: + + if (err==0){ + wan_skb_free(skb); + start_net_queue(dev); + }else{ + stop_net_queue(dev); + edu_priv_area->tick_counter = jiffies; + } + + clear_bit(SEND_CRIT, (void*)&card->wandev.critical); + + return err; +} + +/*============================================================================ + * Send packet. + * Return: 0 - o.k. + * 1 - no transmit buffers available + */ +static int edu_send ( sdla_t* card, edu_private_area_t *edu_priv_area, + void* data, unsigned len, unsigned char tx_bits) +{ + unsigned char* ptr_data; + + ptr_data = (unsigned char*)data; + + DEBUG_TX("%s: called for: %s.\n", __FUNCTION__, card->devname); + + //check data length + if(len >= MAX_TX_RX_DATA_SIZE){ + DEBUG_EVENT("%s: tx data length (%u) greater than maximum (%u)!\n", + card->devname, len, MAX_TX_RX_DATA_SIZE); + return 1; + } + +#if 0 + //print out contents of the tx buffer passed from the stack + { + int i; + + for(i=0; i < len; i++){ + DEBUG_TX("data[%d]: 0x%02X\n", i, ptr_data[i]); + } + DEBUG_TX("\n"); + } +#endif + + if(edu_priv_area->tmp_tx_buff_state == 1){ + //the buffer was not freed yet by the "edukut" app. + DEBUG_TX("%s: tx buff busy!!\n", card->devname); + return 2; + } + //set to busy + edu_priv_area->tmp_tx_buff_state = 1; + //store tx data for "edukit" app + memcpy(edu_priv_area->tmp_tx_data.data, data, len); + //store tx data length + edu_priv_area->tmp_tx_data.buffer_length = len; + + return 0; +} + +/*============================================================================ + * Handle transmit timeout event from netif watchdog + */ +static void if_tx_timeout (netdevice_t *dev) +{ + edu_private_area_t* chan = dev->priv; + sdla_t *card = chan->card; + + DEBUG_TX("%s: called for: %s: interface %s.\n", __FUNCTION__, + card->devname, dev->name); + + chan->tmp_tx_buff_state = 0; + + /* If our device stays busy for at least 5 seconds then we will + * kick start the device by making dev->tbusy = 0. We expect + * that our device never stays busy more than 5 seconds. So this + * is only used as a last resort. + */ + + ++card->wandev.stats.collisions; + + DEBUG_EVENT("%s: Transmit timed out on %s\n", card->devname,dev->name); + netif_wake_queue (dev); +} + +static int wpedu_exec(sdla_t *card, void *u_cmd, void *u_data) +{ + edu_private_area_t* edu_private_area = (edu_private_area_t*)card->tty_buf; + edu_exec_cmd_t* ioctl_cmd = &edu_private_area->ioctl_cmd; + unsigned char* data_buffer = edu_private_area->data_buffer; + + //copy command area + if (copy_from_user((void*)ioctl_cmd, u_cmd, sizeof(edu_exec_cmd_t))){ + DEBUG_EVENT("copy_from_user((void*)&ioctl_cmd...) Failed!\n"); + return -EFAULT; + } + + //copy data + if (copy_from_user((void*)data_buffer, u_data, MAX_TX_RX_DATA_SIZE)){ + DEBUG_EVENT("wpedu_exec():copy_from_user((void*)data_buffer...) Failed!\n"); + return -EFAULT; + } + + DoIoctl(card); + + // return result + if( copy_to_user(u_cmd, (void*)ioctl_cmd, sizeof(edu_exec_cmd_t))){ + DEBUG_EVENT("wpedu_exec():copy_to_user(u_cmd, ...) Failed!\n"); + return -EFAULT; + } + + if( copy_to_user(u_data, (void*)data_buffer, MAX_TX_RX_DATA_SIZE)){ + DEBUG_EVENT("wpedu_exec():copy_to_user(u_data, ...) Failed!\n"); + return -EFAULT; + } + + return 0; +} + +/*============================================================================ + * Receive data handler. + */ +static void handle_rx_data(sdla_t* card, TX_RX_DATA* rx_data) +{ + netdevice_t *dev; + edu_private_area_t* edu_private_area; + struct sk_buff *skb; + void *buf; + + edu_private_area = (edu_private_area_t*)card->tty_buf; + dev = edu_private_area->net_dev; + + /* Allocate socket buffer */ + skb = dev_alloc_skb(rx_data->buffer_length + 2); + + if (skb == NULL) { + DEBUG_EVENT("%s: no socket buffers available!\n", + card->devname); + ++card->wandev.stats.rx_dropped; + goto rx_exit; + } + + /* Align IP on 16 byte */ + skb_reserve(skb, 2); + + /* Copy data to the socket buffer */ + buf = skb_put(skb, rx_data->buffer_length); + + memcpy(buf, rx_data->data, rx_data->buffer_length); + + skb->protocol = htons(ETH_P_IP); + + /* Pass it up the protocol stack */ + card->wandev.stats.rx_packets ++; + card->wandev.stats.rx_bytes += skb->len; + + skb->protocol = htons(ETH_P_IP); + skb->dev = dev; + skb->mac.raw = skb->data; + netif_rx(skb); +rx_exit: + return; +} + + +static void DoIoctl(sdla_t *card) +{ + edu_private_area_t* edu_private_area = (edu_private_area_t*)card->tty_buf; + edu_exec_cmd_t* ioctl_cmd = &edu_private_area->ioctl_cmd; + TX_RX_DATA* tx_data = (TX_RX_DATA*)edu_private_area->data_buffer; + TX_RX_DATA* rx_data = (TX_RX_DATA*)edu_private_area->data_buffer; + unsigned short adapter_type; + + switch(ioctl_cmd->ioctl) + { + case SDLA_CMD_READ_BLOCK: + DEBUG_IOCTL("SDLA_CMD_READ_BLOCK\n"); + + read_block(card); + break; + + case SDLA_CMD_WRITE_BLOCK: + DEBUG_IOCTL("SDLA_CMD_WRITE_BLOCK\n"); + + write_block(card); + break; + + case SDLA_CMD_REGISTER: + DEBUG_IOCTL("SDLA_CMD_REGISTER\n"); + + //This field will be used as a flag for determining if + //it is safe to (re)load the card. + //The flag is set to one before an application will load the card. + //No application will be able to reload the card until the flag is reset by + //SDLA_CMD_DEREGISTER. + if(card->wandev.interface == 0) + { card->wandev.interface = 1; + ioctl_cmd->return_code = 0; + }else + { //indicate failure to the caller + ioctl_cmd->return_code = 1; + } + break; + + case SDLA_CMD_DEREGISTER: + DEBUG_IOCTL("SDLA_CMD_DEREGISTER\n"); + + card->wandev.interface = 0; + ioctl_cmd->return_code = 0; + break; + + + case SDLA_CMD_START_S514: + DEBUG_IOCTL("SDLA_CMD_START_S514\n"); + + //start the CPU directly + card->hw_iface.start(card->hw, 0x100); + // ALEX writeb (S514_CPU_START, card->hw.vector); + break; + + case SDLA_CMD_STOP_S514: + DEBUG_IOCTL("SDLA_CMD_STOP_S514\n"); + + ioctl_cmd->return_code = card->hw_iface.hw_halt(card->hw); + break; + + case SDLA_CMD_IS_TX_DATA_AVAILABLE: + DEBUG_IOCTL("SDLA_CMD_IS_TX_DATA_AVAILABLE\n"); + + if(edu_private_area->tmp_tx_buff_state == 1){ + + tx_data->status = TX_SUCCESS; + + tx_data->buffer_length = edu_private_area->tmp_tx_data.buffer_length; + memcpy(tx_data->data, edu_private_area->tmp_tx_data.data, + edu_private_area->tmp_tx_data.buffer_length); + } + break; + + case SDLA_CMD_COPLETE_TX_REQUEST: + DEBUG_IOCTL("SDLA_CMD_COPLETE_TX_REQUEST\n"); + + if(edu_private_area->tmp_tx_buff_state == 1){ + DEBUG_IOCTL("tx reseting internal state...\n"); + + ++card->wandev.stats.tx_packets; + card->wandev.stats.tx_bytes += edu_private_area->tmp_tx_data.buffer_length; + edu_private_area->tmp_tx_buff_state = 0; + netif_wake_queue (edu_private_area->net_dev); + } + break; + + case SDLA_CMD_INDICATE_RX_DATA_AVAILABLE: + DEBUG_IOCTL("SDLA_CMD_INDICATE_RX_DATA_AVAILABLE\n"); + + handle_rx_data(card, rx_data); + break; + + case SDLA_CMD_GET_PCI_ADAPTER_TYPE: + DEBUG_IOCTL("SDLA_CMD_GET_PCI_ADAPTER_TYPE\n"); + + card->hw_iface.getcfg(card->hw, SDLA_ADAPTERTYPE, &adapter_type); + + DEBUG_IOCTL("adapter_type: 0x%X (%d)\n", adapter_type, adapter_type); + + if(adapter_type == S5147_ADPTR_2_CPU_T1E1){ + //for TE1 code to work adjust the card type + adapter_type = S5144_ADPTR_1_CPU_T1E1; + } + + *(unsigned short*)edu_private_area->data_buffer = adapter_type; + + DEBUG_IOCTL("Returning 0x%02X from SDLA_CMD_GET_PCI_ADAPTER_TYPE.\n", + *(unsigned short*)edu_private_area->data_buffer); + break; + + default: + DEBUG_EVENT("%s: ********* Unknown IOCTL : 0x%x *********\n", + card->devname, ioctl_cmd->ioctl); + ioctl_cmd->return_code = 1; + break; + } +} + +static void read_block(sdla_t *card) +{ + edu_private_area_t* edu_private_area = (edu_private_area_t*)card->tty_buf; + edu_exec_cmd_t* ioctl_cmd = &edu_private_area->ioctl_cmd; + unsigned char* data_buffer = edu_private_area->data_buffer; + + if(ioctl_cmd->buffer_length <= MAX_TX_RX_DATA_SIZE){ + card->hw_iface.peek(card->hw, ioctl_cmd->offset, data_buffer, ioctl_cmd->buffer_length); + ioctl_cmd->return_code = 0; + }else{ + DEBUG_EVENT("%s: SDLA_CMD_READ_BLOCK: invalid data length of %u!\n", + card->devname, + ioctl_cmd->buffer_length + ); + ioctl_cmd->return_code = 1; + } +} + +static void write_block(sdla_t * card) +{ + edu_private_area_t* edu_private_area = (edu_private_area_t*)card->tty_buf; + edu_exec_cmd_t* ioctl_cmd = &edu_private_area->ioctl_cmd; + unsigned char* data_buffer = edu_private_area->data_buffer; + + if( ioctl_cmd->buffer_length <= MAX_TX_RX_DATA_SIZE){ + card->hw_iface.poke(card->hw, ioctl_cmd->offset, data_buffer, ioctl_cmd->buffer_length); + ioctl_cmd->return_code = 0; + }else{ + DEBUG_EVENT("%s: SDLA_CMD_WRITE_BLOCK: invalid data length of %u!\n", + card->devname, + ioctl_cmd->buffer_length + ); + ioctl_cmd->return_code = 1; + } +} + + diff -Nur linux.org/drivers/net/wan/sdla_fr.c linux-2.6.17/drivers/net/wan/sdla_fr.c --- linux.org/drivers/net/wan/sdla_fr.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/drivers/net/wan/sdla_fr.c 2006-08-30 10:07:16.000000000 +0000 @@ -0,0 +1,6628 @@ +/***************************************************************************** +* sdla_fr.c WANPIPE(tm) Multiprotocol WAN Link Driver. Frame relay module. +* +* Author(s): Nenad Corbic +* Gideon Hack +* +* Copyright: (c) 1995-2003 Sangoma Technologies Inc. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version +* 2 of the License, or (at your option) any later version. +* ============================================================================ +* Apr 16, 2003 Nenad Corbic o Frame Relay Bug fix in IP offsets, due +* to header removal out of the data packet +* Jan 03, 2003 Nenad Corbic o Memory leak bug fix under Bridge Mode. +* If not an ethernet frame skb buffer was +* not deallocated. +* Aug 30, 2002 Nenad Corbic o Addes support for S5147 Dual TE1 card +* Dec 19, 2001 Nenad Corbic o Full status request bug fix. Removed the +* fr_issue_isf() firmware man not be ready for +* full status response. +* Dec 04, 2001 Nenad Corbic o Bridge bug fix: the skb mac ptr was being set to +* the skb data ptr. The ethernet header was being +* lost. +* Dec 03, 2001 Gideon Hack o Updated for S514-5 56K adatper +* Sep 20, 2001 Nenad Corbic o The min() function has changed for 2.4.9 +* kernel. Thus using the wp_min() defined in +* wanpipe.h +* Sept 6, 2001 Alex Feldman o Add SNMP support. +* Aug 27, 2001 Nenad Corbic o Added the IPX support and redesigned the +* ARP handling code. +* May 25, 2001 Alex Feldman o Added T1/E1 support (TE1). +* May 22, 2001 Nenad Corbic o Fixed the incoming invalid ARP bug. +* Nov 23, 2000 Nenad Corbic o Added support for 2.4.X kernels +* Nov 15, 2000 David Rokavarg +* Nenad Corbic o Added frame relay bridging support. +* Original code from Mark Wells and Kristian Hoffmann has +* been integrated into the frame relay driver. +* Nov 13, 2000 Nenad Corbic o Added true interface type encoding option. +* Tcpdump doesn't support Frame Relay inteface +* types, to fix this true type option will set +* the interface type to RAW IP mode. +* Nov 07, 2000 Nenad Corbic o Added security features for UDP debugging: +* Deny all and specify allowed requests. +* Nov 06, 2000 Nenad Corbic o Wanpipe interfaces conform to raw packet interfaces. +* Moved the if_header into the if_send() routine. +* The if_header() was breaking the libpcap +* support. i.e. support for tcpdump, ethereal ... +* Oct 12. 2000 Nenad Corbic o Added error message in fr_configure +* Jul 31, 2000 Nenad Corbic o Fixed the Router UP Time. +* Apr 28, 2000 Nenad Corbic o Added the option to shutdown an interface +* when the channel gets disconnected. +* Apr 28, 2000 Nenad Corbic o Added M.Grants patch: disallow duplicate +* interface setups. +* Apr 25, 2000 Nenad Corbic o Added M.Grants patch: dynamically add/remove +* new dlcis/interfaces. +* Mar 23, 2000 Nenad Corbic o Improved task queue, bh handling. +* Mar 16, 2000 Nenad Corbic o Added Inverse ARP support +* Mar 13, 2000 Nenad Corbic o Added new socket API support. +* Mar 06, 2000 Nenad Corbic o Bug Fix: corrupted mbox recovery. +* Feb 24, 2000 Nenad Corbic o Fixed up FT1 UDP debugging problem. +* Dev 15, 1999 Nenad Corbic o Fixed up header files for 2.0.X kernels +* +* Nov 08, 1999 Nenad Corbic o Combined all debug UDP calls into one function +* o Removed the ARP support. This has to be done +* in the next version. +* o Only a Node can implement NO signalling. +* Initialize DLCI during if_open() if NO +* signalling. +* o Took out IPX support, implement in next +* version +* Sep 29, 1999 Nenad Corbic o Added SMP support and changed the update +* function to use timer interrupt. +* o Fixed the CIR bug: Set the value of BC +* to CIR when the CIR is enabled. +* o Updated comments, statistics and tracing. +* Jun 02, 1999 Gideon Hack o Updated for S514 support. +* Sep 18, 1998 Jaspreet Singh o Updated for 2.2.X kernels. +* Jul 31, 1998 Jaspreet Singh o Removed wpf_poll routine. The channel/DLCI +* status is received through an event interrupt. +* Jul 08, 1998 David Fong o Added inverse ARP support. +* Mar 26, 1997 Jaspreet Singh o Returning return codes for failed UDP cmds. +* Jan 28, 1997 Jaspreet Singh o Improved handling of inactive DLCIs. +* Dec 30, 1997 Jaspreet Singh o Replaced dev_tint() with mark_bh(NET_BH) +* Dec 16, 1997 Jaspreet Singh o Implemented Multiple IPX support. +* Nov 26, 1997 Jaspreet Singh o Improved load sharing with multiple boards +* o Added Cli() to protect enabling of interrupts +* while polling is called. +* Nov 24, 1997 Jaspreet Singh o Added counters to avoid enabling of interrupts +* when they have been disabled by another +* interface or routine (eg. wpf_poll). +* Nov 06, 1997 Jaspreet Singh o Added INTR_TEST_MODE to avoid polling +* routine disable interrupts during interrupt +* testing. +* Oct 20, 1997 Jaspreet Singh o Added hooks in for Router UP time. +* Oct 16, 1997 Jaspreet Singh o The critical flag is used to maintain flow +* control by avoiding RACE conditions. The +* cli() and restore_flags() are taken out. +* The fr_channel structure is appended for +* Driver Statistics. +* Oct 15, 1997 Farhan Thawar o updated if_send() and receive for IPX +* Aug 29, 1997 Farhan Thawar o Removed most of the cli() and sti() +* o Abstracted the UDP management stuff +* o Now use tbusy and critical more intelligently +* Jul 21, 1997 Jaspreet Singh o Can configure T391, T392, N391, N392 & N393 +* through router.conf. +* o Protected calls to sdla_peek() by adDing +* save_flags(), cli() and restore_flags(). +* o Added error message for Inactive DLCIs in +* fr_event() and update_chan_state(). +* o Fixed freeing up of buffers using kfree() +* when packets are received. +* Jul 07, 1997 Jaspreet Singh o Added configurable TTL for UDP packets +* o Added ability to discard multicast and +* broadcast source addressed packets +* Jun 27, 1997 Jaspreet Singh o Added FT1 monitor capabilities +* New case (0x44) statement in if_send routine +* Added a global variable rCount to keep track +* of FT1 status enabled on the board. +* May 29, 1997 Jaspreet Singh o Fixed major Flow Control Problem +* With multiple boards a problem was seen where +* the second board always stopped transmitting +* packet after running for a while. The code +* got into a stage where the interrupts were +* disabled and dev->tbusy was set to 1. +* This caused the If_send() routine to get into +* the if clause for it(0,dev->tbusy) +* forever. +* The code got into this stage due to an +* interrupt occuring within the if clause for +* set_bit(0,dev->tbusy). Since an interrupt +* disables furhter transmit interrupt and +* makes dev->tbusy = 0, this effect was undone +* by making dev->tbusy = 1 in the if clause. +* The Fix checks to see if Transmit interrupts +* are disabled then do not make dev->tbusy = 1 +* Introduced a global variable: int_occur and +* added tx_int_enabled in the wan_device +* structure. +* May 21, 1997 Jaspreet Singh o Fixed UDP Management for multiple +* boards. +* +* Apr 25, 1997 Farhan Thawar o added UDP Management stuff +* o fixed bug in if_send() and tx_intr() to +* sleep and wakeup all devices +* Mar 11, 1997 Farhan Thawar Version 3.1.1 +* o fixed (+1) bug in fr508_rx_intr() +* o changed if_send() to return 0 if +* wandev.critical() is true +* o free socket buffer in if_send() if +* returning 0 +* o added tx_intr() routine +* Jan 30, 1997 Gene Kozin Version 3.1.0 +* o implemented exec() entry point +* o fixed a bug causing driver configured as +* a FR switch to be stuck in WAN_ +* mode +* Jan 02, 1997 Gene Kozin Initial version. +*****************************************************************************/ + +#include +#include +#include /* WANPIPE common user API definitions */ +#include +#include /* Wanpipe Socket */ +#include +#include +#include +#include /* frame relay firmware API definitions */ + +/****** Defines & Macros ****************************************************/ + +#define MAX_CMD_RETRY 10 /* max number of firmware retries */ + +#define FR_HEADER_LEN 8 /* max encapsulation header size */ +#define FR_CHANNEL_MTU 1500 /* unfragmented logical channel MTU */ + +/* Private critical flags */ +enum { + SEND_TXIRQ_CRIT = PRIV_CRIT, + ARP_CRIT +}; + +/* Q.922 frame types */ +#define Q922_UI 0x03 /* Unnumbered Info frame */ +#define Q922_XID 0xAF + +/* CISCO data frame encapsulation */ +#define CISCO_UI 0x08 +#define CISCO_IP 0x00 +#define CISCO_INV 0x20 + +/* DLCI configured or not */ +#define DLCI_NOT_CONFIGURED 0x00 +#define DLCI_CONFIG_PENDING 0x01 +#define DLCI_CONFIGURED 0x02 + +/* CIR enabled or not */ +#define CIR_ENABLED 0x00 +#define CIR_DISABLED 0x01 + +#define FRAME_RELAY_API 1 +#define MAX_BH_BUFF 10 + +/* For handle_IPXWAN() */ +#define CVHexToAscii(b) (((unsigned char)(b) > (unsigned char)9) ? ((unsigned char)'A' + ((unsigned char)(b) - (unsigned char)10)) : ((unsigned char)'0' + (unsigned char)(b))) + +/****** Data Structures *****************************************************/ + +/* This is an extention of the 'struct device' we create for each network + * interface to keep the rest of channel-specific data. + */ +typedef struct fr_channel +{ + wanpipe_common_t common; + char name[WAN_IFNAME_SZ+1]; /* interface name, ASCIIZ */ + unsigned dlci_configured ; /* check whether configured or not */ + unsigned cir_status; /* check whether CIR enabled or not */ + unsigned dlci; /* logical channel number */ + unsigned cir; /* committed information rate */ + unsigned bc; /* committed burst size */ + unsigned be; /* excess burst size */ + unsigned mc; /* multicast support on or off */ + unsigned tx_int_status; /* Transmit Interrupt Status */ + unsigned short pkt_length; /* Packet Length */ + unsigned long router_start_time;/* Router start time in seconds */ + unsigned long tick_counter; /* counter for transmit time out */ + char dev_pending_devtint; /* interface pending dev_tint() */ + unsigned long dlci_int_interface_off; /* pointer to the DLCI Interface */ + unsigned long dlci_int_off; /* offset to the DLCI Interface interrupt */ + unsigned long IB_addr; /* physical address of Interface Byte */ + unsigned long state_tick; /* time of the last state change */ + unsigned char enable_IPX; /* Enable/Disable the use of IPX */ + unsigned long network_number; /* Internal Network Number for IPX*/ + sdla_t *card; /* -> owner */ + unsigned route_flag; /* Add/Rem dest addr in route tables */ + unsigned inarp; /* Inverse Arp Request status */ + unsigned long inarp_ready; /* Ready to send requests */ + unsigned char inarp_rx; /* InArp reception support */ + int inarp_interval; /* Time between InArp Requests */ + unsigned long inarp_tick; /* InArp jiffies tick counter */ + unsigned long interface_down; /* Bring interface down on disconnect */ + struct net_device_stats ifstats; /* interface statistics */ + if_send_stat_t drvstats_if_send; + rx_intr_stat_t drvstats_rx_intr; + pipe_mgmt_stat_t drvstats_gen; + unsigned long router_up_time; + + unsigned short transmit_length; + struct sk_buff *delay_skb; + + /* Polling task queue. Each interface + * has its own task queue, which is used + * to defer events from the interrupt */ + struct tq_struct fr_poll_task; + struct timer_list fr_arp_timer; + + u32 ip_local; + u32 ip_remote; + unsigned long config_dlci; + u32 unconfig_dlci; + + /* Whether this interface should be setup as a gateway. + * Used by dynamic route setup code */ + u8 gateway; + + /* True interface type */ + u8 true_if_encoding; + u8 fr_header[FR_HEADER_LEN]; + int fr_header_len; + + /* Encapsulation varialbes, default + * is IETF, however, if we detect CISCO + * use its encapsultaion */ + u8 fr_encap_0; + u8 fr_encap_1; + + /* Pending ARP packet to be transmitted */ + struct sk_buff *tx_arp; + struct sk_buff *tx_ipx; + + /* Entry in proc fs per each interface */ + struct proc_dir_entry* dent; + unsigned long router_last_change; + unsigned int dlci_type; + unsigned long rx_DE_set; + unsigned long tx_DE_set; + unsigned long rx_FECN; + unsigned long rx_BECN; + unsigned err_type; + char err_data[SNMP_FR_ERRDATA_LEN]; + unsigned long err_time; + unsigned long err_faults; + unsigned trap_state; + unsigned long trap_max_rate; + + /* DLCI firmware status */ + unsigned char dlci_stat; +} fr_channel_t; + +/* Route Flag options */ +#define NO_ROUTE 0x00 +#define ADD_ROUTE 0x01 +#define ROUTE_ADDED 0x02 +#define REMOVE_ROUTE 0x03 +#define ARP_REQ 0x04 + +/* inarp options */ +#define INARP_NONE 0x00 +#define INARP_REQUEST 0x01 +#define INARP_CONFIGURED 0x02 + +/* reasons for enabling the timer interrupt on the adapter */ +#define TMR_INT_ENABLED_UDP 0x01 +#define TMR_INT_ENABLED_UPDATE 0x02 +#define TMR_INT_ENABLED_ARP 0x04 +#define TMR_INT_ENABLED_UPDATE_STATE 0x08 +#define TMR_INT_ENABLED_UPDATE_DLCI 0x40 +#define TMR_INT_ENABLED_TE 0x80 + + +typedef struct dlci_status +{ + unsigned short dlci PACKED; + unsigned char state PACKED; +} dlci_status_t; + +typedef struct dlci_IB_mapping +{ + unsigned short dlci PACKED; + unsigned long addr_value PACKED; +} dlci_IB_mapping_t; + +/* This structure is used for DLCI list Tx interrupt mode. It is used to + enable interrupt bit and set the packet length for transmission + */ +typedef struct fr_dlci_interface +{ + unsigned char gen_interrupt PACKED; + unsigned short packet_length PACKED; + unsigned char reserved PACKED; +} fr_dlci_interface_t; + +extern void disable_irq(unsigned int); +extern void enable_irq(unsigned int); + +/****** Function Prototypes *************************************************/ + +/* WAN link driver entry points. These are called by the WAN router module. */ +static int update(wan_device_t *wandev); +static int new_if(wan_device_t *wandev, netdevice_t *dev, wanif_conf_t *conf); +static int del_if(wan_device_t *wandev, netdevice_t *dev); +static void disable_comm (sdla_t *card); + +/* Network device interface */ +static int if_init(netdevice_t *dev); +static int if_open(netdevice_t *dev); +static int if_close(netdevice_t *dev); +static int if_do_ioctl(netdevice_t *dev, struct ifreq *ifr, int cmd); + +static void if_tx_timeout (netdevice_t *dev); + +static int if_send(struct sk_buff *skb, netdevice_t *dev); +static int chk_bcast_mcast_addr(sdla_t *card, netdevice_t* dev, + struct sk_buff *skb); +static struct net_device_stats *if_stats(netdevice_t *dev); + + +/* Interrupt handlers */ +static void fr_isr(sdla_t *card); +static void rx_intr(sdla_t *card); +static void tx_intr(sdla_t *card); +static void timer_intr(sdla_t *card); +static void spur_intr(sdla_t *card); + +/* Frame relay firmware interface functions */ +static int fr_read_version(sdla_t *card, char *str); +static int fr_configure(sdla_t *card, fr_conf_t *conf); +static int fr_dlci_configure(sdla_t *card, fr_dlc_conf_t *conf, unsigned dlci); +static int fr_init_dlci (sdla_t *card, fr_channel_t *chan); +static int fr_set_intr_mode (sdla_t *card, unsigned mode, unsigned mtu, unsigned short timeout); +static int fr_comm_enable(sdla_t *card); +static void fr_comm_disable(sdla_t *card); +static int fr_get_err_stats(sdla_t *card); +static int fr_get_stats(sdla_t *card, fr_channel_t* chan); +static int fr_add_dlci(sdla_t *card, int dlci); +static int fr_activate_dlci(sdla_t *card, int dlci); +static int fr_delete_dlci (sdla_t* card, int dlci); +static int fr_send(sdla_t *card, int dlci, unsigned char attr, int len, + void *buf); +static int fr_send_data_header(sdla_t *card, int dlci, unsigned char attr, int len, + void *buf,unsigned char hdr_len, char lock); +static unsigned int fr_send_hdr(sdla_t *card, int dlci, unsigned int offset); +static int fr_issue_isf (sdla_t* card, int isf); + +static int check_dlci_config (sdla_t *card, fr_channel_t *chan); +static void initialize_rx_tx_buffers (sdla_t *card); + + +/* Firmware asynchronous event handlers */ +static int fr_event(sdla_t *card, int event, wan_mbox_t *mb); +static int fr_modem_failure(sdla_t *card, wan_mbox_t *mb); +static int fr_dlci_change(sdla_t *card, wan_mbox_t *mb, int mbox_offset); + +/* Miscellaneous functions */ +static int update_chan_state(netdevice_t *dev); +static void set_chan_state(netdevice_t *dev, int state); +static netdevice_t *find_channel(sdla_t *card, unsigned dlci); +static int is_tx_ready(sdla_t *card, fr_channel_t *chan); +static unsigned int dec_to_uint(unsigned char *str, int len); +static int reply_udp( unsigned char *data, unsigned int mbox_len ); + +static int intr_test( sdla_t* card ); +static void init_chan_statistics( fr_channel_t* chan ); +static void init_global_statistics( sdla_t* card ); +static void read_DLCI_IB_mapping( sdla_t* card, fr_channel_t* chan ); +static int setup_for_delayed_transmit(netdevice_t* dev, struct sk_buff *skb); + +netdevice_t * move_dev_to_next (sdla_t *, netdevice_t *); +static int check_tx_status(sdla_t *, netdevice_t *); + +/* Frame Relay Socket API */ +static void fr_bh (unsigned long data); + +static void trigger_fr_poll (netdevice_t *); +static void fr_poll (void *); + +static void unconfig_fr_dev (sdla_t *card, netdevice_t *dev); + + +static void config_fr_dev (sdla_t *card,netdevice_t *dev); +static int set_adapter_config (sdla_t* card); + + +/* Inverse ARP and Dynamic routing functions */ +int process_ARP(arphdr_1490_t *ArpPacket, sdla_t *card, netdevice_t *dev); +int is_arp(void *buf); +int send_inarp_request(sdla_t *card, netdevice_t *dev); + +static void trigger_fr_arp (netdevice_t *); +static void fr_arp (unsigned long data); + + +/* Udp management functions */ +static int process_udp_mgmt_pkt(sdla_t *card, void *local_dev); +static int udp_pkt_type( struct sk_buff *skb, sdla_t *card, int); +static int store_udp_mgmt_pkt(int udp_type, char udp_pkt_src, sdla_t* card, + struct sk_buff *skb, int dlci); + +/* IPX functions */ +static void switch_net_numbers(unsigned char *sendpacket, + unsigned long network_number, unsigned char incoming); + +static int handle_IPXWAN(unsigned char *sendpacket, char *devname, + unsigned char enable_IPX, unsigned long network_number); + +/* Lock Functions: SMP supported */ +void s508_s514_unlock(sdla_t *card, unsigned long *smp_flags); +void s508_s514_lock(sdla_t *card, unsigned long *smp_flags); +void s508_s514_send_event_lock(sdla_t *card, unsigned long *smp_flags); +void s508_s514_send_event_unlock(sdla_t *card, unsigned long *smp_flags); + + + +static unsigned short calc_checksum (char *, int); +static int setup_fr_header(struct sk_buff** skb, netdevice_t* dev, char op_mode); + +static int fr_get_config_info(void* priv, struct seq_file* m, int*); +static int fr_get_status_info(void* priv, struct seq_file* m, int*); +static int fr_set_dev_config(struct file*, const char*, unsigned long, void *); +static int fr_set_if_info(struct file*, const char*, unsigned long, void *); + +static WRITE_FRONT_END_REG_T write_front_end_reg; +static READ_FRONT_END_REG_T read_front_end_reg; +static void fr_enable_timer(void* card_id); +static void fr_handle_front_end_state (void* card_id); + +/* SNMP */ +static int fr_snmp_data(sdla_t* card, netdevice_t *dev, void* data); + +/* Debugging */ +static int fr_debugging(sdla_t* card); +static unsigned long fr_crc_frames(sdla_t* card); +static unsigned long fr_abort_frames(sdla_t * card); +static unsigned long fr_tx_underun_frames(sdla_t* card); + +/****** Public Functions ****************************************************/ + +/*============================================================================ + * wpf_init - Frame relay protocol initialization routine. + * + * @card: Wanpipe card pointer + * @conf: User hardware/firmware/general protocol configuration + * pointer. + * + * This routine is called by the main WANPIPE module + * during setup: ROUTER_SETUP ioctl(). + * + * + * At this point adapter is completely initialized and + * firmware is running. + * o read firmware version (to make sure it's alive) + * o configure adapter + * o initialize protocol-specific fields of the adapter data space. + * + * Return: 0 o.k. + * < 0 failure. + */ +int wpf_init(sdla_t *card, wandev_conf_t *conf) +{ + + int err; + fr_buf_info_t buf_info; + unsigned long buf_info_off; + + union + { + char str[80]; + fr_conf_t cfg; + } u; + + int i; + + + printk(KERN_INFO "\n"); + + /* Verify configuration ID */ + if (conf->config_id != WANCONFIG_FR) { + + printk(KERN_INFO "%s: invalid configuration ID %u!\n", + card->devname, conf->config_id); + return -EINVAL; + + } + + /* Initialize protocol-specific fields of adapter data space */ + /* Alex Apr 8 2004 Sangoma ISA card */ + card->mbox_off = FR_MB_VECTOR + FR508_MBOX_OFFS; + card->flags_off = FR_MB_VECTOR + FR508_FLAG_OFFS; + + card->isr = &fr_isr; + + card->intr_type_off = + card->flags_off + + offsetof(fr508_flags_t, iflag); + card->intr_perm_off = + card->flags_off + + offsetof(fr508_flags_t, imask); + + card->wandev.ignore_front_end_status = conf->ignore_front_end_status; + + //ALEX_TODAY err=check_conf_hw_mismatch(card,conf->te_cfg.media); + err = (card->hw_iface.check_mismatch) ? + card->hw_iface.check_mismatch(card->hw,conf->fe_cfg.media) : -EINVAL; + if (err){ + return err; + } + + /* Determine the board type user is trying to configure + * and make sure that the HW matches */ + if (IS_TE1_MEDIA(&conf->fe_cfg)) { + + memcpy(&card->fe.fe_cfg, &conf->fe_cfg, sizeof(sdla_fe_cfg_t)); + sdla_te_iface_init(&card->wandev.fe_iface); + card->fe.name = card->devname; + card->fe.card = card; + card->fe.write_fe_reg = write_front_end_reg; + card->fe.read_fe_reg = read_front_end_reg; + + card->wandev.fe_enable_timer = fr_enable_timer; + card->wandev.te_link_state = fr_handle_front_end_state; + conf->interface = + (IS_T1_FEMEDIA(&card->fe)) ? WANOPT_V35 : WANOPT_RS232; + conf->clocking = WANOPT_EXTERNAL; + + }else if (IS_56K_MEDIA(&conf->fe_cfg)) { + + memcpy(&card->fe.fe_cfg, &conf->fe_cfg, sizeof(sdla_fe_cfg_t)); + sdla_56k_iface_init(&card->wandev.fe_iface); + card->fe.name = card->devname; + card->fe.card = card; + card->fe.write_fe_reg = write_front_end_reg; + card->fe.read_fe_reg = read_front_end_reg; + + }else{ + + card->fe.fe_status = FE_CONNECTED; + + /* Current frame relay firmware doesn't support + * this for S508 and S514 1-2-3 cards */ + card->wandev.ignore_front_end_status = WANOPT_YES; + } + + if (card->wandev.ignore_front_end_status == WANOPT_NO){ + printk(KERN_INFO + "%s: Enabling front end link monitor\n", + card->devname); + }else{ + printk(KERN_INFO + "%s: Disabling front end link monitor\n", + card->devname); + } + + + /* Read firmware version. Note that when adapter initializes, it + * clears the mailbox, so it may appear that the first command was + * executed successfully when in fact it was merely erased. To work + * around this, we execute the first command twice. + */ + + if (fr_read_version(card, NULL) || fr_read_version(card, u.str)){ + return -EIO; + } + + printk(KERN_INFO "%s: running frame relay firmware v%s\n", + card->devname, u.str); + + + if (set_adapter_config(card)) { + return -EIO; + } + + + /* Adjust configuration */ + conf->mtu += FR_HEADER_LEN; + conf->mtu = (conf->mtu >= MIN_LGTH_FR_DATA_CFG) ? + wp_min(conf->mtu, FR_MAX_NO_DATA_BYTES_IN_FRAME) : + FR_CHANNEL_MTU + FR_HEADER_LEN; + + conf->bps = wp_min(conf->bps, 2048000); + + /* Initialze the configuration structure sent to the board to zero */ + memset(&u.cfg, 0, sizeof(u.cfg)); + + memset(card->u.f.dlci_to_dev_map, 0, sizeof(card->u.f.dlci_to_dev_map)); + + /* Configure adapter firmware */ + + u.cfg.mtu = conf->mtu; + u.cfg.kbps = conf->bps / 1000; + + u.cfg.cir_fwd = u.cfg.cir_bwd = 16; + u.cfg.bc_fwd = u.cfg.bc_bwd = 16; + + u.cfg.options = 0x0000; + printk(KERN_INFO "%s: Global CIR enabled by Default\n", card->devname); + + switch (conf->u.fr.signalling) { + + case WANOPT_FR_ANSI: + u.cfg.options = 0x0000; + break; + + case WANOPT_FR_Q933: + u.cfg.options |= 0x0200; + break; + + case WANOPT_FR_LMI: + u.cfg.options |= 0x0400; + break; + + case WANOPT_NO: + u.cfg.options |= 0x0800; + break; + default: + printk(KERN_INFO "%s: Illegal Signalling option\n", + card->wandev.name); + return -EINVAL; + } + + + card->wandev.signalling = conf->u.fr.signalling; + + if (conf->u.fr.station == WANOPT_CPE) { + + + if (conf->u.fr.signalling == WANOPT_NO){ + printk(KERN_INFO + "%s: ERROR - For NO signalling, station must be set to Node!", + card->devname); + return -EINVAL; + } + + u.cfg.station = 0; + u.cfg.options |= 0x8000; /* auto config DLCI */ + card->u.f.dlci_num = 0; + + } else { + + u.cfg.station = 1; /* switch emulation mode */ + + /* For switch emulation we have to create a list of dlci(s) + * that will be sent to be global SET_DLCI_CONFIGURATION + * command in fr_configure() routine. + */ + + card->u.f.dlci_num = wp_min(wp_max(conf->u.fr.dlci_num, 1), 100); + + for ( i = 0; i < card->u.f.dlci_num; i++) { + + card->u.f.node_dlci[i] = (unsigned short) + conf->u.fr.dlci[i] ? conf->u.fr.dlci[i] : 16; + + } + } + + if (conf->clocking == WANOPT_INTERNAL) + u.cfg.port |= 0x0001; + + if (conf->interface == WANOPT_RS232) + u.cfg.port |= 0x0002; + + if (conf->u.fr.t391) + u.cfg.t391 = wp_min(conf->u.fr.t391, 30); + else + u.cfg.t391 = 5; + card->u.f.t391 = u.cfg.t391; + + if (conf->u.fr.t392) + u.cfg.t392 = wp_min(conf->u.fr.t392, 30); + else + u.cfg.t392 = 15; + card->u.f.t392 = u.cfg.t392; + + if (conf->u.fr.n391) + u.cfg.n391 = wp_min(conf->u.fr.n391, 255); + else + u.cfg.n391 = 2; + card->u.f.n391 = u.cfg.n391; + + if (conf->u.fr.n392) + u.cfg.n392 = wp_min(conf->u.fr.n392, 10); + else + u.cfg.n392 = 3; + card->u.f.n392 = u.cfg.n392; + + if (conf->u.fr.n393) + u.cfg.n393 = wp_min(conf->u.fr.n393, 10); + else + u.cfg.n393 = 4; + card->u.f.n393 = u.cfg.n393; + + if (fr_configure(card, &u.cfg)) + return -EIO; + + /* Alex Apr 8 2004 Sangoma ISA card (the same code as for PCI) */ + buf_info_off = FR_MB_VECTOR + FR508_RXBC_OFFS; + card->hw_iface.peek(card->hw, buf_info_off, (unsigned char*)&buf_info, sizeof(buf_info)); + + card->rxmb_off = buf_info.rse_next; + card->u.f.rxmb_base_off = buf_info.rse_base; + card->u.f.rxmb_last_off = + buf_info.rse_base + + (buf_info.rse_num - 1) * sizeof(fr_rx_buf_ctl_t); + + card->u.f.rx_base_off = buf_info.buf_base; + card->u.f.rx_top_off = buf_info.buf_top; + atomic_set(&card->u.f.tx_interrupts_pending,0); + + card->wandev.mtu = conf->mtu; + card->wandev.bps = conf->bps; + card->wandev.interface = conf->interface; + card->wandev.clocking = conf->clocking; + card->wandev.station = conf->u.fr.station; + card->poll = NULL; + card->exec = NULL; + card->wandev.update = &update; + card->wandev.new_if = &new_if; + card->wandev.del_if = &del_if; + + // Proc fs functions + card->wandev.get_config_info = &fr_get_config_info; + card->wandev.get_status_info = &fr_get_status_info; + card->wandev.set_dev_config = &fr_set_dev_config; + card->wandev.set_if_info = &fr_set_if_info; + + /* Debugging */ + card->wan_debugging = &fr_debugging; + card->get_crc_frames = &fr_crc_frames; + card->get_abort_frames = &fr_abort_frames; + card->get_tx_underun_frames = &fr_tx_underun_frames; + + card->wandev.state = WAN_DISCONNECTED; + card->wandev.ttl = conf->ttl; + card->wandev.udp_port = conf->udp_port; + card->disable_comm = &disable_comm; + card->u.f.arp_dev = NULL; + + /* SNMP data */ + card->get_snmp_data = &fr_snmp_data; + + /* Intialize global statistics for a card */ + init_global_statistics( card ); + + card->TracingEnabled = 0; + + /* Interrupt Test */ + card->timer_int_enabled = 0; + card->intr_mode = INTR_TEST_MODE; + err = intr_test(card); + + printk(KERN_INFO "%s: End of Interrupt Test rc=0x%x count=%i\n", + card->devname,err,card->timer_int_enabled); + + if (err || (card->timer_int_enabled < MAX_INTR_TEST_COUNTER)) { + printk(KERN_INFO "%s: Interrupt Test Failed, Counter: %i\n", + card->devname, card->timer_int_enabled); + printk(KERN_INFO "%s: Please choose another interrupt\n", + card->devname); + return -EIO; + } + + printk(KERN_INFO "%s: Interrupt Test Passed, Counter: %i\n", + card->devname, card->timer_int_enabled); + + card->u.f.issue_fs_on_startup = conf->u.fr.issue_fs_on_startup; + if (card->u.f.issue_fs_on_startup){ + printk(KERN_INFO "%s: Configured for full status on startup\n", + card->devname); + }else{ + printk(KERN_INFO "%s: Disabled full status on startup\n", + card->devname); + } + + /* Configure the front end. + * If the onboard CSU/DSU exists, configure via + * user defined options */ + if (IS_TE1_CARD(card)) { + int err = -EINVAL; + printk(KERN_INFO "%s: Configuring onboard %s CSU/DSU\n", + card->devname, + (IS_T1_CARD(card))?"T1":"E1"); + if (card->wandev.fe_iface.config){ + err = card->wandev.fe_iface.config(&card->fe); + } + if (err){ + printk(KERN_INFO "%s: Failed %s configuratoin!\n", + card->devname, + (IS_T1_CARD(card))?"T1":"E1"); + return -EIO; + } + + }else if (IS_56K_CARD(card)) { + int err = -EINVAL; + printk(KERN_INFO "%s: Configuring 56K onboard CSU/DSU\n", + card->devname); + + if (card->wandev.fe_iface.config){ + err = card->wandev.fe_iface.config(&card->fe); + } + if (err){ + printk (KERN_INFO "%s: Failed 56K configuration!\n", + card->devname); + return -EIO; + } + } + + + /* Apr 28 2000. Nenad Corbic + * Enable commnunications here, not in if_open or new_if, since + * interfaces come down when the link is disconnected. + */ + + /* If you enable comms and then set ints, you get a Tx int as you + * perform the SET_INT_TRIGGERS command. So, we only set int + * triggers and then adjust the interrupt mask (to disable Tx ints) + * before enabling comms. + */ + if (fr_set_intr_mode(card, (FR_INTR_RXRDY | FR_INTR_TXRDY | + FR_INTR_DLC | FR_INTR_TIMER | FR_INTR_TX_MULT_DLCIs | FR_INTR_MODEM) , + card->wandev.mtu, 0)) { + return -EIO; + } + + /* Mask - Disable all interrupts */ + card->hw_iface.clear_bit(card->hw, card->intr_perm_off, + (FR_INTR_RXRDY | FR_INTR_TXRDY | FR_INTR_DLC | + FR_INTR_TIMER | FR_INTR_TX_MULT_DLCIs | FR_INTR_MODEM)); + + + if (fr_comm_enable(card)) { + return -EIO; + } + wanpipe_set_state(card, WAN_CONNECTED); + spin_lock_init(&card->u.f.if_send_lock); + + + /* Manually poll the 56K CSU/DSU to get the status */ + if (IS_56K_CARD(card)) { + /* 56K Update CSU/DSU alarms */ + card->wandev.fe_iface.read_alarm(&card->fe, 1); + } + + /* Unmask - Enable all interrupts */ + card->hw_iface.set_bit(card->hw, card->intr_perm_off, + (FR_INTR_RXRDY | FR_INTR_TXRDY | FR_INTR_DLC | + FR_INTR_TIMER | FR_INTR_TX_MULT_DLCIs | FR_INTR_MODEM)); + card->hw_iface.poke_byte(card->hw, card->intr_type_off, 0x00); + atomic_set(&card->wandev.if_cnt,0); + atomic_set(&card->wandev.if_up_cnt,0); + + printk(KERN_INFO "\n"); + return 0; +} + +/******* WAN Device Driver Entry Points *************************************/ + +/*============================================================================ + * update - Update wanpipe device status & statistics + * + * @wandev: Wanpipe device pointer + * + * This procedure is called when updating the PROC file system. + * It returns various communications statistics. + * + * cat /proc/net/wanrouter/wanpipe# (where #=1,2,3...) + * + * These statistics are accumulated from 3 + * different locations: + * 1) The 'if_stats' recorded for the device. + * 2) Communication error statistics on the adapter. + * 3) Frame Relay operational statistics on the adapter. + * + * The board level statistics are read during a timer interrupt. + * Note that we read the error and operational statistics + * during consecitive timer ticks so as to minimize the time + * that we are inside the interrupt handler. + * + */ +static int update (wan_device_t* wandev) +{ + sdla_t* card; + unsigned long smp_flags; + + /* sanity checks */ + if ((wandev == NULL) || (wandev->private == NULL)) + return -EFAULT; + + if (wandev->state == WAN_UNCONFIGURED) + return -ENODEV; + + card = wandev->private; + + if (test_and_set_bit(0,&card->update_comms_stats)){ + return -EBUSY; + } + + spin_lock_irqsave(&card->wandev.lock, smp_flags); + + fr_get_err_stats(card); + fr_get_stats(card, card->u.f.update_dlci); + + if (card->u.f.update_dlci == NULL){ + if (IS_TE1_CARD(card)) { + /* TE1 Update T1/E1 alarms */ + card->wandev.fe_iface.read_alarm(&card->fe, 0); + /* TE1 Update T1/E1 perfomance counters */ + card->wandev.fe_iface.read_pmon(&card->fe, 0); + }else if (IS_56K_CARD(card)) { + /* 56K Update CSU/DSU alarms */ + card->wandev.fe_iface.read_alarm(&card->fe, 1); + } + } + + card->u.f.update_dlci = NULL; + card->update_comms_stats = 0; + + spin_unlock_irqrestore(&card->wandev.lock, smp_flags); + return 0; +} + +/*============================================================================ + * new_if - Create new logical channel. + * + * &wandev: Wanpipe device pointer + * &dev: Network device pointer + * &conf: User configuration options pointer + * + * This routine is called by the ROUTER_IFNEW ioctl, + * in wanmain.c. The ioctl passes us the user configuration + * options which we use to configure the driver and + * firmware. + * + * This functions main purpose is to allocate the + * private structure for Frame Relay protocol and bind it + * to dev->priv pointer. + * + * Also the dev->init pointer should also be initialized + * to the if_init() function. + * + * Any allocation necessary for the private strucutre + * should be done here, as well as proc/ file initializetion + * for the network interface. + * + * o parse media- and hardware-specific configuration + * o make sure that a new channel can be created + * o allocate resources, if necessary + * o prepare network device structure for registaration. + * o add network interface to the /proc/net/wanrouter + * + * The opposite of this function is del_if() + * + * Return: 0 o.k. + * < 0 failure (channel will not be created) + */ + +static int new_if (wan_device_t* wandev, netdevice_t* dev, wanif_conf_t* conf) +{ + sdla_t* card = wandev->private; + fr_channel_t* chan; + int dlci = 0; + int err = 0; + + if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) { + + printk(KERN_INFO "%s: Error, Invalid interface name!\n", + card->devname); + return -EINVAL; + } + + if (atomic_read(&wandev->if_cnt) > 0 && card->u.f.auto_dlci_cfg){ + printk(KERN_INFO + "%s:%s: Error, DLCI autoconfig only allowed on a single DLCI\n", + card->devname,conf->name); + printk(KERN_INFO "%s: Please turn off DLCI autoconfig in %s.conf\n", + card->devname,card->devname); + printk(KERN_INFO "\n"); + return -EINVAL; + } + + /* allocate and initialize private data */ + chan = wan_malloc(sizeof(fr_channel_t)); + if (chan == NULL){ + WAN_MEM_ASSERT(card->devname); + return -ENOMEM; + } + + memset(chan, 0, sizeof(fr_channel_t)); + strcpy(chan->name, conf->name); + chan->card = card; + + WAN_TASKLET_INIT((&chan->common.bh_task),0,fr_bh,(unsigned long)chan); + chan->common.state = WAN_CONNECTING; + + /* verify media address */ + if (strcmp(conf->addr,"auto")){ + + if (is_digit(conf->addr[0])) { + + dlci = dec_to_uint(conf->addr, 0); + + if (dlci && (dlci <= HIGHEST_VALID_DLCI)) { + + chan->dlci = dlci; + chan->common.lcn = dlci; + + } else { + + printk(KERN_INFO + "%s: Error, Invalid DLCI %u on interface %s!\n", + wandev->name, dlci, chan->name); + err = -EINVAL; + goto new_if_error; + } + + } else { + printk(KERN_INFO + "%s: Error, Invalid media address on interface %s!\n", + wandev->name, chan->name); + err = -EINVAL; + goto new_if_error; + } + + }else{ + + if (card->wandev.station == WANOPT_NODE){ + printk(KERN_INFO "%s: Error, DLCI autoconfig only allowed for CPE!\n", + card->devname); + printk(KERN_INFO "%s: Please turn off DLCI autoconfig in %s.conf\n", + card->devname,card->devname); + + err = -EINVAL; + goto new_if_error; + } + + if (atomic_read(&wandev->if_cnt) != 0){ + printk(KERN_INFO + "%s:%s: Error, DLCI autoconfig only allowed on a single DLCI\n", + card->devname,chan->name); + printk(KERN_INFO "%s: Please turn off DLCI autoconfig in %s.conf\n", + card->devname,card->devname); + + err = -EINVAL; + goto new_if_error; + } + + card->u.f.auto_dlci_cfg=1; + + dlci=0xFFFF; + chan->dlci=0xFFFF; + } + + if (find_channel (card, chan->dlci) != NULL){ + printk(KERN_INFO "%s: Warning: Interface %s already bound to dlci %i\n", + card->devname, chan->name, dlci); + err = -EEXIST; + goto new_if_error; + } + + if (card->u.f.auto_dlci_cfg){ + printk(KERN_INFO "%s: Interface %s configured for AUTO DLCI\n", + card->devname,conf->name); + }else{ + printk(KERN_INFO "%s: Interface %s bound to DLCI %i\n", + card->devname,conf->name,dlci); + } + + if ((chan->true_if_encoding = conf->true_if_encoding) == WANOPT_YES){ + printk(KERN_INFO + "%s:%s : Enabling, true interface type encoding.\n", + card->devname,chan->name); + } + + + /* Setup wanpipe as a router (WANPIPE) even if it is + * a bridged DLCI, or as an API + */ + if (strcmp(conf->usedby, "WANPIPE") == 0 || + strcmp(conf->usedby, "BRIDGE") == 0 || + strcmp(conf->usedby, "BRIDGE_N") == 0){ + + if(strcmp(conf->usedby, "WANPIPE") == 0){ + chan->common.usedby = WANPIPE; + + printk(KERN_INFO "%s:%s: Running in WANPIPE mode.\n", + card->devname,chan->name); + + }else if(strcmp(conf->usedby, "BRIDGE") == 0){ + + chan->common.usedby = BRIDGE; + + printk(KERN_INFO "%s:%s: Running in WANPIPE (BRIDGE) mode.\n", + card->devname,chan->name); + + }else if(strcmp(conf->usedby, "BRIDGE_N") == 0 ){ + + chan->common.usedby = BRIDGE_NODE; + + printk(KERN_INFO "%s:%s: Running in WANPIPE (BRIDGE_NODE) mode.\n", + card->devname,chan->name); + } + + if (!err){ + /* Dynamic interface configuration option. + * On disconnect, if the options is selected, + * the interface will be brought down */ + if (conf->if_down == WANOPT_YES){ + set_bit(DYN_OPT_ON,&chan->interface_down); + printk(KERN_INFO + "%s:%s: Dynamic interface configuration enabled.\n", + card->devname,chan->name); + } + } + + } else if(strcmp(conf->usedby, "API") == 0){ + + chan->common.usedby = API; + printk(KERN_INFO "%s:%s: Running in API mode.\n", + wandev->name,chan->name); + wan_reg_api(chan, dev, card->devname); + } + + if (err) { + goto new_if_error; + } + + /* place cir,be,bc and other channel specific information into the + * chan structure + */ + if (conf->cir) { + + chan->cir = wp_max( 1, wp_min( conf->cir, 512 ) ); + chan->cir_status = CIR_ENABLED; + + + /* If CIR is enabled, force BC to equal CIR + * this solves number of potential problems if CIR is + * set and BC is not + */ + chan->bc = chan->cir; + + if (conf->be){ + chan->be = wp_max( 0, wp_min( conf->be, 511) ); + }else{ + conf->be = 0; + } + + printk (KERN_INFO "%s:%s:: CIR enabled\n", + wandev->name,chan->name); + + printk (KERN_INFO "%s: CIR = %i ; BC = %i ; BE = %i\n", + wandev->name,chan->cir,chan->bc,chan->be); + + }else{ + chan->cir_status = CIR_DISABLED; + printk (KERN_INFO "%s:%s: CIR disabled\n", + wandev->name,chan->name); + } + + chan->mc = conf->mc; + + /* Split up between INARP TX and RX. If the TX ARP is + * enabled the RX arp will be enabled by default. + * Otherwise the user has a choice to ignore incoming + * arps if the TX is turned off */ + + chan->inarp_rx = conf->inarp_rx; + + if (conf->inarp == WANOPT_YES){ + printk(KERN_INFO "%s:%s: Inv. ARP Support Enabled\n",card->devname,chan->name); + chan->inarp = conf->inarp ? INARP_REQUEST : INARP_NONE; + chan->inarp_interval = conf->inarp_interval ? conf->inarp_interval : 10; + chan->inarp_rx = WANOPT_YES; + }else{ + printk(KERN_INFO "%s:%s: Inv. ARP Support Disabled\n",card->devname,chan->name); + chan->inarp = INARP_NONE; + chan->inarp_interval = 10; + } + + if (chan->inarp_rx == WANOPT_YES){ + printk(KERN_INFO "%s:%s: Inv. ARP Reception Enabled!\n",card->devname,chan->name); + }else{ + printk(KERN_INFO "%s:%s: Inv. ARP Reception Disabled!\n",card->devname,chan->name); + } + + + chan->dlci_configured = DLCI_NOT_CONFIGURED; + + + /*FIXME: IPX disabled in this WANPIPE version */ + if (conf->enable_IPX == WANOPT_YES){ + chan->enable_IPX = WANOPT_YES; + printk(KERN_INFO "%s:%s: IPX Support Enabled!\n",card->devname,chan->name); + }else{ + printk(KERN_INFO "%s:%s: IPX Support Disabled!\n",card->devname,chan->name); + chan->enable_IPX = WANOPT_NO; + } + + if (conf->network_number && chan->enable_IPX == WANOPT_YES){ + printk(KERN_INFO "%s:%s: IPX Network Address 0x%lX!\n", + card->devname,chan->name,conf->network_number); + chan->network_number = conf->network_number; + }else{ + chan->network_number = 0xDEADBEEF; + } + + chan->route_flag = NO_ROUTE; + + init_chan_statistics(chan); + + chan->transmit_length = 0; + + /* Initialize FR Polling Task Queue + * We need a poll routine for each network + * interface. + */ + + INIT_WORK((&chan->fr_poll_task),fr_poll,dev); + + init_timer(&chan->fr_arp_timer); + chan->fr_arp_timer.data=(unsigned long)dev; + chan->fr_arp_timer.function = fr_arp; + + /* Tells us that if this interface is a + * gateway or not */ + if ((chan->gateway = conf->gateway) == WANOPT_YES){ + printk(KERN_INFO "%s: Interface %s is set as a gateway.\n", + card->devname,dev->name); + } + + /* Initialize the encapsulation header to + * the IETF standard. + */ + chan->fr_encap_0 = Q922_UI; + chan->fr_encap_1 = NLPID_IP; + + /* + * Create interface file in proc fs. + * Once the proc file system is created, the new_if() function + * should exit successfuly. + * + * DO NOT place code under this function that can return + * anything else but 0. + */ + err = wanrouter_proc_add_interface(wandev, &chan->dent, chan->name, dev); + if (err){ + printk(KERN_INFO + "%s: can't create /proc/net/router/fr/%s entry!\n", + card->devname, chan->name); + goto new_if_error; + } + chan->dlci_type = SNMP_FR_STATIC; + chan->trap_state = SNMP_FR_DISABLED; + chan->trap_max_rate = 0; + + dev->init = &if_init; + dev->priv = chan; + chan->common.dev = dev; + + /* Configure this dlci at a later date, when + * the interface comes up. i.e. when if_open() + * executes */ + set_bit(0,&chan->config_dlci); + + atomic_inc(&wandev->if_cnt); + printk(KERN_INFO "\n"); + return 0; + +new_if_error: + + WAN_TASKLET_KILL(&chan->common.bh_task); + wan_unreg_api(chan, card->devname); + + DEBUG_SUB_MEM(sizeof(fr_channel_t)); + wan_free(chan); + + dev->priv=NULL; + return err; +} + +/*============================================================================ + * del_if - Delete logical channel. + * + * @wandev: Wanpipe private device pointer + * @dev: Netowrk interface pointer + * + * This function is called by ROUTER_DELIF ioctl call + * to deallocate the network interface. + * + * The network interface and the private structure are + * about to be deallocated by the upper layer. + * We have to clean and deallocate any allocated memory. + * + */ +static int del_if (wan_device_t* wandev, netdevice_t* dev) +{ + fr_channel_t* chan = dev->priv; + unsigned long smp_flags; + sdla_t *card=wandev->private; + + /* Delete interface name from proc fs. */ + wanrouter_proc_delete_interface(wandev, chan->name); + + /* This interface is dead, make sure the + * ARP timer is stopped */ + del_timer(&chan->fr_arp_timer); + + WAN_TASKLET_KILL(&chan->common.bh_task); + wan_unreg_api(chan, card->devname); + + /* Unconfigure this DLCI, free any pending skb + * buffers and deallocate the bh_head circular + * buffer. + */ + wan_spin_lock_irq(&card->wandev.lock,&smp_flags); + + unconfig_fr_dev (card,dev); + + if (card->u.f.arp_dev == dev){ + card->u.f.arp_dev=NULL; + } + if (chan->delay_skb){ + wan_skb_free(chan->delay_skb); + chan->delay_skb=NULL; + } + if (chan->tx_arp){ + wan_skb_free(chan->tx_arp); + chan->tx_arp=NULL; + } + if (chan->tx_ipx){ + wan_skb_free(chan->tx_ipx); + chan->tx_ipx=NULL; + } + + wan_spin_unlock_irq(&card->wandev.lock,&smp_flags); + + DEBUG_SUB_MEM(sizeof(fr_channel_t)); + atomic_dec(&wandev->if_cnt); + return 0; +} + +/*============================================================= + * disable_comm - Main shutdown function + * + * @card: Wanpipe device pointer + * + * The command 'wanrouter stop' has been called + * and the whole wanpipe device is going down. + * This is the last function called to disable + * all comunications and deallocate any memory + * that is still allocated. + * + * o Disable communications, turn off interrupts + * o Deallocate memory used + * o Unconfigure TE1 card + */ + +static void disable_comm (sdla_t *card) +{ + unsigned long smp_flags; + + printk(KERN_INFO "%s: Disabling Communications!\n", + card->devname); + wan_spin_lock_irq(&card->wandev.lock,&smp_flags); + fr_comm_disable(card); + wan_spin_unlock_irq(&card->wandev.lock,&smp_flags); + + /* TE1 unconfiging */ + if (IS_TE1_CARD(card)) { + if (card->wandev.fe_iface.unconfig){ + card->wandev.fe_iface.unconfig(&card->fe); + } + } +} + +/****** Network Device Interface ********************************************/ + +/*============================================================================ + * Initialize Linux network interface. + * + * This routine is called only once for each interface, during Linux network + * interface registration. Returning anything but zero will fail interface + * registration. + */ +static int if_init (netdevice_t* dev) +{ + fr_channel_t* chan = dev->priv; + sdla_t* card = chan->card; + wan_device_t* wandev = &card->wandev; + + /* Initialize device driver entry points */ + dev->open = &if_open; + dev->stop = &if_close; + dev->hard_header = NULL; + dev->rebuild_header = NULL; + dev->hard_start_xmit = &if_send; + dev->get_stats = &if_stats; +#if defined(LINUX_2_4) || defined(LINUX_2_6) + dev->tx_timeout = &if_tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; +#endif + + if (chan->common.usedby == WANPIPE || chan->common.usedby == API){ + + /* Initialize media-specific parameters */ + if (chan->true_if_encoding){ + dev->type = ARPHRD_DLCI; /* This breaks tcpdump */ + }else{ + dev->type = ARPHRD_PPP; /* ARP h/w type */ + } + + dev->flags |= IFF_POINTOPOINT; + dev->flags |= IFF_NOARP; + + /* Enable Multicast addressing */ + if (chan->mc == WANOPT_YES){ + dev->flags |= IFF_MULTICAST; + } + + dev->mtu = wandev->mtu - FR_HEADER_LEN; + /* For an API, the maximum number of bytes that the stack will pass + to the driver is (dev->mtu + dev->hard_header_len). So, adjust the + mtu so that a frame of maximum size can be transmitted by the API. + */ + if(chan->common.usedby == API) { + dev->mtu += (sizeof(api_tx_hdr_t) - FR_HEADER_LEN); + } + + dev->hard_header_len = 0; /* media header length */ + dev->addr_len = 2; /* hardware address length */ + *(unsigned short*)dev->dev_addr = chan->dlci; + + /* Set transmit buffer queue length */ + dev->tx_queue_len = 100; + + }else{ + + /* Setup the interface for Bridging */ + int hw_addr=0; + ether_setup(dev); + + /* Use a random number to generate the MAC address */ + memcpy(dev->dev_addr, "\xFE\xFC\x00\x00\x00\x00", 6); + get_random_bytes(&hw_addr, sizeof(hw_addr)); + *(int *)(dev->dev_addr + 2) += hw_addr; + } + + /* Initialize hardware parameters (just for reference) */ + dev->irq = wandev->irq; + dev->dma = wandev->dma; + dev->base_addr = wandev->ioport; + card->hw_iface.getcfg(card->hw, SDLA_MEMBASE, &dev->mem_start); //ALEX_TODAY wandev->maddr; + card->hw_iface.getcfg(card->hw, SDLA_MEMEND, &dev->mem_end); //ALEX_TODAY wandev->maddr + wandev->msize - 1; + + /* SNMP */ + dev->do_ioctl = if_do_ioctl; + + return 0; +} + + +/*============================================================================ + * if_open - Open network interface. + * + * @dev: Network device pointer + * + * On ifconfig up, this function gets called in order + * to initialize and configure the private area. + * Driver should be configured to send and receive data. + * + * Return 0 if O.k. or errno. + */ + +static int if_open (netdevice_t* dev) +{ + fr_channel_t* chan = dev->priv; + sdla_t* card = chan->card; + int err = 0; + struct timeval tv; + unsigned long smp_flags; + + if (open_dev_check(dev)){ + return -EBUSY; + } + + netif_start_queue(dev); + + wanpipe_open(card); + do_gettimeofday( &tv ); + chan->router_start_time = tv.tv_sec; + + atomic_inc(&card->wandev.if_up_cnt); + + if (test_bit(0,&chan->config_dlci)){ + netdevice_t *dev1; + + wan_spin_lock_irq(&card->wandev.lock,&smp_flags); + config_fr_dev(card,dev); + clear_bit(0,&chan->config_dlci); + wan_spin_unlock_irq(&card->wandev.lock,&smp_flags); + + dev1 = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + if (dev1 == dev && card->wandev.station == WANOPT_CPE){ + printk(KERN_INFO + "%s: Waiting for DLCI report from frame relay switch...\n\n", + card->devname); + } + }else if (chan->inarp == INARP_REQUEST){ + trigger_fr_arp(dev); + } + + + return err; +} + +/*============================================================================ + * if_close - Close network interface. + * + * @dev: Network device pointer + * + * On ifconfig down, this function gets called in order + * to cleanup interace private area. + * + * IMPORTANT: + * + * No deallocation or unconfiguration should ever occur in this + * function, because the interface can come back up + * (via ifconfig up). + * + * Furthermore, in dynamic interfacace configuration mode, the + * interface will come up and down to reflect the protocol state. + * + * Any private deallocation and cleanup can occur in del_if() + * function. That function is called before the dev interface + * itself is deallocated. + * + * Thus, we should only stop the net queue and decrement + * the wanpipe usage counter via wanpipe_close() function. + */ + +static int if_close (netdevice_t* dev) +{ + fr_channel_t* chan = dev->priv; + sdla_t* card = chan->card; + + if (chan->inarp == INARP_CONFIGURED) { + chan->inarp = INARP_REQUEST; + } + + stop_net_queue(dev); +#if defined(LINUX_2_1) + dev->start=0; +#endif + wanpipe_close(card); + + atomic_dec(&card->wandev.if_up_cnt); + return 0; +} + +/*============================================================================ + * Handle transmit timeout event from netif watchdog + */ +static void if_tx_timeout (netdevice_t *dev) +{ + fr_channel_t* chan = dev->priv; + sdla_t *card = chan->card; + + /* If our device stays busy for at least 5 seconds then we will + * kick start the device by making dev->tbusy = 0. We expect + * that our device never stays busy more than 5 seconds. So this + * is only used as a last resort. + */ + + chan->drvstats_if_send.if_send_tbusy++; + ++chan->ifstats.collisions; + + printk (KERN_INFO "%s: Transmit timed out on %s\n", + card->devname, dev->name); + + atomic_inc(&card->u.f.tx_interrupts_pending); + card->hw_iface.set_bit(card->hw, card->intr_perm_off, FR_INTR_TXRDY); + +#if defined(LINUX_2_4) || defined(LINUX_2_6) + dev->trans_start = jiffies; +#endif + + chan->drvstats_if_send.if_send_tbusy_timeout++; + netif_wake_queue (dev); + +} + +/*============================================================================ + * if_send - Send a packet on a network interface. + * + * @dev: Network interface pointer + * @skb: Packet obtained from the stack or API + * that should be sent out the port. + * + * o set tbusy flag (marks start of the transmission) to + * block a timer-based transmit from overlapping. + * o set critical flag when accessing board. + * o check link state. If link is not up, then drop the packet. + * o check channel status. If it's down then initiate a call. + * o pass a packet to corresponding WAN device. + * o free socket buffer + * + * Return: 0 complete (socket buffer must be freed) + * non-0 packet may be re-transmitted (tbusy must be set) + * + * Notes: + * 1. This routine is called either by the protocol stack or by the "net + * bottom half" (with interrupts enabled). + * + * 2. Using the start_net_queue() and stop_net_queue() MACROS + * will inhibit further transmit requests from the protocol stack + * and can be used for flow control with protocol layer. + */ +static int if_send (struct sk_buff* skb, netdevice_t* dev) +{ + fr_channel_t* chan = dev->priv; + sdla_t* card = chan->card; + unsigned char *sendpacket; + int err; + int udp_type; + unsigned long delay_tx_queued=0; + unsigned long smp_flags=0; + unsigned char attr = 0; + + chan->drvstats_if_send.if_send_entry++; + + if (skb == NULL) { + /* if we get here, some higher layer thinks we've missed an + * tx-done interrupt. + */ + printk(KERN_INFO "%s: interface %s got kicked!\n", + card->devname, dev->name); + chan->drvstats_if_send.if_send_skb_null ++; + + wake_net_dev(dev); + return 0; + } + + DEBUG_ADD_MEM(skb->truesize); + + /* If a peripheral task is running just drop packets */ + if (test_bit(PERI_CRIT, &card->wandev.critical)){ + + printk(KERN_INFO "%s: Critical in if_send(): Peripheral running!\n", + card->devname); + + wan_skb_free(skb); + start_net_queue(dev); + return 0; + } + + /* We must set the 'tbusy' flag if we already have a packet queued for + transmission in the transmit interrupt handler. However, we must + ensure that the transmit interrupt does not reset the 'tbusy' flag + just before we set it, as this will result in a "transmit timeout". + */ + + wan_spin_lock_irq(&card->wandev.lock, &smp_flags); + set_bit(SEND_TXIRQ_CRIT, (void*)&card->wandev.critical); + if(chan->transmit_length || chan->tx_ipx || chan->tx_arp) { + if (card->wandev.state != WAN_CONNECTED || + chan->common.state != WAN_CONNECTED){ + wan_skb_free(skb); + start_net_queue(dev); + chan->drvstats_if_send.if_send_dlci_disconnected ++; + ++chan->ifstats.tx_dropped; + ++card->wandev.stats.tx_dropped; + ++chan->ifstats.tx_carrier_errors; + ++card->wandev.stats.tx_carrier_errors; + err=0; + }else{ + DEBUG_SUB_MEM(skb->truesize); + stop_net_queue(dev); + chan->tick_counter = jiffies; + err=1; + } + clear_bit(SEND_TXIRQ_CRIT, (void*)&card->wandev.critical); + wan_spin_unlock_irq(&card->wandev.lock, &smp_flags); + return err; + } + clear_bit(SEND_TXIRQ_CRIT, (void*)&card->wandev.critical); + wan_spin_unlock_irq(&card->wandev.lock, &smp_flags); + + +#if defined(LINUX_2_1) + if (dev->tbusy) { + + chan->drvstats_if_send.if_send_tbusy++; + ++chan->ifstats.collisions; + + if ((jiffies - chan->tick_counter) < (5 * HZ)) { + return 1; + } + + if_tx_timeout(dev); + } +#endif + + /* Move the if_header() code to here. By inserting frame + * relay header in if_header() we would break the + * tcpdump and other packet sniffers */ + chan->fr_header_len = setup_fr_header(&skb,dev,chan->common.usedby); + if (chan->fr_header_len < 0 ){ + ++chan->ifstats.tx_dropped; + ++card->wandev.stats.tx_dropped; + ++chan->ifstats.tx_errors; + ++card->wandev.stats.tx_errors; + + wan_skb_free(skb); + start_net_queue(dev); + return 0; + } + + sendpacket = skb->data; + + udp_type = udp_pkt_type(skb, card, UDP_PKT_FRM_STACK); + + if(udp_type != UDP_INVALID_TYPE) { + if(store_udp_mgmt_pkt(udp_type, UDP_PKT_FRM_STACK, card, skb, + chan->dlci)) { + card->hw_iface.set_bit(card->hw, card->intr_perm_off, FR_INTR_TIMER); + if (udp_type == UDP_FPIPE_TYPE){ + chan->drvstats_if_send. + if_send_PIPE_request ++; + } + } + start_net_queue(dev); + return 0; + } + +#if 1 + //FIXME: can we do better than sendpacket[2]? + if ((chan->common.usedby == WANPIPE) && (sendpacket[0] == 0x45)) { + /* check to see if the source IP address is a broadcast or */ + /* multicast IP address */ + if(chk_bcast_mcast_addr(card, dev, skb)){ + ++chan->ifstats.tx_dropped; + ++card->wandev.stats.tx_dropped; + wan_skb_free(skb); + start_net_queue(dev); + return 0; + } + } +#endif + + /* Lock the S514/S508 card: SMP Supported */ + s508_s514_lock(card,&smp_flags); + + if (test_and_set_bit(SEND_CRIT, (void*)&card->wandev.critical)) { + + chan->drvstats_if_send.if_send_critical_non_ISR ++; + chan->ifstats.tx_errors ++; + printk(KERN_INFO "%s Critical in IF_SEND: if_send() already running!\n", + card->devname); + goto if_send_start_and_exit; + } + + /* API packet check: minimum packet size must be greater than + * 16 byte API header */ + if((chan->common.usedby == API) && (skb->len <= sizeof(api_tx_hdr_t))) { + ++chan->ifstats.tx_errors; + ++card->wandev.stats.tx_errors; + goto if_send_start_and_exit; + + }else{ + /* During API transmission, get rid of the API header */ + if (chan->common.usedby == API) { + api_tx_hdr_t* api_tx_hdr; + api_tx_hdr = (api_tx_hdr_t*)&skb->data[0x00]; + attr = api_tx_hdr->attr; + skb_pull(skb,sizeof(api_tx_hdr_t)); + } + } + + if (card->wandev.state != WAN_CONNECTED) { + chan->drvstats_if_send.if_send_wan_disconnected ++; + ++chan->ifstats.tx_dropped; + ++card->wandev.stats.tx_dropped; + ++chan->ifstats.tx_carrier_errors; + ++card->wandev.stats.tx_carrier_errors; + + } else if (chan->common.state != WAN_CONNECTED) { + chan->drvstats_if_send.if_send_dlci_disconnected ++; + + /* Update the DLCI state in timer interrupt */ + card->u.f.timer_int_enabled |= TMR_INT_ENABLED_UPDATE_STATE; + card->hw_iface.set_bit(card->hw, card->intr_perm_off, FR_INTR_TIMER); + + ++chan->ifstats.tx_dropped; + ++card->wandev.stats.tx_dropped; + ++chan->ifstats.tx_carrier_errors; + ++card->wandev.stats.tx_carrier_errors; + + + } else if (!is_tx_ready(card, chan)) { + /* No tx buffers available, store for delayed transmit */ + if (!setup_for_delayed_transmit(dev, skb)){ + set_bit(1,&delay_tx_queued); + } + chan->drvstats_if_send.if_send_no_bfrs++; + + } else if (!skb->protocol) { + /* No protocols drop packet */ + printk(KERN_INFO "%s: %s: if_send() pkt no protocol: dropping!\n", + card->devname,dev->name); + chan->drvstats_if_send.if_send_protocol_error ++; + ++card->wandev.stats.tx_errors; + + } else if (test_bit(ARP_CRIT,&card->wandev.critical)){ + /* We are trying to send an ARP Packet, block IP data until + * ARP is sent */ + if (net_ratelimit()){ + printk(KERN_INFO "%s: %s: FR Data Tx waiting for ARP to Tx!\n", + card->devname,dev->name); + } + ++chan->ifstats.tx_dropped; + ++card->wandev.stats.tx_dropped; + + } else { + if(chan->common.usedby == WANPIPE && + htons(skb->protocol) == ETH_P_IPX){ + + if( chan->enable_IPX ) { + switch_net_numbers(sendpacket, + chan->network_number, 0); + } else { + printk(KERN_INFO + "%s: WARNING: Unsupported IPX data in send, packet dropped\n", + card->devname); + + ++chan->ifstats.tx_dropped; + ++card->wandev.stats.tx_dropped; + + goto if_send_start_and_exit; + } + + } + + err = fr_send_data_header(card, + chan->dlci, + attr, + skb->len, + skb->data, + chan->fr_header_len, + 1); + if (err) { + switch(err) { + case FRRES_CIR_OVERFLOW: + case FRRES_BUFFER_OVERFLOW: + if (!setup_for_delayed_transmit(dev, skb)){ + set_bit(1,&delay_tx_queued); + } + chan->drvstats_if_send. + if_send_adptr_bfrs_full ++; + break; + + case FRRES_TOO_LONG: + if (net_ratelimit()){ + printk(KERN_INFO + "%s: Error: Frame too long, transmission failed %i\n", + card->devname, (unsigned int)skb->len); + } + + /* Drop down to default */ + default: + chan->drvstats_if_send. + if_send_dlci_disconnected ++; + ++chan->ifstats.tx_dropped; + ++card->wandev.stats.tx_dropped; + ++chan->ifstats.tx_carrier_errors; + ++card->wandev.stats.tx_carrier_errors; + break; + } + + }else{ + chan->drvstats_if_send. + if_send_bfr_passed_to_adptr++; + ++chan->ifstats.tx_packets; + ++card->wandev.stats.tx_packets; + + chan->ifstats.tx_bytes += skb->len; + card->wandev.stats.tx_bytes += skb->len; +#if defined(LINUX_2_4) || defined(LINUX_2_6) + dev->trans_start = jiffies; +#endif + } + } + +if_send_start_and_exit: + + start_net_queue(dev); + + /* If we queued the packet for transmission, we must not + * deallocate it. The packet is unlinked from the IP stack + * not copied. Therefore, we must keep the original packet */ + if (!test_bit(1,&delay_tx_queued)) { + wan_skb_free(skb); + }else{ + atomic_inc(&card->u.f.tx_interrupts_pending); + card->hw_iface.set_bit(card->hw, card->intr_perm_off, FR_INTR_TXRDY); + } + + clear_bit(SEND_CRIT, (void*)&card->wandev.critical); + + s508_s514_unlock(card,&smp_flags); + + return 0; +} + + +/*========================================================================= + * if_do_ioctl - Ioctl handler for fr + * + * @dev: Device subject to ioctl + * @ifr: Interface request block from the user + * @cmd: Command that is being issued + * + * This function handles the ioctls that may be issued by the user + * to control the settings of a FR. It does both busy + * and security checks. This function is intended to be wrapped by + * callers who wish to add additional ioctl calls of their own. + * + */ +static int if_do_ioctl(netdevice_t *dev, struct ifreq *ifr, int cmd) +{ + unsigned long smp_flags; + fr_channel_t* chan = dev->priv; + sdla_t *card; + wan_udp_pkt_t *wan_udp_pkt; + int err=0; + + if (!chan) + return -ENODEV; + + card = chan->card; + + NET_ADMIN_CHECK(); + + switch(cmd) + { + + case SIOC_WANPIPE_BIND_SK: + if (!ifr){ + err= -EINVAL; + break; + } + + DEBUG_TEST("%s: SIOC_WANPIPE_BIND_SK \n",__FUNCTION__); + + spin_lock_irqsave(&card->wandev.lock,smp_flags); + err=wan_bind_api_to_svc(chan,ifr->ifr_data); + spin_unlock_irqrestore(&card->wandev.lock,smp_flags); + break; + + case SIOC_WANPIPE_UNBIND_SK: + if (!ifr){ + err= -EINVAL; + break; + } + + DEBUG_TEST("%s: SIOC_WANPIPE_UNBIND_SK \n",__FUNCTION__); + spin_lock_irqsave(&card->wandev.lock,smp_flags); + err=wan_unbind_api_from_svc(chan,ifr->ifr_data); + spin_unlock_irqrestore(&card->wandev.lock,smp_flags); + break; + + case SIOC_WANPIPE_CHECK_TX: + case SIOC_ANNEXG_CHECK_TX: + err=0; + break; + + case SIOC_WANPIPE_DEV_STATE: + err = chan->common.state; + break; + + case SIOC_ANNEXG_KICK: + err=0; + break; + + case SIOC_WANPIPE_SNMP: + case SIOC_WANPIPE_SNMP_IFSPEED: + return wan_snmp_data(card, dev, cmd, ifr); + + case SIOC_WANPIPE_PIPEMON: + + if (atomic_read(&card->u.f.udp_pkt_len) != 0){ + return -EBUSY; + } + + atomic_set(&card->u.f.udp_pkt_len,sizeof(wan_udp_hdr_t)); + + wan_udp_pkt=(wan_udp_pkt_t*)&card->u.f.udp_pkt_data; + if (copy_from_user(&wan_udp_pkt->wan_udp_hdr,ifr->ifr_data,sizeof(wan_udp_hdr_t))){ + atomic_set(&card->u.f.udp_pkt_len,0); + return -EFAULT; + } + + spin_lock_irqsave(&card->wandev.lock, smp_flags); + + /* We have to check here again because we don't know + * what happened during spin_lock */ + if (test_bit(0,&card->in_isr)){ + printk(KERN_INFO "%s:%s pipemon command busy: try again!\n", + card->devname,dev->name); + atomic_set(&card->u.f.udp_pkt_len,0); + spin_unlock_irqrestore(&card->wandev.lock, smp_flags); + return -EBUSY; + } + + if (process_udp_mgmt_pkt(card,dev) <= 0 ){ + atomic_set(&card->u.f.udp_pkt_len,0); + spin_unlock_irqrestore(&card->wandev.lock, smp_flags); + return -EINVAL; + } + + + spin_unlock_irqrestore(&card->wandev.lock, smp_flags); + + /* This area will still be critical to other + * PIPEMON commands due to udp_pkt_len + * thus we can release the irq */ + + if (atomic_read(&card->u.f.udp_pkt_len) > sizeof(wan_udp_pkt_t)){ + printk(KERN_INFO "%s: Error: Pipemon buf too bit on the way up! %i\n", + card->devname,atomic_read(&card->u.f.udp_pkt_len)); + atomic_set(&card->u.f.udp_pkt_len,0); + return -EINVAL; + } + + if (copy_to_user(ifr->ifr_data,&wan_udp_pkt->wan_udp_hdr,sizeof(wan_udp_hdr_t))){ + atomic_set(&card->u.f.udp_pkt_len,0); + return -EFAULT; + } + + atomic_set(&card->u.f.udp_pkt_len,0); + return 0; + + default: + return -EOPNOTSUPP; + } + return err; +} + + +/*============================================================================ + * Setup so that a frame can be transmitted on the occurence of a transmit + * interrupt. + */ +static int setup_for_delayed_transmit (netdevice_t* dev, struct sk_buff *skb) +{ + fr_channel_t* chan = dev->priv; + sdla_t* card = chan->card; + fr_dlci_interface_t dlci_interface; + int len = skb->len; + + /* Check that the dlci is properly configured, + * before using tx interrupt */ + if (!chan->dlci_int_interface_off){ + if (net_ratelimit()){ + printk(KERN_INFO + "%s: Error on DLCI %i: Not configured properly !\n", + card->devname, chan->dlci); + printk(KERN_INFO "%s: Please contact Sangoma Technologies\n", + card->devname); + } + return 1; + } + + card->hw_iface.peek(card->hw, chan->dlci_int_interface_off, &dlci_interface, sizeof(dlci_interface)); + + if(chan->transmit_length) { + printk(KERN_INFO "%s: Tx failed to queue packet: queue busy\n", + card->devname); + return 1; + } + + if(len > FR_MAX_NO_DATA_BYTES_IN_FRAME) { + printk(KERN_INFO "%s: Tx failed to queue packet: packet size %i > Max=%i\n", + card->devname,len,FR_MAX_NO_DATA_BYTES_IN_FRAME); + return 1; + } + + wan_skb_unlink(skb); + + chan->transmit_length = len; + chan->delay_skb = skb; + + dlci_interface.gen_interrupt |= FR_INTR_TXRDY; + dlci_interface.packet_length = len; + card->hw_iface.poke(card->hw, chan->dlci_int_interface_off, &dlci_interface, sizeof(dlci_interface)); + /* Turn on TX interrupt at the end of if_send */ + return 0; +} + + +/*============================================================================ + * Check to see if the packet to be transmitted contains a broadcast or + * multicast source IP address. + * Return 0 if not broadcast/multicast address, otherwise return 1. + */ + +static int chk_bcast_mcast_addr(sdla_t *card, netdevice_t* dev, + struct sk_buff *skb) +{ + u32 src_ip_addr; + u32 broadcast_ip_addr = 0; + struct in_device *in_dev; + fr_channel_t* chan = dev->priv; + iphdr_t *iphdr = (iphdr_t *)skb->data; + + if (skb->len < sizeof(iphdr_t)){ + printk(KERN_INFO + "%s: Illegal IP frame len %i, silently discarded\n", + card->devname,skb->len); + return 1; + } + + /* read the IP source address from the outgoing packet */ + src_ip_addr = iphdr->w_ip_src; + + /* read the IP broadcast address for the device */ + in_dev = dev->ip_ptr; + if(in_dev != NULL) { + struct in_ifaddr *ifa= in_dev->ifa_list; + if(ifa != NULL) + broadcast_ip_addr = ifa->ifa_broadcast; + else + return 0; + } + + /* check if the IP Source Address is a Broadcast address */ + if((dev->flags & IFF_BROADCAST) && (src_ip_addr == broadcast_ip_addr)) { + printk(KERN_INFO + "%s: Broadcast Source Address silently discarded\n", + card->devname); + return 1; + } + + /* check if the IP Source Address is a Multicast address */ + if((chan->mc == WANOPT_NO) && (ntohl(src_ip_addr) >= 0xE0000001) && + (ntohl(src_ip_addr) <= 0xFFFFFFFE)) { + printk(KERN_INFO + "%s: Multicast Source Address silently discarded\n", + card->devname); + return 1; + } + + return 0; +} + +/*============================================================================ + * Reply to UDP Management system. + * Return nothing. + */ +static int reply_udp( unsigned char *data, unsigned int mbox_len ) +{ + unsigned short len, udp_length, temp, ip_length; + unsigned long ip_temp; + int even_bound = 0; + wan_udp_pkt_t *wan_udp_pkt = (wan_udp_pkt_t *)data; + + /* Set length of packet */ + len = //sizeof(fr_encap_hdr_t)+ + sizeof(struct iphdr)+ + sizeof(struct udphdr)+ + sizeof(wan_mgmt_t)+ + sizeof(wan_cmd_t)+ + mbox_len; + + + /* fill in UDP reply */ + wan_udp_pkt->wan_udp_request_reply = UDPMGMT_REPLY; + + /* fill in UDP length */ + udp_length = sizeof(struct udphdr)+ + sizeof(wan_mgmt_t)+ + sizeof(wan_cmd_t)+ + mbox_len; + + + /* put it on an even boundary */ + if ( udp_length & 0x0001 ) { + udp_length += 1; + len += 1; + even_bound = 1; + } + + temp = (udp_length<<8)|(udp_length>>8); + wan_udp_pkt->wan_udp_len = temp; + + /* swap UDP ports */ + temp = wan_udp_pkt->wan_udp_sport; + wan_udp_pkt->wan_udp_sport = + wan_udp_pkt->wan_udp_dport; + wan_udp_pkt->wan_udp_dport = temp; + + + + /* add UDP pseudo header */ + temp = 0x1100; + *((unsigned short *) + (wan_udp_pkt->wan_udp_data+mbox_len+even_bound)) = temp; + temp = (udp_length<<8)|(udp_length>>8); + *((unsigned short *) + (wan_udp_pkt->wan_udp_data+mbox_len+even_bound+2)) = temp; + + /* calculate UDP checksum */ + wan_udp_pkt->wan_udp_sum = 0; + + wan_udp_pkt->wan_udp_sum = + calc_checksum(&data[UDP_OFFSET/*+sizeof(fr_encap_hdr_t)*/], + udp_length+UDP_OFFSET); + + /* fill in IP length */ + ip_length = udp_length + sizeof(struct iphdr); + temp = (ip_length<<8)|(ip_length>>8); + wan_udp_pkt->wan_ip_len = temp; + + /* swap IP addresses */ + ip_temp = wan_udp_pkt->wan_ip_src; + wan_udp_pkt->wan_ip_src = + wan_udp_pkt->wan_ip_dst; + wan_udp_pkt->wan_ip_dst = ip_temp; + + + /* fill in IP checksum */ + wan_udp_pkt->wan_ip_sum = 0; + wan_udp_pkt->wan_ip_sum = + calc_checksum(&data[/*sizeof(fr_encap_hdr_t)*/0], + sizeof(struct iphdr)); + + return len; +} /* reply_udp */ + +unsigned short calc_checksum (char *data, int len) +{ + unsigned short temp; + unsigned long sum=0; + int i; + + for( i = 0; i > 16 ) { + sum = (sum & 0xffffUL) + (sum >> 16); + } + + temp = (unsigned short)sum; + temp = ~temp; + + if( temp == 0 ) + temp = 0xffff; + + return temp; +} + +/* + If incoming is 0 (outgoing)- if the net numbers is ours make it 0 + if incoming is 1 - if the net number is 0 make it ours + +*/ +static void switch_net_numbers(unsigned char *sendpacket, + unsigned long network_number, + unsigned char incoming) +{ + unsigned long pnetwork_number; + + pnetwork_number = (unsigned long)((sendpacket[6] << 24) + + (sendpacket[7] << 16) + (sendpacket[8] << 8) + + sendpacket[9]); + + if (!incoming) { + /* If the destination network number is ours, make it 0 */ + if( pnetwork_number == network_number) { + sendpacket[6] = sendpacket[7] = sendpacket[8] = + sendpacket[9] = 0x00; + } + } else { + /* If the incoming network is 0, make it ours */ + if( pnetwork_number == 0) { + sendpacket[6] = (unsigned char)(network_number >> 24); + sendpacket[7] = (unsigned char)((network_number & + 0x00FF0000) >> 16); + sendpacket[8] = (unsigned char)((network_number & + 0x0000FF00) >> 8); + sendpacket[9] = (unsigned char)(network_number & + 0x000000FF); + } + } + + + pnetwork_number = (unsigned long)((sendpacket[18] << 24) + + (sendpacket[19] << 16) + (sendpacket[20] << 8) + + sendpacket[21]); + + if( !incoming ) { + /* If the source network is ours, make it 0 */ + if( pnetwork_number == network_number) { + sendpacket[18] = sendpacket[19] = sendpacket[20] = + sendpacket[21] = 0x00; + } + } else { + /* If the source network is 0, make it ours */ + if( pnetwork_number == 0 ) { + sendpacket[18] = (unsigned char)(network_number >> 24); + sendpacket[19] = (unsigned char)((network_number & + 0x00FF0000) >> 16); + sendpacket[20] = (unsigned char)((network_number & + 0x0000FF00) >> 8); + sendpacket[21] = (unsigned char)(network_number & + 0x000000FF); + } + } +} /* switch_net_numbers */ + +/*============================================================================ + * Get ethernet-style interface statistics. + * Return a pointer to struct enet_statistics. + */ +static struct net_device_stats *if_stats(netdevice_t *dev) +{ + fr_channel_t* chan = dev->priv; + + if(chan == NULL) + return NULL; + + return &chan->ifstats; +} + +/****** Interrupt Handlers **************************************************/ + +/*============================================================================ + * fr_isr: S508 frame relay interrupt service routine. + * + * Description: + * Frame relay main interrupt service route. This + * function check the interrupt type and takes + * the appropriate action. + */ +static void fr_isr (sdla_t* card) +{ + int i,err; + u8 intr_type; + fr508_flags_t flags; + wan_mbox_t* mb = &card->wan_mbox; + + if (!card->hw){ + return; + } + + card->hw_iface.peek(card->hw, card->flags_off, &flags, sizeof(flags)); + /* This flag prevents nesting of interrupts. See sdla_isr() routine + * in sdlamain.c. */ + set_bit(0,&card->in_isr); + + ++card->statistics.isr_entry; + + /* All peripheral (configuraiton, re-configuration) events + * take presidence over the ISR. Thus, retrigger */ + if (test_bit(PERI_CRIT, (void*)&card->wandev.critical)) { + ++card->statistics.isr_already_critical; + goto fr_isr_exit; + } + + if(card->type != SDLA_S514) { + if (test_bit(SEND_CRIT, (void*)&card->wandev.critical)) { + printk(KERN_INFO "%s: Critical while in ISR: If Send Running!\n", + card->devname); + ++card->statistics.isr_already_critical; + goto fr_isr_exit; + } + } + + switch (flags.iflag) { + + case FR_INTR_RXRDY: /* receive interrupt */ + ++card->statistics.isr_rx; + rx_intr(card); + break; + + + case FR_INTR_TXRDY: /* transmit interrupt */ + ++ card->statistics.isr_tx; + tx_intr(card); + break; + + case FR_INTR_READY: + card->timer_int_enabled++; + ++card->statistics.isr_intr_test; + break; + + case FR_INTR_DLC: /* Event interrupt occured */ + mb->wan_command = FR_READ_STATUS; + mb->wan_data_len = 0; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err) + fr_event(card, err, mb); + break; + + case FR_INTR_TIMER: /* Timer interrupt */ + timer_intr(card); + break; + + case FR_INTR_MODEM: + mb->wan_command = FR_READ_STATUS; + mb->wan_data_len = 0; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err) + fr_event(card, err, mb); + break; + + default: + ++card->statistics.isr_spurious; + spur_intr(card); + card->hw_iface.peek(card->hw, card->intr_type_off, &intr_type, 1); + printk(KERN_INFO "%s: Interrupt Type 0x%02X!\n", + card->devname, intr_type); + + printk(KERN_INFO "%s: ID Bytes = ",card->devname); + { + unsigned char str[8]; + card->hw_iface.peek(card->hw, card->intr_type_off+0x28, str, 8); + for(i = 0; i < 8; i ++){ + printk("%02X ", str[i]); + } + } + printk("\n"); + + break; + } + +fr_isr_exit: + + clear_bit(0,&card->in_isr); + card->hw_iface.poke_byte(card->hw, card->intr_type_off, 0x00); + return; +} + + + +/*=========================================================== + * rx_intr Receive interrupt handler. + * + * Description + * Upon receiveing an interrupt: + * 1. Check that the firmware is in sync with + * the driver. + * 2. Find an appropriate network interface + * based on the received dlci number. + * 3. Check that the netowrk interface exists + * and that it's setup properly. + * 4. Copy the data into an skb buffer. + * 5. Check the packet type and take + * appropriate acton: UPD, API, ARP or Data. + */ + +static void rx_intr (sdla_t* card) +{ + fr_rx_buf_ctl_t frbuf; + fr_channel_t* chan; + struct sk_buff* skb; + netdevice_t* dev; + void* buf; + unsigned dlci, len, offs, len_incl_hdr; + int i, udp_type; + + card->hw_iface.peek(card->hw, card->rxmb_off, &frbuf, sizeof(frbuf)); + /* Check that firmware buffers are in sync */ + if (frbuf.flag != 0x01) { + unsigned char str[8]; + printk(KERN_INFO + "%s: corrupted Rx buffer @ 0x%X, flag = 0x%02X!\n", + card->devname, (unsigned)card->rxmb_off, frbuf.flag); + card->hw_iface.peek(card->hw, card->intr_type_off+0x28, str, 8); + printk(KERN_INFO "%s: ID Bytes = ",card->devname); + for(i = 0; i < 8; i ++) + printk("0x%02X ", str[i]); + + printk("\n"); + + ++card->statistics.rx_intr_corrupt_rx_bfr; + + /* Bug Fix: Mar 6 2000 + * If we get a corrupted mailbox, it means that driver + * is out of sync with the firmware. There is no recovery. + * If we don't turn off all interrupts for this card + * the machine will crash. + */ + printk(KERN_INFO "%s: Critical router failure ...!!!\n", card->devname); + printk(KERN_INFO "Please contact Sangoma Technologies !\n"); + fr_set_intr_mode(card, 0, 0, 0); + return; + } + + len = frbuf.length; + dlci = frbuf.dlci; + offs = frbuf.offset; + /* Find the network interface for this packet */ + dev = find_channel(card, dlci); + + + /* Check that the network interface is active and + * properly setup */ + if (dev == NULL) { + if( net_ratelimit()) { + printk(KERN_INFO "%s: rx_isr: received data on unconfigured DLCI %d!\n", + card->devname, dlci); + } + ++card->statistics.rx_intr_on_orphaned_DLCI; + ++card->wandev.stats.rx_dropped; + goto rx_done; + } + + if ((chan = dev->priv) == NULL){ + if( net_ratelimit()) { + printk(KERN_INFO "%s: rx_isr: received data on unconfigured DLCI %d!\n", + card->devname, dlci); + } + ++card->statistics.rx_intr_on_orphaned_DLCI; + ++card->wandev.stats.rx_dropped; + goto rx_done; + } + + if (!is_dev_running(dev)){ + + ++chan->ifstats.rx_dropped; + + if (net_ratelimit()) { + printk(KERN_INFO + "%s: rx_isr: no dev running!\n", + card->devname); + } + + chan->drvstats_rx_intr. + rx_intr_dev_not_started ++; + + goto rx_done; + } + + skb = wan_skb_alloc(len+2); + if (skb == NULL){ + ++chan->ifstats.rx_dropped; + if (net_ratelimit()) { + printk(KERN_INFO + "%s: rx_isr: no socket buffers available!\n", + card->devname); + } + chan->drvstats_rx_intr.rx_intr_no_socket ++; + goto rx_done; + } + + + /* Copy data from the board into the socket buffer */ + if ((offs + len) > card->u.f.rx_top_off + 1) { + unsigned tmp = card->u.f.rx_top_off - offs + 1; + + buf = skb_put(skb, tmp); + card->hw_iface.peek(card->hw, offs, buf, tmp); + offs = card->u.f.rx_base_off; + len -= tmp; + } + + buf = skb_put(skb, len); + card->hw_iface.peek(card->hw, offs, buf, len); + + /* We got the packet from the bard. + * Check the packet type and take appropriate action */ + udp_type = udp_pkt_type( skb, card, UDP_PKT_FRM_NETWORK); + + if(udp_type != UDP_INVALID_TYPE) { + + /* UDP Debug packet received, store the + * packet and handle it in timer interrupt */ + skb_pull(skb, 1); + if (wanrouter_type_trans(skb, dev)){ + if(store_udp_mgmt_pkt(udp_type,UDP_PKT_FRM_NETWORK,card,skb,dlci)){ + + card->hw_iface.set_bit(card->hw, card->intr_perm_off, FR_INTR_TIMER); + + if (udp_type == UDP_FPIPE_TYPE){ + ++chan->drvstats_rx_intr.rx_intr_PIPE_request; + } + } + } + + }else if (chan->common.usedby == API) { + + /* We are in API mode. + * Add an API header to the RAW packet + * and queue it into a circular buffer. + * Then kick the fr_bh() bottom half handler */ + + api_rx_hdr_t* api_rx_hdr; + + skb_push(skb, sizeof(api_rx_hdr_t)); + api_rx_hdr = (api_rx_hdr_t*)&skb->data[0x00]; + api_rx_hdr->attr = frbuf.attr; + api_rx_hdr->time_stamp = frbuf.tmstamp; + + skb->protocol = htons(WP_PVC_PROT); + skb->mac.raw = skb->data; + skb->dev = dev; + skb->pkt_type = WAN_PACKET_DATA; + + if (wan_api_enqueue_skb(chan,skb) < 0){ + wan_skb_free(skb); + ++card->wandev.stats.rx_dropped; + goto rx_done; + } + + WAN_TASKLET_SCHEDULE((&chan->common.bh_task)); + + }else if (handle_IPXWAN(skb->data,chan->name,chan->enable_IPX, chan->network_number)){ + + if (chan->enable_IPX) { + + if (chan->tx_ipx){ + if (net_ratelimit()){ + printk(KERN_INFO + "%s: Dropping IPX data, tx busy : %s!\n", + card->devname,dev->name); + } + wan_skb_free(skb); + }else{ + /* Queue the ipx packet into a tx buffer + * which will be handeld by the tx interrupt */ + chan->tx_ipx=skb; + } + + atomic_inc(&card->u.f.tx_interrupts_pending); + card->hw_iface.set_bit(card->hw, chan->dlci_int_off, FR_INTR_TXRDY); + card->hw_iface.set_bit(card->hw, card->intr_perm_off, FR_INTR_TXRDY); + + }else{ + wan_skb_free(skb); + } + + } else if (is_arp(skb->data)) { + + /* ARP support enabled Mar 16 2000 + * Process incoming ARP reply/request, setup + * dynamic routes. */ + + if (chan->inarp_rx == WANOPT_YES){ + int err; + + err=process_ARP((arphdr_1490_t *)skb->data, card, dev); + + switch (err){ + + case 1: + /* Got request we must send replay. The skb + * packet contains the replay thus, queue it + * into a tx_arp queue, which will be tx on + * next tx interrupt */ + + if (chan->tx_arp){ + if (net_ratelimit()){ + printk(KERN_INFO "Warning: Dropping ARP Req, tx busy!\n"); + } + wan_skb_free(skb); + }else{ + /* Queue the arp packet into a tx buffer + * which will be handeld by the tx interrupt */ + chan->tx_arp=skb; + } + atomic_inc(&card->u.f.tx_interrupts_pending); + card->hw_iface.set_bit(card->hw, chan->dlci_int_off, FR_INTR_TXRDY); + card->hw_iface.set_bit(card->hw, card->intr_perm_off, FR_INTR_TXRDY); + break; + + default: + + if (err == -1 && net_ratelimit()){ + printk (KERN_INFO + "%s: Error processing ARP Packet.\n", + card->devname); + } + wan_skb_free(skb); + break; + } + }else{ + wan_skb_free(skb); + } + + } else if (skb->data[0] != chan->fr_encap_0) { + + switch (skb->data[0]){ + + case CISCO_UI: + printk(KERN_INFO "%s-%s: Changing data encapsulation to CISCO\n", + card->devname,dev->name); + chan->fr_encap_0 = CISCO_UI; + chan->fr_encap_1 = CISCO_IP; + goto rx_intr_receive_ok; + + case Q922_UI: + printk(KERN_INFO "%s-%s: Changing data encapsulation to IETF\n", + card->devname,dev->name); + chan->fr_encap_0 = Q922_UI; + chan->fr_encap_1 = NLPID_IP; + goto rx_intr_receive_ok; + + default: + + if (skb->data[0] != CISCO_INV && net_ratelimit()) { + printk(KERN_INFO + "%s: Rx non IETF/CISCO pkt : 0x%02X 0x%02X, dropping !\n", + card->devname,skb->data[0],skb->data[1]); + } + ++chan->drvstats_rx_intr.rx_intr_bfr_not_passed_to_stack; + ++chan->ifstats.rx_errors; + ++card->wandev.stats.rx_errors; + wan_skb_free(skb); + break; + } + + }else{ + +rx_intr_receive_ok: + + len_incl_hdr = skb->len; + /* Decapsulate packet and pass it up the + protocol stack */ + skb->dev = dev; + + if (chan->common.usedby == BRIDGE || chan->common.usedby == BRIDGE_NODE){ + + /* Make sure it's an Ethernet frame, otherwise drop it */ + if (!memcmp(skb->data, "\x03\x00\x80\x00\x80\xC2\x00\x07", 8)) { + skb_pull(skb, 8); + skb->protocol=eth_type_trans(skb,dev); + }else{ + ++chan->drvstats_rx_intr.rx_intr_bfr_not_passed_to_stack; + ++chan->ifstats.rx_errors; + ++card->wandev.stats.rx_errors; + + /* NC: Jan 02 2002 + * Memory leak bug fix, deallocate packet + * if this is not an ethernet frame */ + wan_skb_free(skb); + + goto rx_done; + } + }else{ + + /* remove hardware header */ + buf = skb_pull(skb, 1); + + skb->protocol=htons(ETH_P_IP); + + if (chan->fr_encap_0 == CISCO_UI && skb->data[0] == CISCO_IP){ + skb_pull(skb,1); + + }else if (!wanrouter_type_trans(skb, dev)) { + + /* can't decapsulate packet */ + wan_skb_free(skb); + + ++chan->drvstats_rx_intr.rx_intr_bfr_not_passed_to_stack; + ++chan->ifstats.rx_errors; + ++card->wandev.stats.rx_errors; + goto rx_done; + } + + skb->mac.raw = skb->data; + } + + + /* Send a packed up the IP stack */ + DEBUG_SUB_MEM(skb->truesize); + +#if defined(LINUX_2_4) || defined(LINUX_2_6) + if (netif_rx(skb) == NET_RX_DROP){ + ++chan->ifstats.rx_dropped; + }else{ + ++chan->drvstats_rx_intr.rx_intr_bfr_passed_to_stack; + ++chan->ifstats.rx_packets; + ++card->wandev.stats.rx_packets; + chan->ifstats.rx_bytes += len_incl_hdr; + card->wandev.stats.rx_bytes += len_incl_hdr; + } +#else + netif_rx(skb); + ++chan->drvstats_rx_intr.rx_intr_bfr_passed_to_stack; + ++chan->ifstats.rx_packets; + ++card->wandev.stats.rx_packets; + chan->ifstats.rx_bytes += len_incl_hdr; + card->wandev.stats.rx_bytes += len_incl_hdr; +#endif + } + +rx_done: + + /* Release buffer element and calculate a pointer to the next one */ + frbuf.flag = 0; + card->hw_iface.poke(card->hw, card->rxmb_off, &frbuf, sizeof(frbuf)); + card->rxmb_off += sizeof(frbuf); + if (card->rxmb_off > card->u.f.rxmb_last_off){ + card->rxmb_off = card->u.f.rxmb_base_off; + } + +} + +/*================================================================== + * tx_intr: Transmit interrupt handler. + * + * Rationale: + * If the board is busy transmitting, if_send() will + * buffers a single packet and turn on + * the tx interrupt. Tx interrupt will be called + * by the board, once the firmware can send more + * data. Thus, no polling is required. + * + * Description: + * Tx interrupt is called for each + * configured dlci channel. Thus: + * 1. Obtain the netowrk interface based on the + * dlci number. + * 2. Check that network interface is up and + * properly setup. + * 3. Check for a buffered packed. + * 4. Transmit the packed. + * 5. If we are in WANPIPE mode, mark the + * NET_BH handler. + * 6. If we are in API mode, kick + * the AF_WANPIPE socket for more data. + * + */ +static void tx_intr(sdla_t *card) +{ + fr508_flags_t flags; + unsigned long bctl_off; + fr_tx_buf_ctl_t bctl; + netdevice_t* dev; + fr_channel_t* chan; + + card->hw_iface.peek(card->hw, card->flags_off, &flags, sizeof(flags)); + + /* Alex Apr 8 2004 Sangoma ISA card */ + bctl_off = flags.tse_offs; + card->hw_iface.peek(card->hw, bctl_off, &bctl, sizeof(bctl)); + + /* Find the structure and make it unbusy */ + dev = find_channel(card, flags.dlci); + if (dev == NULL){ + printk(KERN_INFO "%s: No Dev found in TX Interrupt.\n", + card->devname); + goto end_of_tx_intr; + } + + if ((chan = dev->priv) == NULL){ + printk(KERN_INFO "%s: No DLCI priv area found in TX Interrupt\n", + card->devname); + goto end_of_tx_intr; + } + + if((!chan->transmit_length || !chan->delay_skb) && + !chan->tx_ipx && !chan->tx_arp) { + printk(KERN_INFO "%s: tx int error - transmit length zero\n", + card->wandev.name); + + chan->transmit_length=0; + if (chan->delay_skb){ + wan_skb_free(chan->delay_skb); + chan->delay_skb=NULL; + } + if (chan->tx_arp){ + wan_skb_free(chan->tx_arp); + chan->tx_arp=NULL; + } + if (chan->tx_ipx){ + wan_skb_free(chan->tx_ipx); + chan->tx_ipx=NULL; + } + goto tx_wakeup_net_dev; + } + + if (!(dev->flags&IFF_UP) || + chan->common.state != WAN_CONNECTED || + card->wandev.state != WAN_CONNECTED){ + + chan->transmit_length=0; + if (chan->delay_skb){ + wan_skb_free(chan->delay_skb); + chan->delay_skb=NULL; + } + if (chan->tx_arp){ + wan_skb_free(chan->tx_arp); + chan->tx_arp=NULL; + } + if (chan->tx_ipx){ + wan_skb_free(chan->tx_ipx); + chan->tx_ipx=NULL; + } + bctl.flag = 0xA0; + card->hw_iface.poke(card->hw, bctl_off, &bctl, sizeof(bctl)); + goto tx_wakeup_net_dev; + } + + /* If the 'if_send()' procedure is currently checking the 'tbusy' + status, then we cannot transmit. Instead, we configure the microcode + so as to re-issue this transmit interrupt at a later stage. + */ + if (test_bit(SEND_TXIRQ_CRIT, (void*)&card->wandev.critical)) { + + bctl.flag = 0xA0; + card->hw_iface.poke(card->hw, bctl_off, &bctl, sizeof(bctl)); + card->hw_iface.set_bit(card->hw, chan->dlci_int_off, FR_INTR_TXRDY); + DEBUG_EVENT("TX INTER RETRY \n"); + return; + + }else if (chan->tx_arp){ + bctl.dlci = flags.dlci; + bctl.length = chan->tx_arp->len; + card->hw_iface.poke(card->hw, + bctl.offset, + chan->tx_arp->data, + chan->tx_arp->len); + bctl.flag = 0xC0; + card->hw_iface.poke(card->hw, bctl_off, &bctl, sizeof(bctl)); + ++chan->ifstats.tx_packets; + ++card->wandev.stats.tx_packets; + chan->ifstats.tx_bytes += chan->tx_arp->len; + card->wandev.stats.tx_bytes += chan->tx_arp->len; + + wan_skb_free(chan->tx_arp); + chan->tx_arp=NULL; + + chan->route_flag = ADD_ROUTE; + trigger_fr_poll (dev); + + /* If there is not other data to be transmitted by + * the tx interrupt then, wakup the network + * interface. Otherwise, let tx interrupt retrigger. + */ + + if (!chan->transmit_length && !chan->tx_ipx){ + goto tx_wakeup_net_dev; + }else{ + card->hw_iface.set_bit(card->hw, chan->dlci_int_off, FR_INTR_TXRDY); + } + + + }else if (chan->tx_ipx){ + bctl.dlci = flags.dlci; + bctl.length = chan->tx_ipx->len+chan->fr_header_len; + card->hw_iface.poke(card->hw, + bctl.offset, + chan->tx_ipx->data, + chan->tx_ipx->len); + bctl.flag = 0xC0; + card->hw_iface.poke(card->hw, bctl_off, &bctl, sizeof(bctl)); + ++chan->ifstats.tx_packets; + ++card->wandev.stats.tx_packets; + chan->ifstats.tx_bytes += chan->tx_ipx->len; + card->wandev.stats.tx_bytes += chan->tx_ipx->len; + + wan_skb_free(chan->tx_ipx); + chan->tx_ipx=NULL; + + /* If there is not other data to be transmitted by + * the tx interrupt then, wakup the network + * interface. Otherwise, let tx interrupt retrigger. + */ + if (!chan->transmit_length){ + goto tx_wakeup_net_dev; + }else{ + card->hw_iface.set_bit(card->hw, chan->dlci_int_off, FR_INTR_TXRDY); + //bctl->flag = 0xA0; + } + + }else{ + bctl.dlci = flags.dlci; + bctl.length = chan->transmit_length+chan->fr_header_len; + card->hw_iface.poke(card->hw, + fr_send_hdr(card,bctl.dlci,bctl.offset), + chan->delay_skb->data, + chan->delay_skb->len); + bctl.flag = 0xC0; + card->hw_iface.poke(card->hw, bctl_off, &bctl, sizeof(bctl)); + ++chan->ifstats.tx_packets; + ++card->wandev.stats.tx_packets; + chan->ifstats.tx_bytes += chan->transmit_length; + card->wandev.stats.tx_bytes += chan->transmit_length; + + /* We must free an sk buffer, which we used + * for delayed transmission; Otherwise, the sock + * will run out of memory */ + wan_skb_free(chan->delay_skb); + + chan->delay_skb = NULL; + chan->transmit_length = 0; + +#if defined(LINUX_2_4) || defined(LINUX_2_6) + dev->trans_start = jiffies; +#endif + +tx_wakeup_net_dev: + + if (is_queue_stopped(dev)){ + /* If using API, than wakeup socket BH handler */ + if (chan->common.usedby == API){ + start_net_queue(dev); + wan_wakeup_api(chan); + }else{ + wake_net_dev(dev); + } + } + } + + if (!chan->transmit_length){ + if (is_queue_stopped(dev)){ + /* If using API, than wakeup socket BH handler */ + if (chan->common.usedby == API){ + start_net_queue(dev); + wan_wakeup_api(chan); + }else{ + wake_net_dev(dev); + } + } + } + +end_of_tx_intr: + + /* if any other interfaces have transmit interrupts pending, + * do not disable the global transmit interrupt */ + atomic_dec(&card->u.f.tx_interrupts_pending); + if(atomic_read(&card->u.f.tx_interrupts_pending)<=0){ + atomic_set(&card->u.f.tx_interrupts_pending,0); + card->hw_iface.clear_bit(card->hw, card->intr_perm_off, FR_INTR_TXRDY); + } +} + + +/*============================================================================ + * timer_intr: Timer interrupt handler. + * + * Rationale: + * All commans must be executed within the timer + * interrupt since no two commands should execute + * at the same time. + * + * Description: + * The timer interrupt is used to: + * 1. Processing udp calls from 'fpipemon'. + * 2. Processing update calls from /proc file system + * 3. Reading board-level statistics for + * updating the proc file system. + * 4. Sending inverse ARP request packets. + * 5. Configure a dlci/channel. + * 6. Unconfigure a dlci/channel. (Node only) + */ + +static void timer_intr(sdla_t *card) +{ + + /* UDP Debuging: fpipemon call */ + if (card->u.f.timer_int_enabled & TMR_INT_ENABLED_UDP) { + if(card->u.f.udp_type == UDP_FPIPE_TYPE) { + process_udp_mgmt_pkt(card,NULL); + card->u.f.timer_int_enabled &= + ~TMR_INT_ENABLED_UDP; + } + } + + /* /proc update call : triggered from update() */ + if (card->u.f.timer_int_enabled & TMR_INT_ENABLED_UPDATE) { + fr_get_err_stats(card); + fr_get_stats(card, NULL); + if (IS_TE1_CARD(card)) { + /* TE1 Update T1/E1 alarms */ + card->wandev.fe_iface.read_alarm(&card->fe, 0); + /* TE1 Update T1/E1 perfomance counters */ + card->wandev.fe_iface.read_pmon(&card->fe, 0); + }else if (IS_56K_CARD(card)) { + /* 56K Update CSU/DSU alarms */ + card->wandev.fe_iface.read_alarm(&card->fe, 1); + } + card->update_comms_stats = 0; + card->u.f.timer_int_enabled &= ~TMR_INT_ENABLED_UPDATE; + } + + /* TE timer interrupt */ + if (card->u.f.timer_int_enabled & TMR_INT_ENABLED_TE){ + card->wandev.fe_iface.polling(&card->fe); + card->u.f.timer_int_enabled &= ~TMR_INT_ENABLED_TE; + } + + /* /proc update call : triggered from update() */ + if (card->u.f.timer_int_enabled & TMR_INT_ENABLED_UPDATE_DLCI){ + fr_get_stats(card, NULL); + fr_get_stats(card, card->u.f.update_dlci); + card->update_comms_stats = 0; + card->u.f.update_dlci = NULL; + card->u.f.timer_int_enabled &= ~TMR_INT_ENABLED_UPDATE_DLCI; + } + + /* Update the channel state call. This is call is + * triggered by if_send() function */ + if (card->u.f.timer_int_enabled & TMR_INT_ENABLED_UPDATE_STATE){ + netdevice_t *dev; + if (card->wandev.state == WAN_CONNECTED){ + struct wan_dev_le *devle; + WAN_LIST_FOREACH(devle, &card->wandev.dev_head, dev_link){ + fr_channel_t *chan; + + dev = WAN_DEVLE2DEV(devle); + + if (!dev || !wan_netif_priv(dev)) continue; + chan = wan_netif_priv(dev); + if (chan->common.state != WAN_CONNECTED){ + update_chan_state(dev); + } + } + } + card->u.f.timer_int_enabled &= ~TMR_INT_ENABLED_UPDATE_STATE; + } + + + /* Transmit ARP packets */ + if (card->u.f.timer_int_enabled & TMR_INT_ENABLED_ARP){ + int i=0; + netdevice_t *dev; + + if (card->u.f.arp_dev == NULL){ + card->u.f.arp_dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + } + + dev = card->u.f.arp_dev; + + for (;;){ + fr_channel_t *chan = dev->priv; + + /* If the interface is brought down cancel sending In-ARPs */ + if (!(dev->flags&IFF_UP)){ + clear_bit(0,&chan->inarp_ready); + } + + if (test_bit(0,&chan->inarp_ready)){ + int arp_err; + + if (check_tx_status(card,dev)){ + set_bit(ARP_CRIT,&card->wandev.critical); + break; + } + + arp_err = send_inarp_request(card,dev); + + if (arp_err == 0){ + /* Arp Send successfully */ + clear_bit(0,&chan->inarp_ready); + trigger_fr_arp(dev); + + }else if(arp_err == -EINVAL){ + /* Arp send not supported */ + clear_bit(0,&chan->inarp_ready); + chan->inarp = INARP_NONE; + printk(KERN_INFO + "%s: Error in sending InARP. InARP not supported on %s!\n", + card->devname,dev->name); + + }else{ + /* Arp Send failed + * Retrigger the arp transmission at the later + * time and keep the ARP_CRIT flag critical */ + break; + } + + /* No matter what happend to the arp send on that + * particular interface, we must go throught and + * check all other interfaces, on the next time */ + dev = move_dev_to_next(card,dev); + break; + }else{ + dev = move_dev_to_next(card,dev); + } + + /* If we came to the last interface and all arps have + * been sent, then stop the timer */ + if (++i == atomic_read(&card->wandev.if_cnt)){ + card->u.f.timer_int_enabled &= ~TMR_INT_ENABLED_ARP; + clear_bit(ARP_CRIT,&card->wandev.critical); + break; + } + } + card->u.f.arp_dev = dev; + } + + if (!card->u.f.timer_int_enabled){ + card->hw_iface.clear_bit(card->hw, card->intr_perm_off, FR_INTR_TIMER); + } +} + + +/*============================================================================ + * spur_intr: Spurious interrupt handler. + * + * Description: + * We don't know this interrupt. + * Print a warning. + */ + +static void spur_intr (sdla_t* card) +{ + if (net_ratelimit()){ + printk(KERN_INFO "%s: spurious interrupt!\n", card->devname); + } +} + + +//FIXME: Fix the IPX in next version +/*=========================================================================== + * Return 0 for non-IPXWAN packet + * 1 for IPXWAN packet or IPX is not enabled! + * FIXME: Use a IPX structure here not offsets + */ +static int handle_IPXWAN(unsigned char *sendpacket, + char *devname, unsigned char enable_IPX, + unsigned long network_number) +{ + int i; + + if( sendpacket[1] == 0x00 && sendpacket[2] == 0x80 && + sendpacket[6] == 0x81 && sendpacket[7] == 0x37) { + + /* It's an IPX packet */ + if (!enable_IPX){ + /* Return 1 so we don't pass it up the stack. */ + //FIXME: Take this out when IPX is fixed + if (net_ratelimit()){ + printk (KERN_INFO + "%s: WARNING: Unsupported IPX packet received and dropped\n", + devname); + } + return 1; + } + } else { + /* It's not IPX so return and pass it up the stack. */ + return 0; + } + + if( sendpacket[24] == 0x90 && sendpacket[25] == 0x04){ + /* It's IPXWAN */ + + if( sendpacket[10] == 0x02 && sendpacket[42] == 0x00){ + + /* It's a timer request packet */ + printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n", + devname); + + /* Go through the routing options and answer no to every + * option except Unnumbered RIP/SAP + */ + for(i = 49; sendpacket[i] == 0x00; i += 5){ + /* 0x02 is the option for Unnumbered RIP/SAP */ + if( sendpacket[i + 4] != 0x02){ + sendpacket[i + 1] = 0; + } + } + + /* Skip over the extended Node ID option */ + if( sendpacket[i] == 0x04 ){ + i += 8; + } + + /* We also want to turn off all header compression opt. + */ + for(; sendpacket[i] == 0x80 ;){ + sendpacket[i + 1] = 0; + i += (sendpacket[i + 2] << 8) + (sendpacket[i + 3]) + 4; + } + + /* Set the packet type to timer response */ + sendpacket[42] = 0x01; + + printk(KERN_INFO "%s: Sending IPXWAN Timer Response\n", + devname); + + } else if( sendpacket[42] == 0x02 ){ + + /* This is an information request packet */ + printk(KERN_INFO + "%s: Received IPXWAN Information Request packet\n", + devname); + + /* Set the packet type to information response */ + sendpacket[42] = 0x03; + + /* Set the router name */ + sendpacket[59] = 'F'; + sendpacket[60] = 'P'; + sendpacket[61] = 'I'; + sendpacket[62] = 'P'; + sendpacket[63] = 'E'; + sendpacket[64] = '-'; + sendpacket[65] = CVHexToAscii(network_number >> 28); + sendpacket[66] = CVHexToAscii((network_number & 0x0F000000)>> 24); + sendpacket[67] = CVHexToAscii((network_number & 0x00F00000)>> 20); + sendpacket[68] = CVHexToAscii((network_number & 0x000F0000)>> 16); + sendpacket[69] = CVHexToAscii((network_number & 0x0000F000)>> 12); + sendpacket[70] = CVHexToAscii((network_number & 0x00000F00)>> 8); + sendpacket[71] = CVHexToAscii((network_number & 0x000000F0)>> 4); + sendpacket[72] = CVHexToAscii(network_number & 0x0000000F); + for(i = 73; i < 107; i+= 1) + { + sendpacket[i] = 0; + } + + printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n", + devname); + } else { + + printk(KERN_INFO "%s: Unknown IPXWAN packet!\n",devname); + return 0; + } + + /* Set the WNodeID to our network address */ + sendpacket[43] = (unsigned char)(network_number >> 24); + sendpacket[44] = (unsigned char)((network_number & 0x00FF0000) >> 16); + sendpacket[45] = (unsigned char)((network_number & 0x0000FF00) >> 8); + sendpacket[46] = (unsigned char)(network_number & 0x000000FF); + + return 1; + } + + /* If we get here, its an IPX-data packet so it'll get passed up the + * stack. + * switch the network numbers + */ + switch_net_numbers(&sendpacket[8], network_number ,1); + return 0; +} +/*============================================================================ + * process_route + * + * Rationale: + * If the interface goes down, or we receive an ARP request, + * we have to change the network interface ip addresses. + * This cannot be done within the interrupt. + * + * Description: + * + * This routine is called as a polling routine to dynamically + * add/delete routes negotiated by inverse ARP. It is in this + * "task" because we don't want routes to be added while in + * interrupt context. + * + * Usage: + * This function is called by fr_poll() polling funtion. + */ + +static void process_route (netdevice_t *dev) +{ + fr_channel_t *chan = dev->priv; + sdla_t *card = chan->card; + + struct ifreq if_info; + struct sockaddr_in *if_data; + mm_segment_t fs = get_fs(); + u32 ip_tmp; + int err; + + + switch(chan->route_flag){ + + case ADD_ROUTE: + + /* Set remote addresses */ + memset(&if_info, 0, sizeof(if_info)); + strcpy(if_info.ifr_name, dev->name); + + set_fs(get_ds()); /* get user space block */ + + if_data = (struct sockaddr_in *)&if_info.ifr_dstaddr; + if_data->sin_addr.s_addr = chan->ip_remote; + if_data->sin_family = AF_INET; + err = wp_devinet_ioctl( SIOCSIFDSTADDR, &if_info ); + + set_fs(fs); /* restore old block */ + + if (err) { + + printk(KERN_INFO + "%s: Route Add failed. Error: %d\n", + card->devname,err); + printk(KERN_INFO "%s: Address: %u.%u.%u.%u\n", + chan->name, NIPQUAD(chan->ip_remote)); + + }else { + printk(KERN_INFO "%s: Route Added Successfully: %u.%u.%u.%u\n", + card->devname,NIPQUAD(chan->ip_remote)); + chan->route_flag = ROUTE_ADDED; + } + break; + + case REMOVE_ROUTE: + + /* Set remote addresses */ + memset(&if_info, 0, sizeof(if_info)); + strcpy(if_info.ifr_name, dev->name); + + ip_tmp = get_ip_address(dev,WAN_POINTOPOINT_IP); + + set_fs(get_ds()); /* get user space block */ + + if_data = (struct sockaddr_in *)&if_info.ifr_dstaddr; + if_data->sin_addr.s_addr = 0; + if_data->sin_family = AF_INET; + err = wp_devinet_ioctl( SIOCSIFDSTADDR, &if_info ); + + set_fs(fs); + + if (err) { + + printk(KERN_INFO + "%s: Deleting of route failed. Error: 0x%x", + card->devname,err); + printk(KERN_INFO "%s: Address: %u.%u.%u.%u\n", + dev->name,NIPQUAD(chan->ip_remote) ); + + } else { + + printk(KERN_INFO "%s: Route Removed Sucessfuly: %u.%u.%u.%u\n", + card->devname,NIPQUAD(ip_tmp)); + chan->route_flag = NO_ROUTE; + } + break; + + } /* Case Statement */ + +} + + + +/****** Frame Relay Firmware-Specific Functions *****************************/ + +/*============================================================================ + * Read firmware code version. + * o fill string str with firmware version info. + */ +static int fr_read_version (sdla_t* card, char* str) +{ + wan_mbox_t* mbox = &card->wan_mbox; + int retry = MAX_CMD_RETRY; + int err; + + do + { + mbox->wan_command = FR_READ_CODE_VERSION; + mbox->wan_data_len = 0; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mbox); + } while (err && retry-- && fr_event(card, err, mbox)); + + if (!err && str) { + int len = mbox->wan_data_len; + memcpy(str, mbox->wan_data, len); + str[len] = '\0'; + } + return err; +} + +/*============================================================================ + * Set global configuration. + */ +static int fr_configure (sdla_t* card, fr_conf_t *conf) +{ + wan_mbox_t* mb = &card->wan_mbox; + int retry = MAX_CMD_RETRY; + int dlci_num = card->u.f.dlci_num; + int err, i; + + WAN_MBOX_INIT(mb); + do + { + memcpy(mb->wan_data, conf, sizeof(fr_conf_t)); + + if (dlci_num){ + for (i = 0; i < dlci_num; ++i){ + ((fr_conf_t*)mb->wan_data)->dlci[i] = + card->u.f.node_dlci[i]; + } + } + mb->wan_command = FR_SET_CONFIG; + mb->wan_data_len = + sizeof(fr_conf_t) + dlci_num * sizeof(short); + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + + } while (err && retry-- && fr_event(card, err, mb)); + + /*NC Oct 12 2000 */ + if (err != CMD_OK){ + printk(KERN_INFO "%s: Frame Relay Configuration Failed: rc=0x%x\n", + card->devname,err); + } + + return err; +} + +/*============================================================================ + * Set DLCI configuration. + */ +static int fr_dlci_configure (sdla_t* card, fr_dlc_conf_t *conf, unsigned dlci) +{ + wan_mbox_t* mb = &card->wan_mbox; + int retry = MAX_CMD_RETRY; + unsigned char *buf=mb->wan_data; + int err; + + WAN_MBOX_INIT(mb); + do + { + memcpy(buf, conf, sizeof(fr_dlc_conf_t)); + mb->wan_fr_dlci = (unsigned short) dlci; + mb->wan_command = FR_SET_CONFIG; + mb->wan_data_len = sizeof(fr_dlc_conf_t); + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + } while (err && retry--); + + return err; +} +/*============================================================================ + * Set interrupt mode. + */ +static int fr_set_intr_mode (sdla_t* card, unsigned mode, unsigned mtu, + unsigned short timeout) +{ + wan_mbox_t* mb = &card->wan_mbox; + fr508_intr_ctl_t* ictl = (void*)mb->wan_data; + int retry = MAX_CMD_RETRY; + int err; + + WAN_MBOX_INIT(mb); + do + { + memset(ictl, 0, sizeof(fr508_intr_ctl_t)); + ictl->mode = mode; + ictl->tx_len = mtu; + ictl->irq = card->wandev.irq; // ALEX_TODAY card->hw.irq; + + /* indicate timeout on timer */ + if (mode & 0x20) ictl->timeout = timeout; + + mb->wan_data_len = sizeof(fr508_intr_ctl_t); + mb->wan_command = FR_SET_INTR_MODE; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + + } while (err && retry-- && fr_event(card, err, mb)); + + return err; +} + +/*============================================================================ + * Enable communications. + */ +static int fr_comm_enable (sdla_t* card) +{ + wan_mbox_t* mb = &card->wan_mbox; + int retry = MAX_CMD_RETRY; + int err; + + WAN_MBOX_INIT(mb); + do + { + mb->wan_command = FR_COMM_ENABLE; + mb->wan_data_len = 0; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + } while (err && retry-- && fr_event(card, err, mb)); + + return err; +} + +/*============================================================================ + * fr_comm_disable + * + * Warning: This functin is called by the shutdown() procedure. It is void + * since dev->priv are has already been deallocated and no + * error checking is possible using fr_event() function. + */ +static void fr_comm_disable (sdla_t* card) +{ + wan_mbox_t* mb = &card->wan_mbox; + int retry = MAX_CMD_RETRY; + int err; + + fr_set_intr_mode(card, 0, 0, 0); + + WAN_MBOX_INIT(mb); + do { + mb->wan_command = FR_SET_MODEM_STATUS; + mb->wan_data_len = 1; + mb->wan_data[0] = 0; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + } while (err && retry--); + + retry = MAX_CMD_RETRY; + WAN_MBOX_INIT(mb); + do + { + mb->wan_command = FR_COMM_DISABLE; + mb->wan_data_len = 0; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + } while (err && retry--); + + return; +} + + + +/*============================================================================ + * Get communications error statistics. + */ +static int fr_get_err_stats (sdla_t* card) +{ + wan_mbox_t* mb = &card->wan_mbox; + int retry = MAX_CMD_RETRY; + int err; + + WAN_MBOX_INIT(mb); + do + { + mb->wan_command = FR_READ_ERROR_STATS; + mb->wan_data_len = 0; + mb->wan_fr_dlci = 0; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + } while (err && retry-- && fr_event(card, err, mb)); + + if (!err) { + fr_comm_stat_t* stats = (void*)mb->wan_data; + card->wandev.stats.rx_over_errors = stats->rx_overruns; + card->wandev.stats.rx_crc_errors = stats->rx_bad_crc; + card->wandev.stats.rx_missed_errors = stats->rx_aborts; + card->wandev.stats.rx_length_errors = stats->rx_too_long; + card->wandev.stats.tx_aborted_errors = stats->tx_aborts; + + } + + return err; +} + +/*============================================================================ + * Get statistics. + */ +static int fr_get_stats (sdla_t* card, fr_channel_t* chan) +{ + wan_mbox_t* mb = &card->wan_mbox; + int retry = MAX_CMD_RETRY; + int err; + int dlci = 0; + + if (chan && chan->common.state == WAN_CONNECTED){ + dlci = chan->dlci; + } + + WAN_MBOX_INIT(mb); + do { + mb->wan_command = FR_READ_STATISTICS; + mb->wan_data_len = 0; + mb->wan_fr_dlci = dlci; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + } while (err && retry-- && fr_event(card, err, mb)); + + if (!err) { + if (dlci == 0){ + fr_link_stat_t* stats = (void*)mb->wan_data; + card->wandev.stats.rx_frame_errors = + stats->rx_bad_format; + card->wandev.stats.rx_dropped = + stats->rx_dropped + + stats->rx_dropped2; + }else{ + fr_dlci_stat_t* stats = (void*)mb->wan_data; + chan->rx_DE_set = stats->rx_DE_set; + } + } + + return err; +} + +/*============================================================================ + * Add DLCI(s) (Access Node only!). + * This routine will perform the ADD_DLCIs command for the specified DLCI. + */ +static int fr_add_dlci (sdla_t* card, int dlci) +{ + wan_mbox_t* mb = &card->wan_mbox; + int retry = MAX_CMD_RETRY; + int err; + + WAN_MBOX_INIT(mb); + do + { + unsigned short* dlci_list = (void*)mb->wan_data; + + mb->wan_data_len = sizeof(short); + dlci_list[0] = dlci; + mb->wan_command = FR_ADD_DLCI; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + + } while (err && retry-- && fr_event(card, err, mb)); + + return err; +} + +/*============================================================================ + * Activate DLCI(s) (Access Node only!). + * This routine will perform the ACTIVATE_DLCIs command with a DLCI number. + */ +static int fr_activate_dlci (sdla_t* card, int dlci) +{ + wan_mbox_t* mb = &card->wan_mbox; + int retry = MAX_CMD_RETRY; + int err; + + WAN_MBOX_INIT(mb); + do + { + unsigned short* dlci_list = (void*)mb->wan_data; + + mb->wan_data_len = sizeof(short); + dlci_list[0] = dlci; + mb->wan_command = FR_ACTIVATE_DLCI; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + + } while (err && retry-- && fr_event(card, err, mb)); + + return err; +} + +/*============================================================================ + * Delete DLCI(s) (Access Node only!). + * This routine will perform the DELETE_DLCIs command with a DLCI number. + */ +static int fr_delete_dlci (sdla_t* card, int dlci) +{ + wan_mbox_t* mb = &card->wan_mbox; + int retry = MAX_CMD_RETRY; + int err; + + WAN_MBOX_INIT(mb); + do + { + unsigned short* dlci_list = (void*)mb->wan_data; + + mb->wan_data_len = sizeof(short); + dlci_list[0] = dlci; + mb->wan_command = FR_DELETE_DLCI; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + + } while (err && retry-- && fr_event(card, err, mb)); + + return err; +} + +/*============================================================================ + * Issue in-channel signalling frame. + */ +static int fr_issue_isf (sdla_t* card, int isf) +{ + wan_mbox_t* mb = &card->wan_mbox; + int retry = MAX_CMD_RETRY; + int err; + + WAN_MBOX_INIT(mb); + do + { + mb->wan_data[0] = isf; + mb->wan_data_len = 1; + mb->wan_command = FR_ISSUE_IS_FRAME; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + } while (err && retry-- && fr_event(card, err, mb)); + + return err; +} + + +/*============================================================================ + * Issue in-channel signalling frame. + */ + +static unsigned int fr_send_hdr (sdla_t*card, int dlci, unsigned int offset) +{ + netdevice_t *dev = find_channel(card,dlci); + fr_channel_t *chan; + + if (!dev || !(chan=dev->priv)) + return offset; + + if (chan->fr_header_len){ + card->hw_iface.poke(card->hw, offset, chan->fr_header, chan->fr_header_len); + } + + return offset+chan->fr_header_len; +} + +/*============================================================================ + * Send a frame on a selected DLCI. + */ +static int fr_send_data_header (sdla_t* card, int dlci, unsigned char attr, int len, + void *buf, unsigned char hdr_len,char lock) +{ + wan_mbox_t* mb = &card->wan_mbox; + int retry = 2;//MAX_CMD_RETRY; + int err=0,event_err=0; + + WAN_MBOX_INIT(mb); + do + { + mb->wan_fr_dlci = dlci; + mb->wan_fr_attr = attr; + mb->wan_data_len = len+hdr_len; + mb->wan_command = FR_WRITE; + err = card->hw_iface.cmd(card->hw, card->mbox_off + 0x800, mb); + + switch (err){ + + case 0: + case FRRES_DLCI_INACTIVE: + case FRRES_CIR_OVERFLOW: + case FRRES_BUFFER_OVERFLOW: + case FRRES_TOO_LONG: + event_err=0; + break; + + default: + if (lock){ + unsigned long flags; + s508_s514_send_event_lock(card,&flags); + event_err=fr_event(card, err, mb); + s508_s514_send_event_unlock(card,&flags); + }else{ + event_err=fr_event(card, err, mb); + } + break; + } + } while (err && retry-- && event_err); + + if (!err) { + fr_tx_buf_ctl_t frbuf; + unsigned long frbuf_off = *(unsigned long*)mb->wan_data; + + card->hw_iface.peek(card->hw, frbuf_off, &frbuf, sizeof(frbuf)); + + card->hw_iface.poke(card->hw, fr_send_hdr(card,dlci,frbuf.offset), buf, len); + frbuf.flag = 0x01; + card->hw_iface.poke(card->hw, frbuf_off, &frbuf, sizeof(frbuf)); + } + + return err; +} + +static int fr_send (sdla_t* card, int dlci, unsigned char attr, int len, + void *buf) +{ + wan_mbox_t* mb = &card->wan_mbox; + int retry = MAX_CMD_RETRY; + int err; + + WAN_MBOX_INIT(mb); + do + { + mb->wan_fr_dlci = dlci; + mb->wan_fr_attr = attr; + mb->wan_data_len = len; + mb->wan_command = FR_WRITE; + err = card->hw_iface.cmd(card->hw, card->mbox_off + 0x800, mb); + } while (err && retry-- && fr_event(card, err, mb)); + + if (!err) { + fr_tx_buf_ctl_t frbuf; + unsigned long frbuf_off = *(unsigned long*)mb->wan_data; + + card->hw_iface.peek(card->hw, frbuf_off, &frbuf, sizeof(frbuf)); + + card->hw_iface.poke(card->hw, frbuf.offset, buf, len); + frbuf.flag = 0x01; + card->hw_iface.poke(card->hw, frbuf_off, &frbuf, sizeof(frbuf)); + + } + + return err; +} + + +/*============================================================================ + * TE1 + * Read value from PMC register. + */ +//static unsigned char read_front_end_reg (void* card1, unsigned short reg) +static unsigned char read_front_end_reg (void* card1, ...) +{ + va_list args; + sdla_t *card = (sdla_t*)card1; + wan_mbox_t *mb = &card->wan_mbox; + char *data = mb->wan_data; + u16 reg; + int err; + int retry=15; + + va_start(args, card1); + reg = (u16)va_arg(args, int); + va_end(args); + WAN_MBOX_INIT(mb); + do { + ((FRONT_END_REG_STRUCT *)data)->register_number = (unsigned short)reg; + mb->wan_data_len = sizeof(FRONT_END_REG_STRUCT); + mb->wan_command = READ_FRONT_END_REGISTER; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != 0){ + fr_event(card,err,mb); + } + }while(err && --retry); + + return(((FRONT_END_REG_STRUCT *)data)->register_value); +} + +/*============================================================================ + * TE1 + * Write value to PMC register. + */ +//static unsigned char write_front_end_reg (void* card1, unsigned short reg, unsigned char value) +static int write_front_end_reg (void* card1, ...) +{ + va_list args; + sdla_t *card = (sdla_t*)card1; + wan_mbox_t *mb = &card->wan_mbox; + char *data = mb->wan_data; + u16 reg; + u8 value; + int err; + int retry=15; + + va_start(args, card1); + reg = (u16)va_arg(args, int); + value = (u8)va_arg(args, int); + va_end(args); + + WAN_MBOX_INIT(mb); + do { + ((FRONT_END_REG_STRUCT *)data)->register_number = (unsigned short)reg; + ((FRONT_END_REG_STRUCT *)data)->register_value = value; + mb->wan_data_len = sizeof(FRONT_END_REG_STRUCT); + mb->wan_command = WRITE_FRONT_END_REGISTER; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != 0){ + fr_event(card,err,mb); + } + }while(err && --retry); + + return err; +} + + +/*============================================================================ + * Enable timer interrupt + */ +static void fr_enable_timer (void* card_id) +{ + sdla_t* card = (sdla_t*)card_id; + + card->u.f.timer_int_enabled |= TMR_INT_ENABLED_TE; + card->hw_iface.set_bit(card->hw, card->intr_perm_off, FR_INTR_TIMER); + return; +} + +/****** Firmware Asynchronous Event Handlers ********************************/ + +/*============================================================================ + * Main asyncronous event/error handler. + * This routine is called whenever firmware command returns non-zero + * return code. + * + * Return zero if previous command has to be cancelled. + */ +static int fr_event (sdla_t *card, int event, wan_mbox_t* mb) +{ + fr508_flags_t flags; + u8 tmp; + int i; + + card->hw_iface.peek(card->hw, card->flags_off, &flags, sizeof(flags)); + + switch (event) { + + case FRRES_MODEM_FAILURE: + return fr_modem_failure(card, mb); + + case FRRES_CHANNEL_DOWN: + printk(KERN_INFO "%s: FR Event: Channel Down!\n",card->devname); + { + struct wan_dev_le *devle; + netdevice_t *dev; + + /* Remove all routes from associated DLCI's */ + WAN_LIST_FOREACH(devle, &card->wandev.dev_head, dev_link){ + fr_channel_t *chan; + + dev = WAN_DEVLE2DEV(devle); + + if (!dev || !wan_netif_priv(dev)){ + continue; + } + + chan = wan_netif_priv(dev); + if (chan->route_flag == ROUTE_ADDED) { + chan->route_flag = REMOVE_ROUTE; + } + + if (chan->inarp == INARP_CONFIGURED) { + chan->inarp = INARP_REQUEST; + } + + /* If the link becomes disconnected then, + * all channels will be disconnected + * as well. + */ + set_chan_state(dev,WAN_DISCONNECTED); + } + + wanpipe_set_state(card, WAN_DISCONNECTED); + + /* Debugging */ + WAN_DEBUG_START(card); + return 1; + } + + case FRRES_CHANNEL_UP: + printk(KERN_INFO "%s: FR Event: Channel Up!\n",card->devname); + wanpipe_set_state(card, WAN_CONNECTED); + + { + struct wan_dev_le *devle; + netdevice_t *dev; + fr_channel_t *chan; + + WAN_LIST_FOREACH(devle, &card->wandev.dev_head, dev_link){ + dev = WAN_DEVLE2DEV(devle); + if (!dev || !wan_netif_priv(dev)) continue; + chan = wan_netif_priv(dev); + if (chan->dlci_stat & FR_DLCI_ACTIVE){ + if (card->wandev.ignore_front_end_status == WANOPT_YES || + card->fe.fe_status == FE_CONNECTED){ + set_chan_state(dev,WAN_CONNECTED); + } + } + } + } + + return 1; + + case FRRES_DLCI_CHANGE: + return fr_dlci_change(card, mb, 0); + + case FRRES_DLCI_MISMATCH: + printk(KERN_INFO "%s: FR Event: DLCI list mismatch!\n", + card->devname); + return 1; + + case CMD_TIMEOUT: + printk(KERN_INFO "%s: command 0x%02X timed out!\n", + card->devname, mb->wan_command); + printk(KERN_INFO "%s: ID Bytes = ",card->devname); + for(i = 0; i < 8; i ++){ + card->hw_iface.peek(card->hw, card->intr_type_off+0x18+i, &tmp, 1); + printk("0x%02X ", tmp); + } + printk("\n"); + + break; + + case FRRES_DLCI_INACTIVE: + break; + + case FRRES_CIR_OVERFLOW: + break; + + case FRRES_BUFFER_OVERFLOW: + break; + + default: + printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n" + , card->devname, mb->wan_command, event); + break; + } + + return 0; +} + +/*============================================================================ + * Handle modem error. + * + * Return zero if previous command has to be cancelled. + */ +static int fr_modem_failure (sdla_t *card, wan_mbox_t* mb) +{ + + if (IS_56K_CARD(card)) { + FRONT_END_STATUS_STRUCT FE_status; + unsigned long FE_status_off = 0xF020; + + card->hw_iface.peek(card->hw, FE_status_off, &FE_status, sizeof(FE_status)); + card->fe.fe_param.k56_param.RR8_reg_56k = + FE_status.FE_U.stat_56k.RR8_56k; + card->fe.fe_param.k56_param.RRA_reg_56k = + FE_status.FE_U.stat_56k.RRA_56k; + card->fe.fe_param.k56_param.RRC_reg_56k = + FE_status.FE_U.stat_56k.RRC_56k; + card->wandev.fe_iface.read_alarm(&card->fe, 0); + + FE_status.opp_flag = 0x01; + card->hw_iface.poke(card->hw, FE_status_off, &FE_status, sizeof(FE_status)); + fr_handle_front_end_state (card); + + }else if (IS_TE1_CARD(card)) { + + FRONT_END_STATUS_STRUCT FE_status; + unsigned long FE_status_off = 0xF020; + + + card->hw_iface.peek(card->hw, FE_status_off, &FE_status, sizeof(FE_status)); + /* TE_INTR */ + card->wandev.fe_iface.isr(&card->fe); + FE_status.opp_flag = 0x01; + card->hw_iface.poke(card->hw, FE_status_off, &FE_status, sizeof(FE_status)); + + fr_handle_front_end_state (card); + + }else{ + printk(KERN_INFO "%s: physical link down! (modem error 0x%02X)\n", + card->devname, mb->wan_data[0]); + + if (mb->wan_data[0] == 0x28){ + card->fe.fe_status = FE_CONNECTED; + }else{ + card->fe.fe_status = FE_DISCONNECTED; + } + fr_handle_front_end_state (card); + } + + + switch (mb->wan_command){ + case FR_WRITE: + + case FR_READ: + return 0; + } + + return 1; +} + +/*============================================================================ + * Handle DLCI status change. + * + * Return zero if previous command has to be cancelled. + */ +static int fr_dlci_change (sdla_t *card, wan_mbox_t* mb, int mbox_offset) +{ + struct wan_dev_le *devle; + dlci_status_t* status = (void*)((unsigned char*)mb->wan_data+mbox_offset); + int cnt = mb->wan_data_len / sizeof(dlci_status_t); + fr_channel_t *chan; + netdevice_t* dev2; + + if (cnt > 1 && card->u.f.auto_dlci_cfg){ + netdevice_t* dev; + printk(KERN_INFO "\n"); + printk(KERN_INFO "%s: Warning: CPE set for auto DLCI config but found %i DLCIs\n", + card->devname,cnt); + + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + if (dev){ + fr_channel_t *chan = wan_netif_priv(dev); + if (chan->dlci == 0xFFFF){ + printk(KERN_INFO "%s: Error, CPE cannot select between multiple DLCIs!\n", + card->devname); + printk(KERN_INFO "%s: Error, Aboring auto config!\n", + card->devname); + printk(KERN_INFO "%s: Please turn off Auto DLCI option in %s.conf\n", + card->devname,card->devname); + + set_chan_state(dev, WAN_DISCONNECTED); + /* Debuggin */ + WAN_DEBUG_START(card); + return 1; + } + } + } + + + for (; cnt; --cnt, ++status) { + + unsigned short dlci= status->dlci; + netdevice_t* dev = find_channel(card, dlci); + + if (dev == NULL){ + printk(KERN_INFO + "%s: Warning: Unconfigured DLCI %u reported as %s, %s!\n", + card->devname, dlci, + (status->state & FR_DLCI_DELETED) ? "Deleted" : "Included", + (status->state & FR_DLCI_ACTIVE) ? "Active" : "Inactive"); + + }else{ + fr_channel_t *chan = dev->priv; + if (!chan){ + continue; + } + + if (card->u.f.auto_dlci_cfg && chan->dlci == 0xFFFF){ + chan->dlci=dlci; + chan->common.lcn=dlci; + } + chan->dlci_stat = status->state; + + if ((status->state & ~FR_DLCI_NEW) == FR_DLCI_INOPER) { + printk(KERN_INFO + "%s: DLCI %u reported as Included, Inactive%s!\n", + card->devname, dlci, + (status->state&FR_DLCI_NEW)?", New":""); + printk(KERN_INFO + "%s: Remote Frame end Down!\n", + card->devname); + + if (chan->common.state != WAN_DISCONNECTED){ + if (chan->route_flag == ROUTE_ADDED) { + chan->route_flag = REMOVE_ROUTE; + /* The state change will trigger + * the fr polling routine */ + } + + if (chan->inarp == INARP_CONFIGURED) { + chan->inarp = INARP_REQUEST; + } + + set_chan_state(dev, WAN_DISCONNECTED); + /* Debugging */ + WAN_DEBUG_START(card); + } + } + + if (status->state & FR_DLCI_DELETED) { + + printk(KERN_INFO + "%s: DLCI %u reported as Deleted!\n", + card->devname, dlci); + printk(KERN_INFO + "%s: Contact Frame provider!\n", + card->devname); + + + if (chan->common.state != WAN_DISCONNECTED){ + if (chan->route_flag == ROUTE_ADDED) { + chan->route_flag = REMOVE_ROUTE; + /* The state change will trigger + * the fr polling routine */ + } + + if (chan->inarp == INARP_CONFIGURED) { + chan->inarp = INARP_REQUEST; + } + + set_chan_state(dev, WAN_DISCONNECTED); + /* Debugging */ + WAN_DEBUG_START(card); + } + + + } else if (status->state & FR_DLCI_ACTIVE) { + + chan = dev->priv; + + printk(KERN_INFO + "%s: DLCI %u reported as Included, Active%s!\n", + card->devname, dlci, + (status->state&FR_DLCI_NEW)?", New":""); + + /* This flag is used for configuring specific + DLCI(s) when they become active. + */ + chan->dlci_configured = DLCI_CONFIG_PENDING; + if (card->wandev.state == WAN_CONNECTED){ + if (card->wandev.ignore_front_end_status == WANOPT_YES || + card->fe.fe_status == FE_CONNECTED){ + set_chan_state(dev, WAN_CONNECTED); + } + } + } + } + } + + WAN_LIST_FOREACH(devle, &card->wandev.dev_head, dev_link){ + dev2 = WAN_DEVLE2DEV(devle); + if (!dev2 || !wan_netif_priv(dev2)) continue; + chan = dev2->priv; + if (chan->dlci_configured == DLCI_CONFIG_PENDING) { + if (fr_init_dlci(card, chan)){ + return 1; + } + } + } + return 1; +} + + +static int fr_init_dlci (sdla_t *card, fr_channel_t *chan) +{ + fr_dlc_conf_t cfg; + + memset(&cfg, 0, sizeof(cfg)); + + if ( chan->cir_status == CIR_DISABLED) { + + cfg.cir_fwd = cfg.cir_bwd = 16; + cfg.bc_fwd = cfg.bc_bwd = 16; + cfg.conf_flags = 0x0001; + + }else if (chan->cir_status == CIR_ENABLED) { + + cfg.cir_fwd = cfg.cir_bwd = chan->cir; + cfg.bc_fwd = cfg.bc_bwd = chan->bc; + cfg.be_fwd = cfg.be_bwd = chan->be; + cfg.conf_flags = 0x0000; + } + + if (fr_dlci_configure( card, &cfg , chan->dlci)){ + printk(KERN_INFO + "%s: DLCI Configure failed for %d\n", + card->devname, chan->dlci); + return 1; + } + + chan->dlci_configured = DLCI_CONFIGURED; + + /* Read the interface byte mapping into the channel + * structure. + */ + read_DLCI_IB_mapping( card, chan ); + + return 0; +} +/******* Miscellaneous ******************************************************/ + +/*============================================================================ + * Update channel state. + */ +static int update_chan_state (netdevice_t* dev) +{ + fr_channel_t* chan = dev->priv; + sdla_t* card = chan->card; + wan_mbox_t* mb = &card->wan_mbox; + int retry = MAX_CMD_RETRY; + int err; + + WAN_MBOX_INIT(mb); + do + { + mb->wan_command = FR_LIST_ACTIVE_DLCI; + mb->wan_data_len = 0; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + } while (err && retry-- && fr_event(card, err, mb)); + + if (!err) { + + unsigned short* list = (void*)mb->wan_data; + int cnt = mb->wan_data_len / sizeof(short); + + err=1; + + for (; cnt; --cnt, ++list) { + if (*list == chan->dlci) { + chan->dlci_stat=0x02; + if (card->wandev.state == WAN_CONNECTED){ + if (card->wandev.ignore_front_end_status == WANOPT_YES || + card->fe.fe_status == FE_CONNECTED){ + set_chan_state(dev, WAN_CONNECTED); + } + }else{ + set_chan_state(dev, WAN_DISCONNECTED); + } + + /* May 23 2000. NC + * When a dlci is added or restarted, + * the dlci_int_interface pointer must + * be reinitialized. */ + if (!chan->dlci_int_interface_off){ + err=fr_init_dlci (card,chan); + } + return err; + } + } + } + chan->dlci_stat=0x00; + set_chan_state(dev, WAN_DISCONNECTED); + + return err; +} + +/*============================================================================ + * Set channel state. + */ +static void set_chan_state (netdevice_t* dev, int state) +{ + fr_channel_t* chan = dev->priv; + sdla_t* card = chan->card; + + if (chan->common.state != state) { + + struct timeval tv; + switch (state) { + + case WAN_CONNECTED: + printk(KERN_INFO + "%s: Interface %s: DLCI %d connected\n", + card->devname, dev->name, + chan->dlci > HIGHEST_VALID_DLCI?0:chan->dlci); + + /* If the interface was previoulsy down, + * bring it up, since the channel is active */ + + trigger_fr_poll (dev); + trigger_fr_arp (dev); + break; + + case WAN_CONNECTING: + printk(KERN_INFO + "%s: Interface %s: DLCI %d connecting\n", + card->devname, dev->name, + chan->dlci > HIGHEST_VALID_DLCI?0:chan->dlci); + break; + + case WAN_DISCONNECTED: + printk (KERN_INFO + "%s: Interface %s: DLCI %d disconnected!\n", + card->devname, dev->name, + chan->dlci > HIGHEST_VALID_DLCI?0:chan->dlci); + + /* If the interface is up, bring it down, + * since the channel is now disconnected */ + trigger_fr_poll (dev); + break; + } + + chan->common.state = state; + do_gettimeofday(&tv); + chan->router_last_change = tv.tv_sec; + + if (chan->common.usedby == API){ + wan_update_api_state(chan); + } + } + + chan->state_tick = jiffies; +} + +/*============================================================================ + * Find network device by its channel number. + * + * We need this critical flag because we change + * the dlci_to_dev_map outside the interrupt. + * + * NOTE: del_if() functions updates this array, it uses + * the spin locks to avoid corruption. + */ +static netdevice_t* find_channel (sdla_t* card, unsigned dlci) +{ + + if (card->u.f.auto_dlci_cfg){ + netdevice_t *dev; + + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + if (dev){ + fr_channel_t* chan = wan_netif_priv(dev); + if (chan->dlci != 0xFFFF && chan->dlci != dlci){ + return NULL; + } + return dev; + } + return NULL; + } + + if(dlci > HIGHEST_VALID_DLCI) + return NULL; + + return(card->u.f.dlci_to_dev_map[dlci]); +} + +/*============================================================================ + * Check to see if a frame can be sent. If no transmit buffers available, + * enable transmit interrupts. + * + * Return: 1 - Tx buffer(s) available + * 0 - no buffers available + */ +static int is_tx_ready (sdla_t* card, fr_channel_t* chan) +{ + unsigned char sb; + + if(card->type == SDLA_S514) + return 1; + + card->hw_iface.isa_read_1(card->hw, 0x00, &sb); + if (sb & 0x02) + return 1; + + return 0; +} + +/*============================================================================ + * Convert decimal string to unsigned integer. + * If len != 0 then only 'len' characters of the string are converted. + */ +static unsigned int dec_to_uint (unsigned char* str, int len) +{ + unsigned val; + + if (!len) + len = strlen(str); + + for (val = 0; len && is_digit(*str); ++str, --len) + val = (val * 10) + (*str - (unsigned)'0'); + + return val; +} + + + +/*============================================================================= + * Store a UDP management packet for later processing. + */ + +static int store_udp_mgmt_pkt(int udp_type, char udp_pkt_src, sdla_t* card, + struct sk_buff *skb, int dlci) +{ + int udp_pkt_stored = 0; + + netdevice_t *dev=find_channel(card,dlci); + fr_channel_t *chan; + + if (!dev || !(chan=dev->priv)) + return 1; + + if(!atomic_read(&card->u.f.udp_pkt_len) && (skb->len <= MAX_LGTH_UDP_MGNT_PKT)){ + atomic_set(&card->u.f.udp_pkt_len,skb->len + chan->fr_header_len); + card->u.f.udp_type = udp_type; + card->u.f.udp_pkt_src = udp_pkt_src; + card->u.f.udp_dlci = dlci; + memcpy((u8*)&card->u.f.udp_pkt_data, skb->data, skb->len); + card->u.f.timer_int_enabled |= TMR_INT_ENABLED_UDP; + udp_pkt_stored = 1; + + }else{ + printk(KERN_INFO "ERROR: UDP packet not stored for DLCI %d\n", + dlci); + } + + if(udp_pkt_src == UDP_PKT_FRM_STACK){ + wan_skb_free(skb); + }else{ + wan_skb_free(skb); + } + + return(udp_pkt_stored); +} + + +/*============================================================================== + * Process UDP call of type FPIPE8ND + */ +static int process_udp_mgmt_pkt(sdla_t* card, void *local_dev) +{ + int c_retry = MAX_CMD_RETRY; + unsigned char *buf; + unsigned char frames; + unsigned int len; + unsigned short buffer_length; + struct sk_buff *new_skb; + wan_mbox_t* mb = &card->wan_mbox; + int err; + struct timeval tv; + int udp_mgmt_req_valid = 1; + netdevice_t* dev; + fr_channel_t* chan; + wan_udp_pkt_t *wan_udp_pkt; + unsigned short num_trc_els; + fr_trc_el_t* ptr_trc_el; + fr_trc_el_t trc_el; + fpipemon_trc_t* fpipemon_trc; + + char udp_pkt_src = card->u.f.udp_pkt_src; + int dlci = card->u.f.udp_dlci; + + if (local_dev == NULL){ + + /* Find network interface for this packet */ + dev = find_channel(card, dlci); + if (!dev){ + atomic_set(&card->u.f.udp_pkt_len,0); + return -ENODEV; + } + if ((chan = dev->priv) == NULL){ + atomic_set(&card->u.f.udp_pkt_len,0); + return -ENODEV; + } + + /* If the UDP packet is from the network, we are going to have to + transmit a response. Before doing so, we must check to see that + we are not currently transmitting a frame (in 'if_send()') and + that we are not already in a 'delayed transmit' state. + */ + if(udp_pkt_src == UDP_PKT_FRM_NETWORK) { + if (check_tx_status(card,dev)){ + atomic_set(&card->u.f.udp_pkt_len,0); + return -EBUSY; + } + } + + wan_udp_pkt = (wan_udp_pkt_t *)&card->u.f.udp_pkt_data; + + + if(udp_pkt_src == UDP_PKT_FRM_NETWORK) { + + switch(wan_udp_pkt->wan_udp_command) { + + case FR_READ_MODEM_STATUS: + case FR_READ_STATUS: + case FPIPE_ROUTER_UP_TIME: + case FR_READ_ERROR_STATS: + case FPIPE_DRIVER_STAT_GEN: + case FR_READ_STATISTICS: + case FR_READ_ADD_DLC_STATS: + case FR_READ_CONFIG: + case FR_READ_CODE_VERSION: + case WAN_GET_MEDIA_TYPE: + case WAN_FE_GET_CFG: + case WAN_FE_GET_STAT: + case WAN_GET_PROTOCOL: + case WAN_GET_PLATFORM: + udp_mgmt_req_valid = 1; + break; + default: + udp_mgmt_req_valid = 0; + break; + } + } + }else{ + dev = (netdevice_t *) local_dev; + if ((chan = dev->priv) == NULL){ + return -ENODEV; + } + dlci=chan->dlci; + + if (atomic_read(&card->u.f.udp_pkt_len) == 0){ + return -ENODEV; + } + + wan_udp_pkt = (wan_udp_pkt_t *)&card->u.f.udp_pkt_data; + + udp_mgmt_req_valid=1; + } + + + wan_udp_pkt->wan_udp_opp_flag = 0x0; + if(!udp_mgmt_req_valid) { + /* set length to 0 */ + wan_udp_pkt->wan_udp_data_len = 0; + /* set return code */ + wan_udp_pkt->wan_udp_return_code = 0xCD; + + chan->drvstats_gen.UDP_PIPE_mgmt_direction_err ++; + + if (net_ratelimit()){ + printk(KERN_INFO + "%s: Warning, Illegal UDP command attempted from network: %x\n", + card->devname,wan_udp_pkt->wan_udp_command); + } + + } else { + + switch(wan_udp_pkt->wan_udp_command) { + + case FPIPE_ENABLE_TRACING: + if(!card->TracingEnabled) { + WAN_MBOX_INIT(mb); + do { + mb->wan_command = FR_SET_TRACE_CONFIG; + mb->wan_data_len = 1; + mb->wan_fr_dlci = 0x00; + mb->wan_data[0] = wan_udp_pkt->wan_udp_data[0] | + RESET_TRC; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + } while (err && c_retry-- && fr_event(card, err, mb)); + + if(err) { + card->TracingEnabled = 0; + /* set the return code */ + wan_udp_pkt->wan_udp_return_code = + mb->wan_return_code; + mb->wan_data_len = 0; + break; + } + + card->hw_iface.peek(card->hw, NO_TRC_ELEMENTS_OFF, + &num_trc_els, 2); + card->hw_iface.peek(card->hw, BASE_TRC_ELEMENTS_OFF, + &card->u.f.trc_el_base, 4); + card->u.f.curr_trc_el = card->u.f.trc_el_base; + card->u.f.trc_el_last = card->u.f.curr_trc_el + + ((num_trc_els - 1) * + sizeof(fr_trc_el_t)); + + /* Calculate the maximum trace data area in */ + /* the UDP packet */ + card->u.f.trc_bfr_space= + MAX_LGTH_UDP_MGNT_PKT- + sizeof(struct iphdr)- + sizeof(struct udphdr) - + sizeof(wan_mgmt_t)- + sizeof(wan_cmd_t); + + /* set return code */ + wan_udp_pkt->wan_udp_return_code = 0; + + } else { + /* set return code to line trace already + enabled */ + wan_udp_pkt->wan_udp_return_code = 1; + } + + mb->wan_data_len = 0; + card->TracingEnabled = 1; + break; + + + case FPIPE_DISABLE_TRACING: + if(card->TracingEnabled) { + + WAN_MBOX_INIT(mb); + do { + mb->wan_command = FR_SET_TRACE_CONFIG; + mb->wan_data_len = 1; + mb->wan_fr_dlci = 0x00; + mb->wan_data[0] = ~ACTIVATE_TRC; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + } while (err && c_retry-- && fr_event(card, err, mb)); + } + + /* set return code */ + wan_udp_pkt->wan_udp_return_code = 0; + mb->wan_data_len = 0; + card->TracingEnabled = 0; + break; + + case FPIPE_GET_TRACE_INFO: + + /* Line trace cannot be performed on the 502 */ + if(!card->TracingEnabled) { + /* set return code */ + wan_udp_pkt->wan_udp_return_code = 1; + mb->wan_data_len = 0; + break; + } + + ptr_trc_el = (fr_trc_el_t*) card->u.f.curr_trc_el; + + buffer_length = 0; + wan_udp_pkt->wan_udp_data[0x00] = 0x00; + + for(frames = 0; frames < MAX_FRMS_TRACED; frames ++) { + + card->hw_iface.peek(card->hw, (unsigned long)ptr_trc_el, + (void *)&trc_el.flag, + sizeof(fr_trc_el_t)); + + if(trc_el.flag == 0x00) { + break; + } + if((card->u.f.trc_bfr_space - buffer_length) + < sizeof(fpipemon_trc_hdr_t)+trc_el.length) { + wan_udp_pkt->wan_udp_data[0x00] |= MORE_TRC_DATA; + break; + } + + fpipemon_trc = + (fpipemon_trc_t *)&wan_udp_pkt->wan_udp_data[buffer_length]; + fpipemon_trc->fpipemon_trc_hdr.status = + trc_el.attr; + fpipemon_trc->fpipemon_trc_hdr.tmstamp = + trc_el.tmstamp; + fpipemon_trc->fpipemon_trc_hdr.length = + trc_el.length; + + if(!trc_el.offset || !trc_el.length) { + + fpipemon_trc->fpipemon_trc_hdr.data_passed = 0x00; + + }else if((trc_el.length + sizeof(fpipemon_trc_hdr_t) + 1) > + (card->u.f.trc_bfr_space - buffer_length)){ + + fpipemon_trc->fpipemon_trc_hdr.data_passed = 0x00; + wan_udp_pkt->wan_udp_data[0x00] |= MORE_TRC_DATA; + + }else { + fpipemon_trc->fpipemon_trc_hdr.data_passed = 0x01; + card->hw_iface.peek(card->hw, trc_el.offset, + fpipemon_trc->data, + trc_el.length); + } + + trc_el.flag = 0x00; + card->hw_iface.poke_byte(card->hw, (unsigned long)ptr_trc_el, 0x00); + + ptr_trc_el ++; + if((void *)ptr_trc_el > card->u.f.trc_el_last) + ptr_trc_el = (fr_trc_el_t*)card->u.f.trc_el_base; + + buffer_length += sizeof(fpipemon_trc_hdr_t); + if(fpipemon_trc->fpipemon_trc_hdr.data_passed) { + buffer_length += trc_el.length; + } + + if(wan_udp_pkt->wan_udp_data[0x00] & MORE_TRC_DATA) { + break; + } + } + + if(frames == MAX_FRMS_TRACED) { + wan_udp_pkt->wan_udp_data[0x00] |= MORE_TRC_DATA; + } + + card->u.f.curr_trc_el = (void *)ptr_trc_el; + + /* set the total number of frames passed */ + wan_udp_pkt->wan_udp_data[0x00] |= + ((frames << 1) & (MAX_FRMS_TRACED << 1)); + + /* set the data length and return code */ + wan_udp_pkt->wan_udp_data_len = mb->wan_data_len = buffer_length; + wan_udp_pkt->wan_udp_return_code = 0; + break; + + case FPIPE_FT1_READ_STATUS: + card->hw_iface.peek(card->hw, 0xF020, + &wan_udp_pkt->wan_udp_data[0x00] , 2); + wan_udp_pkt->wan_udp_data_len = mb->wan_data_len = 2; + wan_udp_pkt->wan_udp_return_code = 0; + break; + + case FPIPE_FLUSH_DRIVER_STATS: + init_chan_statistics(chan); + init_global_statistics(card); + mb->wan_data_len = 0; + break; + + case FPIPE_ROUTER_UP_TIME: + do_gettimeofday(&tv); + chan->router_up_time = tv.tv_sec - + chan->router_start_time; + *(unsigned long *)&wan_udp_pkt->wan_udp_data = + chan->router_up_time; + mb->wan_data_len = wan_udp_pkt->wan_udp_data_len = 4; + wan_udp_pkt->wan_udp_return_code = 0; + break; + + case FPIPE_DRIVER_STAT_IFSEND: + memcpy(wan_udp_pkt->wan_udp_data, + &chan->drvstats_if_send.if_send_entry, + sizeof(if_send_stat_t)); + mb->wan_data_len = wan_udp_pkt->wan_udp_data_len =sizeof(if_send_stat_t); + wan_udp_pkt->wan_udp_return_code = 0; + break; + + case FPIPE_DRIVER_STAT_INTR: + + memcpy(wan_udp_pkt->wan_udp_data, + &card->statistics.isr_entry, + sizeof(global_stats_t)); + + memcpy(&wan_udp_pkt->wan_udp_data[sizeof(global_stats_t)], + &chan->drvstats_rx_intr.rx_intr_no_socket, + sizeof(rx_intr_stat_t)); + + mb->wan_data_len = wan_udp_pkt->wan_udp_data_len = + sizeof(global_stats_t) + + sizeof(rx_intr_stat_t); + wan_udp_pkt->wan_udp_return_code = 0; + break; + + case FPIPE_DRIVER_STAT_GEN: + memcpy(wan_udp_pkt->wan_udp_data, + &chan->drvstats_gen.UDP_PIPE_mgmt_kmalloc_err, + sizeof(pipe_mgmt_stat_t)); + + memcpy(&wan_udp_pkt->wan_udp_data[sizeof(pipe_mgmt_stat_t)], + &card->statistics, sizeof(global_stats_t)); + + mb->wan_data_len = wan_udp_pkt->wan_udp_data_len = sizeof(global_stats_t)+ + sizeof(rx_intr_stat_t); + wan_udp_pkt->wan_udp_return_code = 0; + break; + + + case FR_FT1_STATUS_CTRL: + if(wan_udp_pkt->wan_udp_data[0] == 1) { + if(card->rCount++ != 0 ){ + wan_udp_pkt->wan_udp_return_code = 0; + mb->wan_data_len = 1; + break; + } + } + + /* Disable FT1 MONITOR STATUS */ + if(wan_udp_pkt->wan_udp_data[0] == 0) { + if( --card->rCount != 0) { + wan_udp_pkt->wan_udp_return_code = 0; + mb->wan_data_len = 1; + break; + } + } + goto udp_mgmt_dflt; + + case WAN_GET_MEDIA_TYPE: + case WAN_FE_GET_STAT: + case WAN_FE_SET_LB_MODE: + case WAN_FE_FLUSH_PMON: + case WAN_FE_GET_CFG: + + if (IS_TE1_CARD(card)){ + card->wandev.fe_iface.process_udp( + &card->fe, + &wan_udp_pkt->wan_udp_cmd, + &wan_udp_pkt->wan_udp_data[0]); + }else if (IS_56K_CARD(card)){ + card->wandev.fe_iface.process_udp( + &card->fe, + &wan_udp_pkt->wan_udp_cmd, + &wan_udp_pkt->wan_udp_data[0]); + }else{ + if (wan_udp_pkt->wan_udp_command == WAN_GET_MEDIA_TYPE){ + wan_udp_pkt->wan_udp_data_len = sizeof(unsigned char); + wan_udp_pkt->wan_udp_return_code = CMD_OK; + }else{ + wan_udp_pkt->wan_udp_return_code = WAN_UDP_INVALID_CMD; + } + } + mb->wan_data_len = wan_udp_pkt->wan_udp_data_len; + break; +#if 0 + case WAN_FE_SET_LB_MODE: + /* Activate/Deactivate Line Loopback modes */ + if (IS_TE1_CARD(card)){ + err = card->wandev.fe_iface.set_fe_lbmode( + &card->fe, + wan_udp_pkt->wan_udp_data[0], + wan_udp_pkt->wan_udp_data[1]); + wan_udp_pkt->wan_udp_return_code = + (!err) ? CMD_OK : WAN_UDP_FAILED_CMD; + }else{ + wan_udp_pkt->wan_udp_return_code = WAN_UDP_INVALID_CMD; + } + wan_udp_pkt->wan_udp_data_len = 0x00; + break; + + case WAN_GET_MEDIA_TYPE: + wan_udp_pkt->wan_udp_data[0] = + (IS_T1_CARD(card) ? WAN_MEDIA_T1 : + IS_E1_CARD(card) ? WAN_MEDIA_E1 : + IS_56K_CARD(card) ? WAN_MEDIA_56K : + WAN_MEDIA_NONE); + wan_udp_pkt->wan_udp_data_len = sizeof(unsigned char); + wan_udp_pkt->wan_udp_return_code = 0; + mb->wan_data_len = sizeof(unsigned char); + break; + + case WAN_FE_GET_STAT: + if (IS_TE1_CARD(card)) { + /* TE1_56K Read T1/E1/56K alarms */ + *(unsigned long *)&wan_udp_pkt->wan_udp_data = + card->wandev.fe_iface.read_alarm( + &card->fe, 0); + /* TE1 Update T1/E1 perfomance counters */ + card->wandev.fe_iface.read_pmon(&card->fe); + memcpy(&wan_udp_pkt->wan_udp_data[sizeof(unsigned long)], + &card->wandev.te_pmon, + sizeof(sdla_te_pmon_t)); + wan_udp_pkt->wan_udp_return_code = 0; + wan_udp_pkt->wan_udp_data_len = + sizeof(unsigned long) + sizeof(sdla_te_pmon_t); + mb->wan_data_len = wan_udp_pkt->wan_udp_data_len; + }else if (IS_56K_CARD(card)){ + /* 56K Update CSU/DSU alarms */ + card->wandev.k56_alarm = sdla_56k_alarm(card, 1); + *(unsigned long *)&wan_udp_pkt->wan_udp_data = + card->wandev.k56_alarm; + wan_udp_pkt->wan_udp_return_code = 0; + wan_udp_pkt->wan_udp_data_len = sizeof(unsigned long); + mb->wan_data_len = wan_udp_pkt->wan_udp_data_len; + } + break; + + case WAN_FE_FLUSH_PMON: + /* TE1 Flush T1/E1 pmon counters */ + if (IS_TE1_CARD(card)){ + card->wandev.fe_iface.flush_pmon(&card->fe); + wan_udp_pkt->wan_udp_return_code = 0; + } + break; + + case WAN_FE_GET_CFG: + /* Read T1/E1 configuration */ + if (IS_TE1_CARD(card)){ + memcpy(&wan_udp_pkt->wan_udp_data[0], + &card->wandev.te_cfg, + sizeof(sdla_te_cfg_t)); + wan_udp_pkt->wan_udp_return_code = 0; + wan_udp_pkt->wan_udp_data_len = sizeof(sdla_te_cfg_t); + mb->wan_data_len = wan_udp_pkt->wan_udp_data_len; + } + break; +#endif + + + case WAN_GET_PROTOCOL: + wan_udp_pkt->wan_udp_data[0] = card->wandev.config_id; + wan_udp_pkt->wan_udp_return_code = CMD_OK; + mb->wan_data_len = wan_udp_pkt->wan_udp_data_len = 1; + break; + + case WAN_GET_PLATFORM: + wan_udp_pkt->wan_udp_data[0] = WAN_LINUX_PLATFORM; + wan_udp_pkt->wan_udp_return_code = CMD_OK; + mb->wan_data_len = wan_udp_pkt->wan_udp_data_len = 1; + break; + + + default: +udp_mgmt_dflt: + WAN_MBOX_INIT(mb); + do { + memcpy(&mb->wan_command, + &wan_udp_pkt->wan_udp_command, + sizeof(wan_cmd_t)); + if(mb->wan_data_len) { + memcpy(&mb->wan_data, + (char *)wan_udp_pkt->wan_udp_data, + mb->wan_data_len); + } + + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + + } while (err && c_retry-- && fr_event(card, err, mb)); + + if(!err){ + chan->drvstats_gen. + UDP_PIPE_mgmt_adptr_cmnd_OK ++; + }else{ + chan->drvstats_gen. + UDP_PIPE_mgmt_adptr_cmnd_timeout ++; + } + + /* copy the result back to our buffer */ + memcpy(&wan_udp_pkt->wan_udp_hdr.wan_cmd, mb, sizeof(wan_cmd_t)); + + if(mb->wan_data_len) { + memcpy(&wan_udp_pkt->wan_udp_data, + &mb->wan_data, mb->wan_data_len); + } + } + } + + + /* Fill UDP TTL */ + wan_udp_pkt->wan_ip_ttl = card->wandev.ttl; + + if (local_dev){ + wan_udp_pkt->wan_udp_request_reply = UDPMGMT_REPLY; + return 1; + } + + len = reply_udp((u8*)&card->u.f.udp_pkt_data, mb->wan_data_len); + + if(udp_pkt_src == UDP_PKT_FRM_NETWORK) { + + chan->fr_header_len=2; + chan->fr_header[0]=chan->fr_encap_0; + chan->fr_header[1]=chan->fr_encap_1; + + err = fr_send_data_header(card, dlci, 0, len, + (u8*)&card->u.f.udp_pkt_data,chan->fr_header_len,0); + if (err){ + chan->drvstats_gen.UDP_PIPE_mgmt_adptr_send_passed ++; + }else{ + chan->drvstats_gen.UDP_PIPE_mgmt_adptr_send_failed ++; + } + + }else{ + /* Allocate socket buffer */ + if((new_skb = wan_skb_alloc(len)) != NULL) { + + /* copy data into new_skb */ + buf = skb_put(new_skb, len); + memcpy(buf, (u8*)&card->u.f.udp_pkt_data, len); + + chan->drvstats_gen. + UDP_PIPE_mgmt_passed_to_stack ++; + new_skb->dev = dev; + new_skb->protocol = htons(ETH_P_IP); + new_skb->mac.raw = new_skb->data; + + DEBUG_SUB_MEM(new_skb->truesize); + netif_rx(new_skb); + + } else { + chan->drvstats_gen.UDP_PIPE_mgmt_no_socket ++; + printk(KERN_INFO + "%s: UDP mgmt cmnd, no socket buffers available!\n", + card->devname); + } + } + + atomic_set(&card->u.f.udp_pkt_len,0); + return len; +} + +/*============================================================================== + * Send Inverse ARP Request + */ + +int send_inarp_request(sdla_t *card, netdevice_t *dev) +{ + int err=0; + + arphdr_1490_t *ArpPacket; + arphdr_fr_t *arphdr; + fr_channel_t *chan = dev->priv; + struct in_device *in_dev; + + in_dev = dev->ip_ptr; + + if(in_dev != NULL ) { + + ArpPacket = wan_malloc(sizeof(arphdr_1490_t) + sizeof(arphdr_fr_t)); + /* SNAP Header indicating ARP */ + ArpPacket->control = 0x03; + ArpPacket->pad = 0x00; + ArpPacket->NLPID = 0x80; + ArpPacket->OUI[0] = 0; + ArpPacket->OUI[1] = 0; + ArpPacket->OUI[2] = 0; + ArpPacket->PID = 0x0608; + + arphdr = (arphdr_fr_t *)(ArpPacket + 1); // Go to ARP Packet + + /* InARP request */ + arphdr->ar_hrd = 0x0F00; /* Frame Relay HW type */ + arphdr->ar_pro = 0x0008; /* IP Protocol */ + arphdr->ar_hln = 2; /* HW addr length */ + arphdr->ar_pln = 4; /* IP addr length */ + arphdr->ar_op = htons(0x08); /* InARP Request */ + arphdr->ar_sha = 0; /* src HW DLCI - Doesn't matter */ + if(in_dev->ifa_list != NULL) + arphdr->ar_sip = in_dev->ifa_list->ifa_local; /* Local Address */else + arphdr->ar_sip = 0; + arphdr->ar_tha = 0; /* dst HW DLCI - Doesn't matter */ + arphdr->ar_tip = 0; /* Remote Address -- what we want */ + + err = fr_send(card, chan->dlci, 0, sizeof(arphdr_1490_t) + sizeof(arphdr_fr_t), + (void *)ArpPacket); + + if (!err){ + printk(KERN_INFO "\n"); + printk(KERN_INFO "%s: Sending InARP request on DLCI %d.\n", + card->devname, chan->dlci); + } + + DEBUG_SUB_MEM(sizeof(arphdr_1490_t) + sizeof(arphdr_fr_t)); + wan_free(ArpPacket); + }else{ + printk(KERN_INFO "%s: INARP ERROR: %s doesn't have a local IP address!\n", + card->devname,dev->name); + return -EINVAL; + } + + return err; +} + + +/*============================================================================== + * Check packet for ARP Type + */ + +int is_arp(void *buf) +{ + arphdr_1490_t *arphdr = (arphdr_1490_t *)buf; + + if (arphdr->pad == 0x00 && + arphdr->NLPID == 0x80 && + arphdr->PID == 0x0608) + return 1; + else return 0; +} + +/*============================================================================== + * Process ARP Packet Type + */ + +int process_ARP(arphdr_1490_t *ArpPacket, sdla_t *card, netdevice_t* dev) +{ + + int err=0; + arphdr_fr_t *arphdr = (arphdr_fr_t *)(ArpPacket + 1); /* Skip header */ + struct in_device *in_dev; + fr_channel_t *chan = dev->priv; + + in_dev = dev->ip_ptr; + + /* Check that IP addresses exist for our network address */ + if (in_dev == NULL || in_dev->ifa_list == NULL){ + err = -1; + goto process_arp_exit; + } + + switch (ntohs(arphdr->ar_op)) { + + case 0x08: // Inverse ARP request -- Send Reply, add route. + + /* Check for valid Address */ + printk(KERN_INFO "%s: Recvd PtP addr -InArp Req: %u.%u.%u.%u\n", + card->devname, NIPQUAD(arphdr->ar_sip)); + + /* Check that the network address is the same as ours, only + * if the netowrk mask is not 255.255.255.255. Otherwise + * this check would not make sense */ + + if (in_dev->ifa_list->ifa_mask != 0xFFFFFFFF && + (in_dev->ifa_list->ifa_mask & arphdr->ar_sip) != + (in_dev->ifa_list->ifa_mask & in_dev->ifa_list->ifa_local)){ + + printk(KERN_INFO + "%s: Error, Invalid PtP address. %u.%u.%u.%u InARP ignored.\n", + card->devname,NIPQUAD(arphdr->ar_sip)); + + printk(KERN_INFO "%s: mask %u.%u.%u.%u\n", + card->devname, NIPQUAD(in_dev->ifa_list->ifa_mask)); + printk(KERN_INFO "%s: local %u.%u.%u.%u\n", + card->devname,NIPQUAD(in_dev->ifa_list->ifa_local)); + + err = -1; + goto process_arp_exit; + } + + if (in_dev->ifa_list->ifa_local == arphdr->ar_sip){ + printk(KERN_INFO + "%s: Local addr = PtP addr. InARP ignored.\n", + card->devname); + + err = -1; + goto process_arp_exit; + } + + arphdr->ar_op = htons(0x09); /* InARP Reply */ + + /* Set addresses */ + arphdr->ar_tip = arphdr->ar_sip; + arphdr->ar_sip = in_dev->ifa_list->ifa_local; + + chan->ip_local = in_dev->ifa_list->ifa_local; + chan->ip_remote = arphdr->ar_sip; + + /* Signal the above function to queue up the + * arp response and send it to a tx interrupt */ + err = 1; + + break; + + case 0x09: // Inverse ARP reply + + /* Check for valid Address */ + printk(KERN_INFO "%s: Recvd PtP addr %u.%u.%u.%u -InArp Reply\n", + card->devname, NIPQUAD(arphdr->ar_sip)); + + + /* Compare network addresses, only if network mask + * is not 255.255.255.255 It would not make sense + * to perform this test if the mask was all 1's */ + + if (in_dev->ifa_list->ifa_mask != 0xffffffff && + (in_dev->ifa_list->ifa_mask & arphdr->ar_sip) != + (in_dev->ifa_list->ifa_mask & in_dev->ifa_list->ifa_local)) { + + printk(KERN_INFO "%s: Error, Invalid PtP address. InARP ignored.\n", + card->devname); + err = -1; + goto process_arp_exit; + } + + /* Make sure that the received IP address is not + * the same as our own local address */ + if (in_dev->ifa_list->ifa_local == arphdr->ar_sip) { + printk(KERN_INFO "%s: Local addr = PtP addr. InARP ignored.\n", + card->devname); + err = -1; + goto process_arp_exit; + } + + chan->ip_local = in_dev->ifa_list->ifa_local; + chan->ip_remote = arphdr->ar_sip; + + /* Add Route Flag */ + /* The route will be added in the polling routine so + that it is not interrupt context. */ + + chan->route_flag = ADD_ROUTE; + chan->inarp = INARP_CONFIGURED; + trigger_fr_poll(dev); + + break; + default: // ARP's and RARP's -- Shouldn't happen. + DEBUG_EVENT("%s: Rx invalid frame relay ARP/RARP packet! 0x%x\n", + card->devname, ntohs(arphdr->ar_op)); + err=1; + break; + } + +process_arp_exit: + + return err; +} + + +/*============================================================ + * trigger_fr_arp + * + * Description: + * Add an fr_arp() task into a arp + * timer handler for a specific dlci/interface. + * This will kick the fr_arp() routine + * within the specified time interval. + * + * Usage: + * This timer is used to send ARP requests at + * certain time intervals. + * Called by an interrupt to request an action + * at a later date. + */ + +static void trigger_fr_arp (netdevice_t *dev) +{ + fr_channel_t* chan = dev->priv; + + del_timer(&chan->fr_arp_timer); + chan->fr_arp_timer.expires = jiffies + (chan->inarp_interval * HZ); + add_timer(&chan->fr_arp_timer); + return; +} + + + +/*============================================================================== + * ARP Request Action + * + * This funciton is called by timer interrupt to send an arp request + * to the remote end. + */ + +static void fr_arp (unsigned long data) +{ + netdevice_t *dev = (netdevice_t *)data; + fr_channel_t *chan = dev->priv; + sdla_t *card = chan->card; + + /* Send ARP packets for all devs' until + * ARP state changes to CONFIGURED */ + + if (chan->inarp == INARP_REQUEST && + chan->common.state == WAN_CONNECTED && + card->wandev.state == WAN_CONNECTED){ + set_bit(0,&chan->inarp_ready); + card->u.f.timer_int_enabled |= TMR_INT_ENABLED_ARP; + card->hw_iface.set_bit(card->hw, card->intr_perm_off, FR_INTR_TIMER); + } + + return; +} + + +/*============================================================================== + * Perform the Interrupt Test by running the READ_CODE_VERSION command MAX_INTR_ + * TEST_COUNTER times. + */ +static int intr_test( sdla_t* card ) +{ + wan_mbox_t* mb = &card->wan_mbox; + int err,i; + + err = fr_set_intr_mode(card, FR_INTR_READY, card->wandev.mtu, 0 ); + + if (err == CMD_OK) { + + WAN_MBOX_INIT(mb); + for ( i = 0; i < MAX_INTR_TEST_COUNTER; i++ ) { + /* Run command READ_CODE_VERSION */ + mb->wan_data_len = 0; + mb->wan_command = FR_READ_CODE_VERSION; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != CMD_OK) + fr_event(card, err, mb); + } + + } else { + printk(KERN_INFO "Interrupt test failed err=0x%02X\n", + err); + return err; + } + + err = fr_set_intr_mode( card, 0, card->wandev.mtu, 0 ); + + if( err != CMD_OK ) + return err; + + return 0; +} + +/*============================================================================== + * Determine what type of UDP call it is. FPIPE8ND ? + */ +static int udp_pkt_type( struct sk_buff *skb, sdla_t* card, int direction) +{ + wan_udp_pkt_t *wan_udp_pkt = (wan_udp_pkt_t *)skb->data; + + if (skb->len < sizeof(wan_udp_pkt_t)){ + return UDP_INVALID_TYPE; + } + + /* Quick HACK */ + if (direction == UDP_PKT_FRM_NETWORK){ + wan_udp_pkt = (wan_udp_pkt_t *)&skb->data[2]; + } + + if((wan_udp_pkt->wan_ip_p == UDPMGMT_UDP_PROTOCOL) && + (wan_udp_pkt->wan_udp_dport == ntohs(card->wandev.udp_port)) && + (wan_udp_pkt->wan_udp_request_reply == UDPMGMT_REQUEST)) { + if(!strncmp(wan_udp_pkt->wan_udp_signature, + UDPMGMT_FPIPE_SIGNATURE, 8)){ + return UDP_FPIPE_TYPE; + } + if(!strncmp(wan_udp_pkt->wan_udp_signature, + GLOBAL_UDP_SIGNATURE, 8)){ + return UDP_FPIPE_TYPE; + } + } + return UDP_INVALID_TYPE; +} + + +/*============================================================================== + * Initializes the Statistics values in the fr_channel structure. + */ +void init_chan_statistics( fr_channel_t* chan) +{ + memset(&chan->drvstats_if_send.if_send_entry, 0, + sizeof(if_send_stat_t)); + memset(&chan->drvstats_rx_intr.rx_intr_no_socket, 0, + sizeof(rx_intr_stat_t)); + memset(&chan->drvstats_gen.UDP_PIPE_mgmt_kmalloc_err, 0, + sizeof(pipe_mgmt_stat_t)); +} + +/*============================================================================== + * Initializes the Statistics values in the Sdla_t structure. + */ +void init_global_statistics( sdla_t* card ) +{ + /* Intialize global statistics for a card */ + memset(&card->statistics.isr_entry, 0, sizeof(global_stats_t)); +} + +static void read_DLCI_IB_mapping( sdla_t* card, fr_channel_t* chan ) +{ + wan_mbox_t* mb = &card->wan_mbox; + int retry = MAX_CMD_RETRY; + dlci_IB_mapping_t* result; + int err, counter, found; + + WAN_MBOX_INIT(mb); + do { + mb->wan_command = FR_READ_DLCI_IB_MAPPING; + mb->wan_data_len = 0; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + } while (err && retry-- && fr_event(card, err, mb)); + + if( mb->wan_return_code != 0){ + printk(KERN_INFO "%s: Read DLCI IB Mapping failed\n", + chan->name); + } + + counter = mb->wan_data_len / sizeof(dlci_IB_mapping_t); + result = (void *)mb->wan_data; + + found = 0; + for (; counter; --counter, ++result) { + if ( result->dlci == chan->dlci ) { + chan->IB_addr = result->addr_value; + /* Alex Apr 8 2004 Sangoma ISA card */ + chan->dlci_int_interface_off = chan->IB_addr; + chan->dlci_int_off = + chan->IB_addr + offsetof(fr_dlci_interface_t, gen_interrupt); + found = 1; + break; + } + } + if (!found) + printk( KERN_INFO "%s: DLCI %d not found by IB MAPPING cmd\n", + card->devname, chan->dlci); +} + + + +void s508_s514_lock(sdla_t *card, unsigned long *smp_flags) +{ + if (card->type != SDLA_S514){ + spin_lock_irqsave(&card->wandev.lock, *smp_flags); + }else{ + spin_lock(&card->u.f.if_send_lock); + } + return; +} + + +void s508_s514_unlock(sdla_t *card, unsigned long *smp_flags) +{ + if (card->type != SDLA_S514){ + spin_unlock_irqrestore (&card->wandev.lock, *smp_flags); + }else{ + spin_unlock(&card->u.f.if_send_lock); + } + return; +} + + +void s508_s514_send_event_lock(sdla_t *card, unsigned long *smp_flags) +{ + if (card->type == SDLA_S514){ + spin_lock_irqsave(&card->wandev.lock, *smp_flags); + } + return; +} + +void s508_s514_send_event_unlock(sdla_t *card, unsigned long *smp_flags) +{ + if (card->type == SDLA_S514){ + spin_unlock_irqrestore(&card->wandev.lock, *smp_flags); + } + return; +} + + + +/*---------------------------------------------------------------------- + RECEIVE INTERRUPT: BOTTOM HALF HANDLERS + ----------------------------------------------------------------------*/ + +/*======================================================== + * fr_bh + * + * Description: + * Frame relay receive BH handler. + * Dequeue data from the BH circular + * buffer and pass it up the API sock. + * + * Rationale: + * This fuction is used to offload the + * rx_interrupt during API operation mode. + * The fr_bh() function executes for each + * dlci/interface. + * + * Once receive interrupt copies data from the + * card into an skb buffer, the skb buffer + * is appended to a circular BH buffer. + * Then the interrupt kicks fr_bh() to finish the + * job at a later time (no within the interrupt). + * + * Usage: + * Interrupts use this to defer a taks to + * a polling routine. + * + */ + +static void fr_bh (unsigned long data) +{ + fr_channel_t* chan = (fr_channel_t*)data; + sdla_t *card = chan->card; + struct sk_buff *skb; + int len; + + while ((skb=wan_api_dequeue_skb(chan)) != NULL){ + + len=skb->len; + + if (wan_api_rx(chan,skb) == 0){ + card->wandev.stats.rx_packets++; + card->wandev.stats.rx_bytes += len; + chan->ifstats.rx_packets++; + chan->ifstats.rx_bytes += len; + chan->drvstats_rx_intr.rx_intr_bfr_passed_to_stack ++; + }else{ + ++card->wandev.stats.rx_dropped; + ++chan->ifstats.rx_dropped; + wan_skb_free(skb); + } + + } + + WAN_TASKLET_END((&chan->common.bh_task)); + + return; +} + +/*---------------------------------------------------------------------- + POLL BH HANDLERS AND KICK ROUTINES + ----------------------------------------------------------------------*/ + +/*============================================================ + * trigger_fr_poll + * + * Description: + * Add a fr_poll() task into a tq_scheduler bh handler + * for a specific dlci/interface. This will kick + * the fr_poll() routine at a later time. + * + * Usage: + * Interrupts use this to defer a taks to + * a polling routine. + * + */ +static void trigger_fr_poll (netdevice_t *dev) +{ + fr_channel_t* chan = dev->priv; + + wan_schedule_task(&chan->fr_poll_task); + return; +} + + +/*============================================================ + * fr_poll + * + * Rationale: + * We cannot manipulate the routing tables, or + * ip addresses withing the interrupt. Therefore + * we must perform such actons outside an interrupt + * at a later time. + * + * Description: + * Frame relay polling routine, responsible for + * shutting down interfaces upon disconnect + * and adding/removing routes. + * + * Usage: + * This function is executed for each frame relay + * dlci/interface through a tq_schedule bottom half. + * + * trigger_fr_poll() function is used to kick + * the fr_poll routine. + */ + +static void fr_poll (void *dev_ptr) +{ + netdevice_t *dev=dev_ptr; + fr_channel_t* chan; + sdla_t *card; + u8 check_gateway=0; + + if (!dev || (chan = dev->priv) == NULL) + return; + + card = chan->card; + + /* (Re)Configuraiton is in progress, stop what you are + * doing and get out */ + if (test_bit(PERI_CRIT,&card->wandev.critical)){ + return; + } + + switch (chan->common.state){ + + case WAN_DISCONNECTED: + + if (test_bit(DYN_OPT_ON,&chan->interface_down) && + !test_bit(DEV_DOWN, &chan->interface_down) && + dev->flags&IFF_UP){ + + printk(KERN_INFO "%s: Interface %s is Down.\n", + card->devname,dev->name); + change_dev_flags(dev,dev->flags&~IFF_UP); + set_bit(DEV_DOWN, &chan->interface_down); + chan->route_flag = NO_ROUTE; + + }else{ + if (chan->inarp != INARP_NONE) + process_route(dev); + } + break; + + case WAN_CONNECTED: + + if (test_bit(DYN_OPT_ON,&chan->interface_down) && + test_bit(DEV_DOWN, &chan->interface_down) && + !(dev->flags&IFF_UP)){ + + printk(KERN_INFO "%s: Interface %s is Up.\n", + card->devname,dev->name); + + change_dev_flags(dev,dev->flags|IFF_UP); + clear_bit(DEV_DOWN, &chan->interface_down); + check_gateway=1; + } + + if (chan->inarp != INARP_NONE){ + process_route(dev); + check_gateway=1; + } + + if (chan->gateway && check_gateway) + add_gateway(card,dev); + + break; + + } + + return; +} + +/*============================================================== + * check_tx_status + * + * Rationale: + * We cannot transmit from an interrupt while + * the if_send is transmitting data. Therefore, + * we must check whether the tx buffers are + * begin used, before we transmit from an + * interrupt. + * + * Description: + * Checks whether it's safe to use the transmit + * buffers. + * + * Usage: + * ARP and UDP handling routines use this function + * because, they need to transmit data during + * an interrupt. + */ + +static int check_tx_status(sdla_t *card, netdevice_t *dev) +{ + + if (card->type == SDLA_S514){ + if (test_bit(SEND_CRIT, (void*)&card->wandev.critical) || + test_bit(SEND_TXIRQ_CRIT, (void*)&card->wandev.critical)) { + return 1; + } + } + + if (is_queue_stopped(dev) || (atomic_read(&card->u.f.tx_interrupts_pending))) + return 1; + + return 0; +} + +/*=============================================================== + * move_dev_to_next + * + * Description: + * Move the dev pointer to the next location in the + * link list. Check if we are at the end of the + * list, if so start from the begining. + * + * Usage: + * Timer interrupt uses this function to efficiently + * step through the devices that need to send ARP data. + * + */ + +netdevice_t * move_dev_to_next (sdla_t *card, netdevice_t *dev) +{ + struct wan_dev_le *devle; + if (atomic_read(&card->wandev.if_cnt) == 1){ + return dev; + } + WAN_LIST_FOREACH(devle, &card->wandev.dev_head, dev_link){ + if (devle->dev == dev){ + dev = WAN_DEVLE2DEV(WAN_LIST_NEXT(devle, dev_link)); + if (!dev){ + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + } + return dev; + } + } + return dev; +} + +static void config_fr_dev (sdla_t *card,netdevice_t *dev) +{ + fr_channel_t *chan=dev->priv; + + /* If signalling is set to NO, then setup + * DLCI addresses right away. Don't have to wait for + * link to connect. + */ + if (card->wandev.signalling == WANOPT_NO){ + printk(KERN_INFO "%s: Signalling set to NO: Mapping DLCI's\n", + card->wandev.name); + if (fr_init_dlci(card,chan)){ + printk(KERN_INFO "%s: ERROR: Failed to configure DLCI %i !\n", + card->devname, chan->dlci); + return; + } + } + + if (card->wandev.station == WANOPT_CPE) { + + update_chan_state(dev); + + /* CPE: User enabled option to send out a Full + * status request as soon as all interfaces are + * configured */ + if (card->u.f.issue_fs_on_startup && + (atomic_read(&card->wandev.if_cnt) == atomic_read(&card->wandev.if_up_cnt))){ + card->u.f.issue_fs_on_startup=0; + fr_issue_isf(card, FR_ISF_FSE); + } + + } else { + /* FR switch: activate DLCI(s) */ + + /* For Switch emulation we have to ADD and ACTIVATE + * the DLCI(s) that were configured with the SET_DLCI_ + * CONFIGURATION command. Add and Activate will fail if + * DLCI specified is not included in the list. + * + * Also If_open is called once for each interface. But + * it does not get in here for all the interface. So + * we have to pass the entire list of DLCI(s) to add + * activate routines. + */ + + if (!check_dlci_config (card, chan)){ + fr_add_dlci(card, chan->dlci); + fr_activate_dlci(card, chan->dlci); + } + } + + if (!card->u.f.auto_dlci_cfg){ + card->u.f.dlci_to_dev_map[chan->dlci] = dev; + } + return; +} + + +/*============================================================== + * unconfig_fr_dev + * + * Rationale: + * All commands must be executed during an interrupt. + * + * Description: + * Remove the dlci from firmware. + * This funciton is used in NODE shutdown. + */ + +static void unconfig_fr_dev (sdla_t *card,netdevice_t *dev) +{ + fr_channel_t *chan=dev->priv; + + if (card->wandev.station == WANOPT_NODE){ + printk(KERN_INFO "%s: Unconfiguring DLCI %i\n", + card->devname,chan->dlci); + fr_delete_dlci(card,chan->dlci); + } + + if (!card->u.f.auto_dlci_cfg){ + card->u.f.dlci_to_dev_map[chan->dlci] = NULL; + } +} + + +static int setup_fr_header(struct sk_buff ** skb_orig, netdevice_t* dev, char op_mode) +{ + struct sk_buff *skb = *skb_orig; + fr_channel_t *chan=dev->priv; + + if (op_mode == WANPIPE){ + + switch (htons(skb->protocol)){ + + case ETH_P_IP: + chan->fr_header[0]=chan->fr_encap_0; + chan->fr_header[1]=chan->fr_encap_1; + return 2; + + case ETH_P_IPX: + chan->fr_header[0]=Q922_UI; + chan->fr_header[1]=0; + chan->fr_header[2]=NLPID_SNAP; + chan->fr_header[3]=0; + chan->fr_header[4]=0; + chan->fr_header[5]=0; + *((unsigned short*)&chan->fr_header[6]) = skb->protocol; + return 8; + + default: + return -EINVAL; + } + } + + /* If we are in bridging mode, we must apply + * an Ethernet header */ + if (op_mode == BRIDGE || op_mode == BRIDGE_NODE){ + + /* Encapsulate the packet as a bridged Ethernet frame. */ +#ifdef DEBUG + printk(KERN_INFO "%s: encapsulating skb for frame relay\n", + dev->name); +#endif + + chan->fr_header[0] = 0x03; + chan->fr_header[1] = 0x00; + chan->fr_header[2] = 0x80; + chan->fr_header[3] = 0x00; + chan->fr_header[4] = 0x80; + chan->fr_header[5] = 0xC2; + chan->fr_header[6] = 0x00; + chan->fr_header[7] = 0x07; + + /* Yuck. */ + skb->protocol = ETH_P_802_3; + return 8; + } + + return 0; +} + + +static int check_dlci_config (sdla_t *card, fr_channel_t *chan) +{ + struct wan_dev_le *devle; + wan_mbox_t* mb = &card->wan_mbox; + int err=0; + fr_conf_t *conf=NULL; + unsigned short dlci_num = chan->dlci; + int dlci_offset=0; + netdevice_t *dev=NULL; + + WAN_MBOX_INIT(mb); + mb->wan_command = FR_READ_CONFIG; + mb->wan_data_len = 0; + mb->wan_fr_dlci = dlci_num; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + + if (err == CMD_OK){ + return 0; + } + + WAN_LIST_FOREACH(devle, &card->wandev.dev_head, dev_link){ + dev = WAN_DEVLE2DEV(devle); + if (!dev) continue; + set_chan_state(dev,WAN_DISCONNECTED); + } + + printk(KERN_INFO "%s: FR NODE configuring unconfigured DLCI %i\n", + card->devname,dlci_num); + + WAN_MBOX_INIT(mb); + mb->wan_command = FR_COMM_DISABLE; + mb->wan_data_len = 0; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != CMD_OK){ + fr_event(card, err, mb); + return 2; + } + + printk(KERN_INFO "%s: FR NODE disabled communications \n", + card->devname); + + WAN_MBOX_INIT(mb); + mb->wan_command = FR_READ_CONFIG; + mb->wan_data_len = 0; + mb->wan_fr_dlci = 0; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + + if (err != CMD_OK){ + fr_event(card, err, mb); + return 2; + } + + conf = (fr_conf_t *)mb->wan_data; + + dlci_offset=0; + + WAN_LIST_FOREACH(devle, &card->wandev.dev_head, dev_link){ + fr_channel_t *chan_tmp; + + dev = WAN_DEVLE2DEV(devle); + if (!dev || !wan_netif_priv(dev)) continue; + chan_tmp = wan_netif_priv(dev); + conf->dlci[dlci_offset] = chan_tmp->dlci; + dlci_offset++; + } + + WAN_MBOX_INIT(mb); + mb->wan_data_len = 0x20 + dlci_offset*2; + + mb->wan_command = FR_SET_CONFIG; + mb->wan_fr_dlci = 0; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != CMD_OK){ + fr_event(card, err, mb); + return 2; + } + + initialize_rx_tx_buffers (card); + + printk(KERN_INFO "%s: FR Node add new DLCI %i\n", + card->devname,dlci_num); + + if (fr_comm_enable (card)){ + return 2; + } + + printk(KERN_INFO "%s: FR Node Enabling Communications \n", + card->devname); + + WAN_LIST_FOREACH(devle, &card->wandev.dev_head, dev_link){ + fr_channel_t *chan_tmp; + + dev = WAN_DEVLE2DEV(devle); + if (!dev || !wan_netif_priv(dev)) continue; + chan_tmp = wan_netif_priv(dev); + fr_init_dlci(card,chan_tmp); + fr_add_dlci(card, chan_tmp->dlci); + fr_activate_dlci(card, chan_tmp->dlci); + } + + return 1; +} + +static void initialize_rx_tx_buffers (sdla_t *card) +{ + fr_buf_info_t buf_info; + unsigned long buf_info_off; + + /* Alex Apr 8 2004 Sangoma ISA card */ + buf_info_off = FR_MB_VECTOR + FR508_RXBC_OFFS; + card->hw_iface.peek(card->hw, buf_info_off, &buf_info, sizeof(buf_info)); + + card->rxmb_off = buf_info.rse_next; + card->u.f.rxmb_base_off = buf_info.rse_base; + card->u.f.rxmb_last_off = + (buf_info.rse_num - 1) * sizeof(fr_rx_buf_ctl_t) + + buf_info.rse_base; + + card->u.f.rx_base_off = buf_info.buf_base; + card->u.f.rx_top_off = buf_info.buf_top; + + atomic_set(&card->u.f.tx_interrupts_pending,0); + + return; +} + +static int set_adapter_config (sdla_t* card) +{ + wan_mbox_t* mb = &card->wan_mbox; + ADAPTER_CONFIGURATION_STRUCT* cfg = (ADAPTER_CONFIGURATION_STRUCT*)mb->wan_data; + int err; + + WAN_MBOX_INIT(mb); + card->hw_iface.getcfg(card->hw, SDLA_ADAPTERTYPE, &cfg->adapter_type); + cfg->adapter_config = 0x00; + cfg->operating_frequency = 00; + mb->wan_data_len = sizeof(ADAPTER_CONFIGURATION_STRUCT); + mb->wan_command = SET_ADAPTER_CONFIGURATION; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if(err != 0) { + fr_event(card,err,mb); + } + return (err); +} + + + +/* + * Proc FS function + */ +#define PROC_CFG_FRM "%-15s| %-12s| %-5u|\n" +#define PROC_STAT_FRM "%-15s| %-12s| %-14s|\n" +static char fr_config_hdr[] = + "Interface name | Device name | DLCI |\n"; +static char fr_status_hdr[] = + "Interface name | Device name | Status |\n"; + +static int fr_get_config_info(void* priv, struct seq_file* m, int* stop_cnt) +{ + fr_channel_t* chan = (fr_channel_t*)priv; + sdla_t* card = chan->card; + + if (chan == NULL) + return m->count; + if ((m->from == 0 && m->count == 0) || (m->from && m->from == *stop_cnt)){ + PROC_ADD_LINE(m, "%s", fr_config_hdr); + } + + PROC_ADD_LINE(m, + PROC_CFG_FRM, chan->name, card->devname, chan->dlci); + return m->count; +} + +static int fr_get_status_info(void* priv, struct seq_file* m, int* stop_cnt) +{ + fr_channel_t* chan = (fr_channel_t*)priv; + sdla_t* card = chan->card; + + if (chan == NULL) + return m->count; + + if ((m->from == 0 && m->count == 0) || (m->from && m->from == *stop_cnt)){ + PROC_ADD_LINE(m, + "%s", fr_status_hdr); + } + + PROC_ADD_LINE(m, + PROC_STAT_FRM, chan->name, card->devname, STATE_DECODE(chan->common.state)); + return m->count; +} + +#define PROC_DEV_FR_S_FRM "%-20s| %-14s|\n" +#define PROC_DEV_FR_D_FRM "%-20s| %-14d|\n" +#define PROC_DEV_SEPARATE "=====================================\n" + +static int fr_set_dev_config(struct file *file, + const char *buffer, + unsigned long count, + void *data) +{ + int cnt = 0; + wan_device_t* wandev = (void*)data; + sdla_t* card = NULL; + + if (wandev == NULL) + return cnt; + + card = (sdla_t*)wandev->private; + + printk(KERN_INFO "%s: New device config (%s)\n", + wandev->name, buffer); + /* Parse string */ + + return count; +} + +#define PROC_IF_FR_S_FRM "%-30s\t%-14s\n" +#define PROC_IF_FR_D_FRM "%-30s\t%-14d\n" +#define PROC_IF_FR_L_FRM "%-30s\t%-14ld\n" +#define PROC_IF_SEPARATE "====================================================\n" + +static int fr_set_if_info(struct file *file, + const char *buffer, + unsigned long count, + void *data) +{ + netdevice_t* dev = (void*)data; + fr_channel_t* chan = (fr_channel_t*)dev->priv; + sdla_t* card = chan->card; + + if (dev == NULL || dev->priv == NULL) + return count; + chan = (fr_channel_t*)dev->priv; + if (chan->card == NULL) + return count; + card = chan->card; + + printk(KERN_INFO "%s: New interface config (%s)\n", + chan->name, buffer); + /* Parse string */ + + return count; +} + + +static void fr_handle_front_end_state (void* card_id) +{ + struct wan_dev_le *devle; + sdla_t* card = (sdla_t*)card_id; + netdevice_t* dev; + fr_channel_t* chan; + + if (card->wandev.ignore_front_end_status == WANOPT_YES){ + return; + } + + WAN_LIST_FOREACH(devle, &card->wandev.dev_head, dev_link){ + + dev = WAN_DEVLE2DEV(devle); + if (!dev || !wan_netif_priv(dev)) continue; + chan = wan_netif_priv(dev); + if (!chan){ + continue; + } + + if (card->fe.fe_status == FE_CONNECTED){ + if (chan->dlci_stat & FR_DLCI_ACTIVE && + card->wandev.state == WAN_CONNECTED && + chan->common.state != WAN_CONNECTED){ + set_chan_state(dev,WAN_CONNECTED); + } + }else{ + if (chan->common.state != WAN_DISCONNECTED){ + if (chan->route_flag == ROUTE_ADDED) { + chan->route_flag = REMOVE_ROUTE; + /* The state change will trigger + * the fr polling routine */ + } + + if (chan->inarp == INARP_CONFIGURED) { + chan->inarp = INARP_REQUEST; + } + + set_chan_state(dev,WAN_DISCONNECTED); + /* Debugging */ + WAN_DEBUG_START(card); + } + } + } +} + + +/* SNMP + ****************************************************************************** + * fr_snmp_data() + * + * Description: Save snmp request and parameters in private structure, enable + * TIMER interrupt, put current process in sleep. + * Arguments: + * Returns: + ****************************************************************************** + */ +#define FRDLCMIIFINDEX 3 +#define FRDLCMISTATE 4 +#define FRDLCMIADDRESS 5 +#define FRDLCMIADDRESSLEN 6 +#define FRDLCMIPOLLINGINTERVAL 7 +#define FRDLCMIFULLENQUIRYINTERVAL 8 +#define FRDLCMIERRORTHRESHOLD 9 +#define FRDLCMIMONITOREDEVENTS 10 +#define FRDLCMIMAXSUPPORTEDVCS 11 +#define FRDLCMIMULTICAST 12 +#define FRDLCMISTATUS 13 +#define FRDLCMIROWSTATUS 14 +#define FRCIRCUITIFINDEX 17 +#define FRCIRCUITDLCI 18 +#define FRCIRCUITSTATE 19 +#define FRCIRCUITRECEIVEDFECNS 20 +#define FRCIRCUITRECEIVEDBECNS 21 +#define FRCIRCUITSENTFRAMES 22 +#define FRCIRCUITSENTOCTETS 23 +#define FRCIRCUITRECEIVEDFRAMES 24 +#define FRCIRCUITRECEIVEDOCTETS 25 +#define FRCIRCUITCREATIONTIME 26 +#define FRCIRCUITLASTTIMECHANGE 27 +#define FRCIRCUITCOMMITTEDBURST 28 +#define FRCIRCUITEXCESSBURST 29 +#define FRCIRCUITTHROUGHPUT 30 +#define FRCIRCUITMULTICAST 31 +#define FRCIRCUITTYPE 32 +#define FRCIRCUITDISCARDS 33 +#define FRCIRCUITRECEIVEDDES 34 +#define FRCIRCUITSENTDES 35 +#define FRCIRCUITLOGICALIFINDEX 36 +#define FRCIRCUITROWSTATUS 37 +#define FRERRIFINDEX 40 +#define FRERRTYPE 41 +#define FRERRDATA 42 +#define FRERRTIME 43 +#define FRERRFAULTS 44 +#define FRERRFAULTTIME 45 +#define FRTRAPSTATE 46 +#define FRTRAPMAXRATE 47 + +static int fr_snmp_data(sdla_t* card, netdevice_t *dev, void* data) +{ + fr_channel_t* chan = NULL; + wanpipe_snmp_t* snmp; + struct timeval tv; + + if (dev == NULL || dev->priv == NULL) + return -EFAULT; + chan = (fr_channel_t*)dev->priv; + /* Update device statistics */ + if (card->wandev.update) { + int rslt = 0; + card->u.f.update_dlci = chan; + rslt = card->wandev.update(&card->wandev); + if(rslt) { + return (rslt) ? (-EBUSY) : (-EINVAL); + } + } + + snmp = (wanpipe_snmp_t*)data; + + switch(snmp->snmp_magic){ + /***** Data Link Connection Management Interface ****/ + case FRDLCMIIFINDEX: + break; + + case FRDLCMISTATE: + snmp->snmp_val = + (card->wandev.signalling == WANOPT_FR_ANSI) ? SNMP_FR_ANSIT1617D : + (card->wandev.signalling == WANOPT_FR_Q933) ? SNMP_FR_ITUT933A : + (card->wandev.signalling == WANOPT_FR_LMI) ? SNMP_FR_LMIREV: + SNMP_FR_NOLMICONF; + break; + + case FRDLCMIADDRESS: + snmp->snmp_val = SNMP_FR_Q922; + break; + + case FRDLCMIADDRESSLEN: + snmp->snmp_val = SNMP_FR_4BYTE_ADDR; + break; + + case FRDLCMIPOLLINGINTERVAL: + snmp->snmp_val = card->u.f.t391; + break; + + case FRDLCMIFULLENQUIRYINTERVAL: + snmp->snmp_val = card->u.f.n391; + break; + + case FRDLCMIERRORTHRESHOLD: + snmp->snmp_val = card->u.f.n392; + break; + + case FRDLCMIMONITOREDEVENTS: + snmp->snmp_val = card->u.f.n393; + break; + + case FRDLCMIMAXSUPPORTEDVCS: + snmp->snmp_val = HIGHEST_VALID_DLCI; + break; + + case FRDLCMIMULTICAST: + snmp->snmp_val = SNMP_FR_NONBROADCAST; + break; + + case FRDLCMISTATUS: /* FIXME */ + snmp->snmp_val = SNMP_FR_RUNNING; + break; + + case FRDLCMIROWSTATUS: /* FIXME */ + snmp->snmp_val = 0; + break; + + /****************** Circuit Table *******************/ + case FRCIRCUITIFINDEX: + break; + + case FRCIRCUITDLCI: + snmp->snmp_val = chan->dlci; + break; + + case FRCIRCUITSTATE: + snmp->snmp_val = (chan->common.state == WAN_CONNECTED) ? SNMP_FR_ACTIVE : SNMP_FR_INACTIVE; + break; + + case FRCIRCUITRECEIVEDFECNS: + snmp->snmp_val = chan->rx_FECN; + break; + + case FRCIRCUITRECEIVEDBECNS: + snmp->snmp_val = chan->rx_BECN; + break; + + case FRCIRCUITSENTFRAMES: + snmp->snmp_val = chan->ifstats.tx_packets; + break; + + case FRCIRCUITSENTOCTETS: + snmp->snmp_val = chan->ifstats.tx_bytes; + break; + + case FRCIRCUITRECEIVEDFRAMES: + snmp->snmp_val = chan->ifstats.rx_packets; + break; + + case FRCIRCUITRECEIVEDOCTETS: + snmp->snmp_val = chan->ifstats.rx_bytes; + break; + + case FRCIRCUITCREATIONTIME: + do_gettimeofday( &tv ); + snmp->snmp_val = tv.tv_sec - chan->router_start_time; + break; + + case FRCIRCUITLASTTIMECHANGE: + do_gettimeofday( &tv ); + snmp->snmp_val = tv.tv_sec - chan->router_last_change; + break; + + case FRCIRCUITCOMMITTEDBURST: + snmp->snmp_val = (unsigned long)chan->bc; + break; + + case FRCIRCUITEXCESSBURST: + snmp->snmp_val = (unsigned long)chan->be; + break; + + case FRCIRCUITTHROUGHPUT: /* FIXME */ + snmp->snmp_val = (unsigned long)0; + break; + + case FRCIRCUITMULTICAST: + snmp->snmp_val = (chan->mc) ? SNMP_FR_ONEWAY : SNMP_FR_UNICAST; + break; + + case FRCIRCUITTYPE: + snmp->snmp_val = chan->dlci_type; + break; + + case FRCIRCUITDISCARDS: + snmp->snmp_val = chan->ifstats.rx_errors; + break; + + case FRCIRCUITRECEIVEDDES: + snmp->snmp_val = chan->rx_DE_set; + break; + + case FRCIRCUITSENTDES: + snmp->snmp_val = chan->tx_DE_set; + break; + + case FRCIRCUITLOGICALIFINDEX: /* FIXME */ + snmp->snmp_val = 0; + break; + + case FRCIRCUITROWSTATUS: /* FIXME */ + snmp->snmp_val = 0; + break; + + /****************** Errort Table *******************/ + case FRERRIFINDEX: + break; + + case FRERRTYPE: /* FIXME */ + snmp->snmp_val = chan->err_type; + break; + + case FRERRDATA: /* FIXME */ + strcpy((void*)snmp->snmp_data, chan->err_data); + break; + + case FRERRTIME: /* FIXME */ + snmp->snmp_val = chan->err_time; + break; + + case FRERRFAULTS: /* FIXME */ + snmp->snmp_val = chan->err_faults; + break; + + case FRERRFAULTTIME: /* FIXME */ + snmp->snmp_val = (unsigned long)0; + break; + + /************ Frame Relay Trap Control **************/ + case FRTRAPSTATE: + snmp->snmp_val = chan->trap_state; + break; + + case FRTRAPMAXRATE: + snmp->snmp_val = chan->trap_max_rate; + break; + + default: + return -EAFNOSUPPORT; + } + + return 0; + +} + +/* +**************************************************************************** +** +** +** +*/ +static int fr_debugging(sdla_t* card) +{ + + if (card->wan_debugging_state == WAN_DEBUGGING_CONT && + card->wandev.station == WANOPT_CPE){ + card->wan_debugging_state = WAN_DEBUGGING_PROTOCOL; + /* + ** If link still down after 100 seconds (only for CPE), then + ** report error. + */ + return 100; + } + + if (card->wandev.station == WANOPT_CPE){ + if (card->wan_debug_last_msg != WAN_DEBUG_FR_CPE_MSG){ + DEBUG_EVENT("%s: Frame Relay switch not replying.\n", + card->devname); + DEBUG_EVENT("%s: Check ANSI/LMI/Q.933 setting with Frame Relay provider.\n", + card->devname); + } + card->wan_debug_last_msg = WAN_DEBUG_FR_CPE_MSG; + }else{ + if (card->wan_debug_last_msg != WAN_DEBUG_FR_NODE_MSG){ + DEBUG_EVENT("%s: No Signalling frames received from Frame Relay CPE!\n", + card->devname); + } + card->wan_debug_last_msg = WAN_DEBUG_FR_NODE_MSG; + } + return 0; +} + +static unsigned long fr_crc_frames(sdla_t* card) +{ + wan_mbox_t* mb = &card->wan_mbox; + unsigned long smp_flags; + unsigned long rx_bad_crc = 0; + + wan_spin_lock_irq(&card->wandev.lock,&smp_flags); + if (!fr_get_err_stats(card)){ + fr_comm_stat_t* err_stats = (void*)mb->wan_data; + rx_bad_crc = err_stats->rx_bad_crc; + } + wan_spin_unlock_irq(&card->wandev.lock,&smp_flags); + return rx_bad_crc; +} + +static unsigned long fr_abort_frames(sdla_t * card) +{ + wan_mbox_t* mb = &card->wan_mbox; + unsigned long smp_flags; + unsigned long rx_aborts = 0; + + wan_spin_lock_irq(&card->wandev.lock,&smp_flags); + if (!fr_get_err_stats(card)){ + fr_comm_stat_t* err_stats = (void*)mb->wan_data; + rx_aborts = err_stats->rx_aborts; + } + wan_spin_unlock_irq(&card->wandev.lock,&smp_flags); + return rx_aborts; +} + +static unsigned long fr_tx_underun_frames(sdla_t* card) +{ + wan_mbox_t* mb = &card->wan_mbox; + unsigned long smp_flags; + unsigned long tx_missed_undr = 0; + + wan_spin_lock_irq(&card->wandev.lock,&smp_flags); + if (!fr_get_err_stats(card)){ + fr_comm_stat_t* err_stats = (void*)mb->wan_data; + tx_missed_undr = err_stats->tx_missed_undr; + } + wan_spin_unlock_irq(&card->wandev.lock,&smp_flags); + return tx_missed_undr; +} + + + +/****** End *****************************************************************/ diff -Nur linux.org/drivers/net/wan/sdla_ft1.c linux-2.6.17/drivers/net/wan/sdla_ft1.c --- linux.org/drivers/net/wan/sdla_ft1.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/drivers/net/wan/sdla_ft1.c 2006-08-30 10:07:16.000000000 +0000 @@ -0,0 +1,358 @@ +/***************************************************************************** +* sdla_ft1.c WANPIPE(tm) Multiprotocol WAN Link Driver. Cisco HDLC module. +* +* Authors: Nenad Corbic +* Gideon Hack +* +* Copyright: (c) 1995-1999 Sangoma Technologies Inc. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version +* 2 of the License, or (at your option) any later version. +* ============================================================================ +* Aug 23, 2001 Nenad Corbic Removed the if_header and set the hard_header +* length to zero. Caused problems with Checkpoint +* firewall. +* Sep 30, 1999 Nenad Corbic Fixed dynamic IP and route setup. +* Sep 23, 1999 Nenad Corbic Added SMP support, fixed tracing +* Sep 13, 1999 Nenad Corbic Split up Port 0 and 1 into separate devices. +* Jun 02, 1999 Gideon Hack Added support for the S514 adapter. +* Oct 30, 1998 Jaspreet Singh Added Support for CHDLC API (HDLC STREAMING). +* Oct 28, 1998 Jaspreet Singh Added Support for Dual Port CHDLC. +* Aug 07, 1998 David Fong Initial version. +*****************************************************************************/ + + +#include +#include +#include +#include +#include + + +#include /* WAN router definitions */ +#include /* WANPIPE common user API definitions */ +#include +#include /* CHDLC firmware API definitions */ + +/****** Defines & Macros ****************************************************/ + +/* reasons for enabling the timer interrupt on the adapter */ +#define TMR_INT_ENABLED_UDP 0x0001 +#define TMR_INT_ENABLED_UPDATE 0x0002 + +#define CHDLC_DFLT_DATA_LEN 1500 /* default MTU */ +#define CHDLC_HDR_LEN 1 + +#define IFF_POINTTOPOINT 0x10 + +#define WANPIPE 0x00 +#define API 0x01 +#define CHDLC_API 0x01 + +#define PORT(x) (x == 0 ? "PRIMARY" : "SECONDARY" ) + + +/******Data Structures*****************************************************/ + +/* This structure is placed in the private data area of the device structure. + * The card structure used to occupy the private area but now the following + * structure will incorporate the card structure along with CHDLC specific data + */ + +typedef struct chdlc_private_area +{ + netdevice_t *slave; + sdla_t *card; + int TracingEnabled; /* For enabling Tracing */ + unsigned long curr_trace_addr; /* Used for Tracing */ + unsigned long start_trace_addr; + unsigned long end_trace_addr; + unsigned long base_addr_trace_buffer; + unsigned long end_addr_trace_buffer; + unsigned short number_trace_elements; + unsigned available_buffer_space; + unsigned long router_start_time; + unsigned char route_status; + unsigned char route_removed; + unsigned long tick_counter; /* For 5s timeout counter */ + unsigned long router_up_time; + u32 IP_address; /* IP addressing */ + u32 IP_netmask; + unsigned char mc; /* Mulitcast support on/off */ + unsigned short udp_pkt_lgth; /* udp packet processing */ + char udp_pkt_src; + char udp_pkt_data[MAX_LGTH_UDP_MGNT_PKT]; + unsigned short timer_int_enabled; + char update_comms_stats; /* updating comms stats */ + //FIXME: add driver stats as per frame relay! + +} chdlc_private_area_t; + +/* Route Status options */ +#define NO_ROUTE 0x00 +#define ADD_ROUTE 0x01 +#define ROUTE_ADDED 0x02 +#define REMOVE_ROUTE 0x03 + + +/****** Function Prototypes *************************************************/ +/* WAN link driver entry points. These are called by the WAN router module. */ +static int wpft1_exec (struct sdla *card, void *u_cmd, void *u_data); +static int chdlc_read_version (sdla_t* card, char* str); +static int chdlc_error (sdla_t *card, int err, wan_mbox_t *mb); + +/****** Public Functions ****************************************************/ + +/*============================================================================ + * Cisco HDLC protocol initialization routine. + * + * This routine is called by the main WANPIPE module during setup. At this + * point adapter is completely initialized and firmware is running. + * o read firmware version (to make sure it's alive) + * o configure adapter + * o initialize protocol-specific fields of the adapter data space. + * + * Return: 0 o.k. + * < 0 failure. + */ +int wpft1_init (sdla_t* card, wandev_conf_t* conf) +{ + unsigned char port_num; + int err; + + union + { + char str[80]; + } u; + volatile wan_mbox_t* mb; + wan_mbox_t* mb1; + unsigned long timeout; + + /* Verify configuration ID */ + if (conf->config_id != WANCONFIG_CHDLC) { + printk(KERN_INFO "%s: invalid configuration ID %u!\n", + card->devname, conf->config_id); + return -EINVAL; + } + + /* Use primary port */ + card->u.c.comm_port = 0; + + + /* Initialize protocol-specific fields */ + /* Alex Apr 8 2004 Sangoma ISA card */ + card->mbox_off = PRI_BASE_ADDR_MB_STRUCT; + + mb = &card->wan_mbox; + mb1 = &card->wan_mbox; + + if (!card->configured){ + unsigned char return_code = 0x00; + + /* The board will place an 'I' in the return code to indicate that it is + ready to accept commands. We expect this to be completed in less + than 1 second. */ + + timeout = jiffies; + do { + return_code = 0x00; + card->hw_iface.peek(card->hw, + card->mbox_off+offsetof(wan_mbox_t, wan_return_code), + &return_code, + sizeof(unsigned char)); + if ((jiffies - timeout) > 1*HZ) break; + }while(return_code != 'I'); + if (return_code != 'I') { + printk(KERN_INFO + "%s: Initialization not completed by adapter\n", + card->devname); + printk(KERN_INFO "Please contact Sangoma representative.\n"); + return -EIO; + } + } + + /* Read firmware version. Note that when adapter initializes, it + * clears the mailbox, so it may appear that the first command was + * executed successfully when in fact it was merely erased. To work + * around this, we execute the first command twice. + */ + + if (chdlc_read_version(card, u.str)) + return -EIO; + + printk(KERN_INFO "%s: Running FT1 Configuration firmware v%s\n", + card->devname, u.str); + + card->isr = NULL; + card->poll = NULL; + card->exec = &wpft1_exec; + card->wandev.update = NULL; + card->wandev.new_if = NULL; + card->wandev.del_if = NULL; + card->wandev.state = WAN_DUALPORT; + card->wandev.udp_port = conf->udp_port; + + card->wandev.new_if_cnt = 0; + + /* This is for the ports link state */ + card->u.c.state = WAN_DISCONNECTED; + + /* reset the number of times the 'update()' proc has been called */ + card->u.c.update_call_count = 0; + + card->wandev.ttl = 0x7F; + card->wandev.interface = 0; + + card->wandev.clocking = 0; + + port_num = card->u.c.comm_port; + + /* Setup Port Bps */ + + card->wandev.bps = 0; + + card->wandev.mtu = MIN_LGTH_CHDLC_DATA_CFG; + + /* Set up the interrupt status area */ + /* Read the CHDLC Configuration and obtain: + * Ptr to shared memory infor struct + * Use this pointer to calculate the value of card->u.c.flags ! + */ + mb1->wan_data_len = 0; + mb1->wan_command = READ_CHDLC_CONFIGURATION; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb1); + if(err != COMMAND_OK) { + chdlc_error(card, err, mb1); + return -EIO; + } + + /* Alex Apr 8 2004 Sangoma ISA card */ + card->flags_off = + ((CHDLC_CONFIGURATION_STRUCT *)mb1->wan_data)-> + ptr_shared_mem_info_struct; + + card->intr_type_off = + card->flags_off + + offsetof(SHARED_MEMORY_INFO_STRUCT, interrupt_info_struct) + + offsetof(INTERRUPT_INFORMATION_STRUCT, interrupt_type); + card->intr_perm_off = + card->flags_off + + offsetof(SHARED_MEMORY_INFO_STRUCT, interrupt_info_struct) + + offsetof(INTERRUPT_INFORMATION_STRUCT, interrupt_permission); + + card->wandev.state = WAN_FT1_READY; + printk(KERN_INFO "%s: FT1 Config Ready !\n",card->devname); + + return 0; +} + +static int wpft1_exec(sdla_t *card, void *u_cmd, void *u_data) +{ + wan_mbox_t* mbox = &card->wan_mbox; + int len,err; + + + if (copy_from_user(mbox, u_cmd, sizeof(wan_cmd_t))){ + DEBUG_EVENT("%s:%d: Failed to copy mbox from user\n", + __FUNCTION__,__LINE__); + return -EFAULT; + } + + mbox->wan_opp_flag=0; + + len = mbox->wan_data_len; + + if (len) { + if(copy_from_user((void*)&mbox->wan_data, u_data, len)){ + DEBUG_EVENT("%s:%d: Failed to copy mbox data from user\n", + __FUNCTION__,__LINE__); + return -EFAULT; + } + } + + /* execute command */ + if ((err=card->hw_iface.cmd(card->hw, card->mbox_off, mbox)) != 0){ + DEBUG_EVENT("%s:%d: Failed FT1 command err=0x%X\n", + __FUNCTION__,__LINE__,err); + return -EIO; + } + + /* return result */ + if (copy_to_user(u_cmd, (void*)mbox, sizeof(wan_cmd_t))){ + DEBUG_EVENT("%s:%d: Failed to copy mbox to user\n", + __FUNCTION__,__LINE__); + return -EFAULT; + } + + len = mbox->wan_data_len; + + if (len && u_data && copy_to_user(u_data, (void*)&mbox->wan_data, len)){ + DEBUG_EVENT("%s:%d: Failed to copy mbox data to user\n", + __FUNCTION__,__LINE__); + return -EFAULT; + } + + return 0; + +} + +/*============================================================================ + * Read firmware code version. + * Put code version as ASCII string in str. + */ +static int chdlc_read_version (sdla_t* card, char* str) +{ + wan_mbox_t* mb = &card->wan_mbox; + int len; + char err; + mb->wan_data_len = 0; + mb->wan_command = READ_CHDLC_CODE_VERSION; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + + if(err != COMMAND_OK) { + chdlc_error(card,err,mb); + } + else if (str) { /* is not null */ + len = mb->wan_data_len; + memcpy(str, mb->wan_data, len); + str[len] = '\0'; + } + return (err); +} + +/*============================================================================ + * Firmware error handler. + * This routine is called whenever firmware command returns non-zero + * return code. + * + * Return zero if previous command has to be cancelled. + */ +static int chdlc_error (sdla_t *card, int err, wan_mbox_t *mb) +{ + unsigned cmd = mb->wan_command; + + switch (err) { + + case CMD_TIMEOUT: + printk(KERN_INFO "%s: command 0x%02X timed out!\n", + card->devname, cmd); + break; + + case S514_BOTH_PORTS_SAME_CLK_MODE: + if(cmd == SET_CHDLC_CONFIGURATION) { + printk(KERN_INFO + "%s: Configure both ports for the same clock source\n", + card->devname); + break; + } + + default: + printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n", + card->devname, cmd, err); + } + + return 0; +} + diff -Nur linux.org/drivers/net/wan/sdlamain.c linux-2.6.17/drivers/net/wan/sdlamain.c --- linux.org/drivers/net/wan/sdlamain.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/drivers/net/wan/sdlamain.c 2006-08-30 10:07:16.000000000 +0000 @@ -0,0 +1,2067 @@ +/**************************************************************************** +* sdlamain.c WANPIPE(tm) Multiprotocol WAN Link Driver. Main module. +* +* Author: Nenad Corbic +* Gideon Hack +* +* Copyright: (c) 1995-2002 Sangoma Technologies Inc. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version +* 2 of the License, or (at your option) any later version. +* ============================================================================ +* Jul 29, 2002 Nenad Corbic Addes support for SDLC driver +* May 13, 2002 Nenad Corbic Added the support for ADSL drivers +* Jan 2, 2002 Nenad Corbic Updated the request_region() function call. +* Due to the change in function interface. +* Nov 5, 2001 Nenad Corbic Changed the card_array into a card_list. +* Kernel limitation does not allow a large +* contigous memory allocation. This restricted +* the wanpipe drivers to 20 devices. +* May 8, 2001 Nenad Corbic Fixed the Piggiback bug introducted by +* the auto_pci_cfg update. Thus, do not use +* the slot number in piggyback testing, if +* the auto_pci_cfg option is enabled. +* Dec 22, 2000 Nenad Corbic Updated for 2.4.X kernels. +* Removed the polling routine. +* Nov 13, 2000 Nenad Corbic Added hw probing on module load and dynamic +* device allocation. +* Nov 7, 2000 Nenad Corbic Fixed the Multi-Port PPP for kernels +* 2.2.16 and above. +* Aug 2, 2000 Nenad Corbic Block the Multi-Port PPP from running on +* kernels 2.2.16 or greater. The SyncPPP +* has changed. +* Jul 25, 2000 Nenad Corbic Updated the Piggiback support for MultPPPP. +* Jul 13, 2000 Nenad Corbic Added Multi-PPP support. +* Feb 02, 2000 Nenad Corbic Fixed up piggyback probing and selection. +* Sep 23, 1999 Nenad Corbic Added support for SMP +* Sep 13, 1999 Nenad Corbic Each port is treated as a separate device. +* Jun 02, 1999 Gideon Hack Added support for the S514 adapter. +* Updates for Linux 2.2.X kernels. +* Sep 17, 1998 Jaspreet Singh Updated for 2.1.121+ kernel +* Nov 28, 1997 Jaspreet Singh Changed DRV_RELEASE to 1 +* Nov 10, 1997 Jaspreet Singh Changed sti() to restore_flags(); +* Nov 06, 1997 Jaspreet Singh Changed DRV_VERSION to 4 and DRV_RELEASE to 0 +* Oct 20, 1997 Jaspreet Singh Modified sdla_isr routine so that card->in_isr +* assignments are taken out and placed in the +* sdla_ppp.c, sdla_fr.c and sdla_x25.c isr +* routines. Took out 'wandev->tx_int_enabled' and +* replaced it with 'wandev->enable_tx_int'. +* May 29, 1997 Jaspreet Singh Flow Control Problem +* added "wandev->tx_int_enabled=1" line in the +* init module. This line intializes the flag for +* preventing Interrupt disabled with device set to +* busy +* Jan 15, 1997 Gene Kozin Version 3.1.0 +* o added UDP management stuff +* Jan 02, 1997 Gene Kozin Initial version. +*****************************************************************************/ + +#define _K22X_MODULE_FIX_ + +#include +#include +#include +#include +#include +#include /* WAN router definitions */ +#include +#include /* WANPIPE common user API definitions */ +#include +#include +#include +#include +#include + +#define KMEM_SAFETYZONE 8 + +#ifndef CONFIG_PRODUCT_WANPIPE_BASE + + #ifndef CONFIG_WANPIPE_FR + #define wpf_init(a,b) (-EPROTONOSUPPORT) + #endif + + #ifndef CONFIG_WANPIPE_CHDLC + #define wpc_init(a,b) (-EPROTONOSUPPORT) + #endif + + #ifndef CONFIG_WANPIPE_X25 + #define wpx_init(a,b) (-EPROTONOSUPPORT) + #endif + + #ifndef CONFIG_WANPIPE_PPP + #define wpp_init(a,b) (-EPROTONOSUPPORT) + #endif + + #ifndef CONFIG_WANPIPE_MULTPROT + #define wp_mprot_init(a,b) (-EPROTONOSUPPORT) + #endif + + #ifndef CONFIG_WANPIPE_LIP_ATM + #define wp_lip_atm_init(a,b) (-EPROTONOSUPPORT) + #endif + + #ifndef CONFIG_WANPIPE_MULTFR + #define wp_hdlc_fr_init(a,b) (-EPROTONOSUPPORT) + #endif + +#else + + #ifndef CONFIG_PRODUCT_WANPIPE_FR + #define wpf_init(a,b) (-EPROTONOSUPPORT) + #endif + + #ifndef CONFIG_PRODUCT_WANPIPE_CHDLC + #define wpc_init(a,b) (-EPROTONOSUPPORT) + #endif + + #ifndef CONFIG_PRODUCT_WANPIPE_X25 + #define wpx_init(a,b) (-EPROTONOSUPPORT) + #endif + + #ifndef CONFIG_PRODUCT_WANPIPE_PPP + #define wpp_init(a,b) (-EPROTONOSUPPORT) + #endif + + #ifndef CONFIG_PRODUCT_WANPIPE_MULTPROT + #define wp_mprot_init(a,b) (-EPROTONOSUPPORT) + #endif + + #ifndef CONFIG_WANPIPE_LIP_ATM + #define wp_lip_atm_init(a,b) (-EPROTONOSUPPORT) + #endif + + #ifndef CONFIG_PRODUCT_WANPIPE_MULTFR + #define wp_hdlc_fr_init(a,b) (-EPROTONOSUPPORT) + #endif + +#endif + + +#ifndef CONFIG_PRODUCT_WANPIPE_ASYHDLC + #define wp_asyhdlc_init(a,b) (-EPROTONOSUPPORT) +#endif + +#ifndef CONFIG_PRODUCT_WANPIPE_SDLC + #define wp_sdlc_init(a,b) (-EPROTONOSUPPORT) +#endif + +#ifndef CONFIG_PRODUCT_WANPIPE_EDU + #define wpedu_init(a,b) (-EPROTONOSUPPORT) +#endif + +#ifndef CONFIG_PRODUCT_WANPIPE_BSC + #define wpbsc_init(a,b) (-EPROTONOSUPPORT) +#endif + +#ifndef CONFIG_PRODUCT_WANPIPE_SS7 + #define wpss7_init(a,b) (-EPROTONOSUPPORT) +#endif + +#ifndef CONFIG_PRODUCT_WANPIPE_BSCSTRM + #define wp_bscstrm_init(a,b) (-EPROTONOSUPPORT) +#endif + +#ifndef CONFIG_PRODUCT_WANPIPE_BITSTRM + #define wpbit_init(a,b) (-EPROTONOSUPPORT) +#endif + +#ifndef CONFIG_PRODUCT_WANPIPE_ADSL + #define wp_adsl_init(card,conf) (-EPROTONOSUPPORT) +#endif + +#ifndef CONFIG_PRODUCT_WANPIPE_POS + #define wp_pos_init(card,conf) (-EPROTONOSUPPORT) +#endif + +#ifndef CONFIG_PRODUCT_WANPIPE_ATM + #define wp_atm_init(card,conf) (-EPROTONOSUPPORT) +#endif + +#ifndef CONFIG_PRODUCT_WANPIPE_AFT + #define wp_xilinx_init(card,conf) (-EPROTONOSUPPORT) +#endif + +#ifndef CONFIG_PRODUCT_WANPIPE_AFT_TE1 + #define wp_aft_te1_init(card,conf) (-EPROTONOSUPPORT) + #define wp_aft_analog_init(card,conf) (-EPROTONOSUPPORT) + #define aft_global_hw_device_init() +#endif + +#ifndef CONFIG_PRODUCT_WANPIPE_AFT_TE3 + #define wp_aft_te3_init(card,conf) (-EPROTONOSUPPORT) +#endif + +#ifndef CONFIG_PRODUCT_WANPIPE_ADCCP + #define wp_adccp_init(card,conf) (-EPROTONOSUPPORT) +#endif + + + +/***********FOR DEBUGGING PURPOSES********************************************* +static void * dbg_kmalloc(unsigned int size, int prio, int line) { + int i = 0; + void * v = kmalloc(size+sizeof(unsigned int)+2*KMEM_SAFETYZONE*8,prio); + char * c1 = v; + c1 += sizeof(unsigned int); + *((unsigned int *)v) = size; + + for (i = 0; i < KMEM_SAFETYZONE; i++) { + c1[0] = 'D'; c1[1] = 'E'; c1[2] = 'A'; c1[3] = 'D'; + c1[4] = 'B'; c1[5] = 'E'; c1[6] = 'E'; c1[7] = 'F'; + c1 += 8; + } + c1 += size; + for (i = 0; i < KMEM_SAFETYZONE; i++) { + c1[0] = 'M'; c1[1] = 'U'; c1[2] = 'N'; c1[3] = 'G'; + c1[4] = 'W'; c1[5] = 'A'; c1[6] = 'L'; c1[7] = 'L'; + c1 += 8; + } + v = ((char *)v) + sizeof(unsigned int) + KMEM_SAFETYZONE*8; + printk(KERN_INFO "line %d kmalloc(%d,%d) = %p\n",line,size,prio,v); + return v; +} +static void dbg_kfree(void * v, int line) { + unsigned int * sp = (unsigned int *)(((char *)v) - (sizeof(unsigned int) + KMEM_SAFETYZONE*8)); + unsigned int size = *sp; + char * c1 = ((char *)v) - KMEM_SAFETYZONE*8; + int i = 0; + for (i = 0; i < KMEM_SAFETYZONE; i++) { + if ( c1[0] != 'D' || c1[1] != 'E' || c1[2] != 'A' || c1[3] != 'D' + || c1[4] != 'B' || c1[5] != 'E' || c1[6] != 'E' || c1[7] != 'F') { + printk(KERN_INFO "kmalloced block at %p has been corrupted (underrun)!\n",v); + printk(KERN_INFO " %4x: %2x %2x %2x %2x %2x %2x %2x %2x\n", i*8, + c1[0],c1[1],c1[2],c1[3],c1[4],c1[5],c1[6],c1[7] ); + } + c1 += 8; + } + c1 += size; + for (i = 0; i < KMEM_SAFETYZONE; i++) { + if ( c1[0] != 'M' || c1[1] != 'U' || c1[2] != 'N' || c1[3] != 'G' + || c1[4] != 'W' || c1[5] != 'A' || c1[6] != 'L' || c1[7] != 'L' + ) { + printk(KERN_INFO "kmalloced block at %p has been corrupted (overrun):\n",v); + printk(KERN_INFO " %4x: %2x %2x %2x %2x %2x %2x %2x %2x\n", i*8, + c1[0],c1[1],c1[2],c1[3],c1[4],c1[5],c1[6],c1[7] ); + } + c1 += 8; + } + printk(KERN_INFO "line %d kfree(%p)\n",line,v); + v = ((char *)v) - (sizeof(unsigned int) + KMEM_SAFETYZONE*8); + kfree(v); +} + +#define kmalloc(x,y) dbg_kmalloc(x,y,__LINE__) +#define kfree(x) dbg_kfree(x,__LINE__) +******************************************************************************/ + + + +/****** Defines & Macros ****************************************************/ + +#ifdef _DEBUG_ +#define STATIC +#else +#define STATIC static +#endif + +#ifndef CONFIG_WANPIPE_CARDS /* configurable option */ +#define CONFIG_WANPIPE_CARDS 1 +#endif + +#define CMD_OK 0 /* normal firmware return code */ +#define CMD_TIMEOUT 0xFF /* firmware command timed out */ +#define MAX_CMD_RETRY 10 /* max number of firmware retries */ + +#define INVALID_ADAPTER_CHECK(card,cfg) \ + { \ + u16 adapter_type = 0x00; \ + card->hw_iface.getcfg(card->hw, SDLA_ADAPTERTYPE, &adapter_type); \ + if (adapter_type == S5144_ADPTR_1_CPU_T1E1 || \ + IS_TE1_MEDIA(&(cfg))){ \ + DEBUG_EVENT("%s: Error: Protocol not supported on S514-4 T1/E1 Adapter\n", \ + card->devname); \ + err = -EPFNOSUPPORT; \ + break; \ + }else if (adapter_type == S5145_ADPTR_1_CPU_56K || \ + IS_56K_MEDIA(&(cfg))){ \ + DEBUG_EVENT("%s: Error: Protocol not supported on S514-5 56K Adapter\n", \ + card->devname); \ + err = -EPFNOSUPPORT; \ + break; \ + } \ + } + +/****** Function Prototypes *************************************************/ + +extern void disable_irq(unsigned int); +extern void enable_irq(unsigned int); + +/* Module entry points */ +int init_module (void); +void cleanup_module (void); + +/* WAN link driver entry points */ +static int setup (wan_device_t* wandev, wandev_conf_t* conf); +static int shutdown (wan_device_t* wandev, wandev_conf_t* conf); +static int ioctl (wan_device_t* wandev, unsigned cmd, unsigned long arg); +static int debugging (wan_device_t* wandev); + +/* IOCTL handlers */ +static int ioctl_dump (sdla_t* card, sdla_dump_t* u_dump); +static int ioctl_exec (sdla_t* card, sdla_exec_t* u_exec, int); + +/* Miscellaneous functions */ +STATIC irqreturn_t sdla_isr (int irq, void* dev_id, struct pt_regs *regs); + +static void release_hw (sdla_t *card); + +static int check_s508_conflicts (sdla_t* card,wandev_conf_t* conf, int*); +static int check_s514_conflicts (sdla_t* card,wandev_conf_t* conf, int*); +static int check_adsl_conflicts (sdla_t* card,wandev_conf_t* conf, int*); +static int check_aft_conflicts (sdla_t* card,wandev_conf_t* conf, int*); + +static int wanpipe_register_fw_to_api(void); +static int wanpipe_unregister_fw_from_api(void); + + +/****** Global Data ********************************************************** + * Note: All data must be explicitly initialized!!! + */ + +/* private data */ +static char drvname[] = "wanpipe"; +static char fullname[] = "WANPIPE(tm) Multi-Protocol WAN Driver Module"; +static int ncards; + +static sdla_t* card_list; /* adapter data space */ +sdla_t* wanpipe_debug; + + +typedef struct{ + unsigned char name [100]; +}func_debug_t; + +static int DBG_ARRAY_CNT; +func_debug_t DEBUG_ARRAY[100]; + +/******* Kernel Loadable Module Entry Points ********************************/ + +/*============================================================================ + * Module 'insert' entry point. + * o print announcement + * o allocate adapter data space + * o initialize static data + * o register all cards with WAN router + * o calibrate SDLA shared memory access delay. + * + * Return: 0 Ok + * < 0 error. + * Context: process + */ + +MODULE_AUTHOR ("Nenad Corbic "); +MODULE_DESCRIPTION ("Sangoma WANPIPE: WAN Multi-Protocol Driver"); +MODULE_LICENSE("GPL"); + + +int __init wanpipe_init(void) +{ + int i, cnt, err = 0; + sdla_t *card,*tmpcard; + + ncards=0; + + if (WANPIPE_VERSION_BETA){ + DEBUG_EVENT("%s Beta%s-%s %s %s\n", + fullname, WANPIPE_SUB_VERSION, WANPIPE_VERSION, + WANPIPE_COPYRIGHT_DATES,WANPIPE_COMPANY); + }else{ + DEBUG_EVENT("%s Stable %s-%s %s %s\n", + fullname, WANPIPE_VERSION, WANPIPE_SUB_VERSION, + WANPIPE_COPYRIGHT_DATES,WANPIPE_COMPANY); + } + + /* Probe for wanpipe cards and return the number found */ + DEBUG_EVENT("wanpipe: Probing for WANPIPE hardware.\n"); + ncards = sdla_hw_probe(); + if (ncards){ + DEBUG_EVENT("wanpipe: Allocating maximum %i devices: wanpipe%i - wanpipe%i.\n", + ncards,1,ncards); + }else{ + DEBUG_EVENT("wanpipe: No AFT/S514/S508 cards found, unloading modules!\n"); + return -ENODEV; + } + + card_list=NULL; + wanpipe_debug=NULL; + + for (i=0;ilist; + kfree(tmpcard); + tmpcard=tmp; + } + card_list=NULL; + return -ENOMEM; + } + memset(tmpcard,0,sizeof(sdla_t)); + tmpcard->list=card_list; + card_list=tmpcard; + } + + cnt=0; + /* Register adapters with WAN router */ + for (card = card_list; card; card = card->list) { + + wan_device_t* wandev = &card->wandev; + + card->next = NULL; + sprintf(card->devname, "%s%d", drvname, ++cnt); + wandev->magic = ROUTER_MAGIC; + wandev->name = card->devname; + wandev->private = card; + wandev->enable_tx_int = 0; + wandev->setup = &setup; + wandev->shutdown = &shutdown; + wandev->ioctl = &ioctl; + wandev->debugging = &debugging; + err = register_wan_device(wandev); + if (err) { + DEBUG_EVENT("%s: %s registration failed with error %d!\n", + drvname, card->devname, err); + break; + } + } + if (cnt){ + ncards = cnt; /* adjust actual number of cards */ + }else { + sdla_t *tmp; + for (tmpcard=card_list;tmpcard;){ + unregister_wan_device(tmpcard->devname); + tmp=tmpcard->list; + kfree(tmpcard); + tmpcard=tmp; + } + card_list=NULL; + DEBUG_EVENT("IN Init Module: NO Cards registered\n"); + err = -ENODEV; + } + + if (err){ + return err; + } + + + err=wanpipe_register_fw_to_api(); + if (err){ + return err; + } + + err=wanpipe_codec_init(); + if (err){ + return err; + } + + wanpipe_globals_util_init(); + + aft_global_hw_device_init(); + +#if 0 + wp_tasklet_per_cpu_init(); +#endif + + return err; +} + +/*============================================================================ + * Module 'remove' entry point. + * o unregister all adapters from the WAN router + * o release all remaining system resources + */ +void __exit wanpipe_exit(void) +{ + sdla_t *tmpcard, *tmp; + + wanpipe_unregister_fw_from_api(); + + if (!card_list) + return; + + for (tmpcard=card_list;tmpcard;){ + unregister_wan_device(tmpcard->devname); + tmp=tmpcard->list; + kfree(tmpcard); + tmpcard=tmp; + } + + card_list=NULL; + + wanpipe_codec_free(); + + DEBUG_EVENT("\n"); + DEBUG_EVENT("wanpipe: WANPIPE Modules Unloaded.\n"); + +#if defined(WAN_DEBUG_MEM) + DEBUG_EVENT("wanpipe: Total Mem %d\n",atomic_read(&wan_debug_mem)); +#endif +} + +module_init(wanpipe_init); +module_exit(wanpipe_exit); + +/******* WAN Device Driver Entry Points *************************************/ + +/*============================================================================ + * Setup/configure WAN link driver. + * o check adapter state + * o make sure firmware is present in configuration + * o make sure I/O port and IRQ are specified + * o make sure I/O region is available + * o allocate interrupt vector + * o setup SDLA hardware + * o call appropriate routine to perform protocol-specific initialization + * o mark I/O region as used + * o if this is the first active card, then schedule background task + * + * This function is called when router handles ROUTER_SETUP IOCTL. The + * configuration structure is in kernel memory (including extended data, if + * any). + */ + +static int setup (wan_device_t* wandev, wandev_conf_t* conf) +{ + sdla_t* card; + int err = 0; + int irq=0; + + /* Sanity checks */ + if ((wandev == NULL) || (wandev->private == NULL) || (conf == NULL)){ + DEBUG_EVENT("%s: Failed Sdlamain Setup wandev %u, card %u, conf %u !\n", + wandev->name, + (unsigned int)wandev,(unsigned int)wandev->private, + (unsigned int)conf); + return -EFAULT; + } + + DEBUG_EVENT("%s: Starting WAN Setup\n", wandev->name); + + card = wandev->private; + if (wandev->state != WAN_UNCONFIGURED){ + DEBUG_EVENT("%s: Device already configured\n", + wandev->name); + return -EBUSY; /* already configured */ + } + card->wandev.piggyback = 0; + + DEBUG_EVENT("\n"); + DEBUG_EVENT("Processing WAN device %s...\n", wandev->name); + + /* Initialize the counters for each wandev + * Used for counting number of times new_if and + * del_if get called. + */ + wandev->del_if_cnt = 0; + wandev->new_if_cnt = 0; + wandev->config_id = conf->config_id; + switch(conf->config_id){ + case WANCONFIG_AFT: + conf->card_type = WANOPT_AFT; + break; + case WANCONFIG_AFT_TE1: + conf->card_type = WANOPT_AFT104; + conf->S514_CPU_no[0] = 'A'; + break; + case WANCONFIG_AFT_ANALOG: + conf->card_type = WANOPT_AFT_ANALOG; + conf->S514_CPU_no[0] = 'A'; + break; + case WANCONFIG_AFT_TE3: + conf->card_type = WANOPT_AFT300; + conf->S514_CPU_no[0] = 'A'; + break; + } + + wandev->card_type = conf->card_type; + card->hw = sdla_register(&card->hw_iface, conf, card->devname); + if (card->hw == NULL){ + return -EINVAL; + } + + /* Check for resource conflicts and setup the + * card for piggibacking if necessary */ + switch (conf->card_type){ + + case WANOPT_S50X: + + if (!conf->data_size || (conf->data == NULL)) { + DEBUG_EVENT("%s: firmware not found in configuration data!\n", + wandev->name); + sdla_unregister(&card->hw, card->devname); + return -EINVAL; + } + + if ((err=check_s508_conflicts(card,conf,&irq)) != 0){ + sdla_unregister(&card->hw, card->devname); + return err; + } + break; + + case WANOPT_S51X: + + if ((!conf->data_size || (conf->data == NULL)) && + (conf->config_id != WANCONFIG_DEBUG)){ + DEBUG_EVENT("%s: firmware not found in configuration data!\n", + wandev->name); + sdla_unregister(&card->hw, card->devname); + return -EINVAL; + } + if ((err=check_s514_conflicts(card,conf,&irq)) != 0){ + sdla_unregister(&card->hw, card->devname); + return err; + } + break; + + case WANOPT_ADSL: + + if ((err=check_adsl_conflicts(card,conf,&irq)) != 0){ + sdla_unregister(&card->hw, card->devname); + return err; + } + break; + + case WANOPT_AFT: + case WANOPT_AFT104: + case WANOPT_AFT300: + case WANOPT_AFT_ANALOG: + + err=0; + if ((err=check_aft_conflicts(card,conf,&irq)) != 0){ + sdla_unregister(&card->hw, card->devname); + return err; + } + break; + + default: + DEBUG_EVENT("%s: ERROR, invalid card type 0x%0X!\n", + card->devname,conf->card_type); + sdla_unregister(&card->hw, card->devname); + return -EINVAL; + } + + card->hw_iface.getcfg(card->hw, SDLA_CARDTYPE, &card->type); + card->hw_iface.getcfg(card->hw, SDLA_ADAPTERTYPE, &card->adptr_type); + card->hw_iface.getcfg(card->hw, SDLA_ADAPTERSUBTYPE, &card->adptr_subtype); + card->isr=NULL; + + /* If the current card has already been configured + * or its a piggyback card, do not try to allocate + * resources. + */ + if (!card->wandev.piggyback && !card->configured){ + + err = card->hw_iface.setup(card->hw, conf); + if (err){ + DEBUG_EVENT("%s: Hardware setup Failed %i\n", + card->devname,err); + card->hw_iface.down(card->hw); + sdla_unregister(&card->hw, card->devname); + return err; + } + + if (conf->config_id == WANCONFIG_DEBUG){ + if (wanpipe_debug){ + DEBUG_EVENT("%s: More than 2 debugging cards!\n", + card->devname); + card->hw_iface.down(card->hw); + sdla_unregister(&card->hw, card->devname); + return -EINVAL; + } + wanpipe_debug = card; + wanpipe_debug->u.debug.total_len = 0; + wanpipe_debug->u.debug.total_num = 0; + wanpipe_debug->u.debug.current_offset = + sizeof(wanpipe_kernel_msg_hdr_t); + wanpipe_debug->configured = 1; + wanpipe_debug->wandev.state = WAN_CONNECTED; + wanpipe_debug->wandev.debug_read = wan_debug_read; + //wanpipe_debug->adapter_type = card->hw.pci_adapter_type; + spin_lock_init(&wanpipe_debug->wandev.lock); + return 0; + } + if(conf->card_type == WANOPT_S50X){ + irq = (conf->irq == 2) ? 9 : conf->irq; /* IRQ2 -> IRQ9 */ + }else{ + irq = conf->irq; + } + spin_lock_init(&card->wandev.lock); + + /* request an interrupt vector - note that interrupts may be shared */ + /* when using the S514 PCI adapter */ + if (card->wandev.config_id != WANCONFIG_BSC && card->wandev.config_id != WANCONFIG_POS){ + if(request_irq(irq, sdla_isr, + (card->type == SDLA_S508) ? 0: SA_SHIRQ, + wandev->name, card)){ + + DEBUG_EVENT("%s: Can't reserve IRQ %d!\n", + wandev->name, irq); + card->hw_iface.down(card->hw); + sdla_unregister(&card->hw, card->devname); + return -EINVAL; + } + } + + }else{ + DEBUG_EVENT("%s: Card Configured %li or Piggybacking %i!\n", + wandev->name,card->configured,card->wandev.piggyback); + spin_lock_init(&card->wandev.lock); + } + + if (!card->configured){ + + /* Intialize WAN device data space */ + wandev->irq = irq; + wandev->dma = 0; + if(conf->card_type == WANOPT_S50X){ + card->hw_iface.getcfg(card->hw, SDLA_IOPORT, &wandev->ioport); + }else{ + card->hw_iface.getcfg(card->hw, SDLA_CPU, &wandev->S514_cpu_no[0]); + card->hw_iface.getcfg(card->hw, SDLA_SLOT, &wandev->S514_slot_no); + } +#if 0 + // ALEX_TODAY + wandev->maddr = (unsigned long)card->hw.dpmbase; + wandev->msize = card->hw.dpmsize; + wandev->hw_opt[0] = card->hw.type; + wandev->hw_opt[1] = card->hw.pclk; + wandev->hw_opt[2] = card->hw.memory; + wandev->hw_opt[3] = card->hw.fwid; +#endif + } + + /* Debugging: Read PCI adapter type */ + //card->adapter_type = card->hw.pci_adapter_type; + card->hw_iface.getcfg(card->hw, SDLA_ADAPTERTYPE, &card->adptr_type); + + /* Protocol-specific initialization */ + switch (conf->config_id) { + + case WANCONFIG_X25: + DEBUG_EVENT("%s: Starting x25 Protocol Init.\n", + card->devname); + + INVALID_ADAPTER_CHECK(card,conf->fe_cfg); + err = wpx_init(card, conf); + break; + + case WANCONFIG_FR: + DEBUG_EVENT("%s: Starting Frame Relay Protocol Init.\n", + card->devname); + err = wpf_init(card, conf); + break; + + case WANCONFIG_PPP: + DEBUG_EVENT("%s: Starting PPP Protocol Init.\n", + card->devname); + err = wpp_init(card, conf); + break; + + case WANCONFIG_SDLC: + DEBUG_EVENT("%s: Starting SDLC Protocol Init.\n", + card->devname); + err = wp_sdlc_init(card, conf); + break; + + case WANCONFIG_ASYHDLC: + DEBUG_EVENT("%s: Starting ASY HDLC Protocol Init.\n", + card->devname); + err = wp_asyhdlc_init(card, conf); + break; + + case WANCONFIG_CHDLC: + if (conf->ft1){ + DEBUG_EVENT("%s: Starting FT1 CSU/DSU Config Driver.\n", + card->devname); + err = wpft1_init(card, conf); + break; + + }else{ + DEBUG_EVENT("%s: Starting CHDLC Protocol Init.\n", + card->devname); + err = wpc_init(card, conf); + break; + } + break; + + case WANCONFIG_MPROT: + + DEBUG_EVENT("%s: Starting Multi Protocol Driver Init.\n", + card->devname); + err = wp_mprot_init(card,conf); + break; + + case WANCONFIG_MFR: + DEBUG_EVENT("%s: Starting Multi-Port Frame Relay Protocol Init.\n", + card->devname); + err = wp_hdlc_fr_init(card,conf); + break; + + /* Extra, non-standard WANPIPE Protocols */ + case WANCONFIG_BITSTRM: + DEBUG_EVENT("%s: Starting Bit Stream Protocol Init.\n", + card->devname); + err = wpbit_init(card, conf); + break; + + + case WANCONFIG_EDUKIT: + DEBUG_EVENT("%s: Starting Educational mode.\n", + card->devname); + err = wpedu_init(card, conf); + break; + + case WANCONFIG_BSC: + DEBUG_EVENT("%s: Starting Bisync API Protocol Init.\n", + card->devname); + INVALID_ADAPTER_CHECK(card,conf->fe_cfg); + err = wpbsc_init(card,conf); + break; + + case WANCONFIG_SS7: + DEBUG_EVENT("%s: Starting SS7 API Protocol Init.\n", + card->devname); + err = wpss7_init(card,conf); + break; + + case WANCONFIG_BSCSTRM: + DEBUG_EVENT("%s: Starting BiSync Streaming API Init.\n", + card->devname); + INVALID_ADAPTER_CHECK(card,conf->fe_cfg); + err = wp_bscstrm_init(card,conf); + break; + + case WANCONFIG_ADSL: + DEBUG_EVENT("%s: Starting ADSL Device Init.\n", + card->devname); + err = wp_adsl_init(card,conf); + break; + + case WANCONFIG_ATM: + DEBUG_EVENT("%s: Starting ATM Protocol Init.\n", + card->devname); + err = wp_atm_init(card,conf); + break; + + case WANCONFIG_POS: + DEBUG_EVENT("%s: Starting POS Protocol Init.\n", + card->devname); + err = wp_pos_init(card,conf); + break; + + case WANCONFIG_ADCCP: + DEBUG_EVENT("%s: Starting ADCCP Protocol Init.\n", + card->devname); + err = wp_adccp_init(card,conf); + break; + + case WANCONFIG_AFT: + DEBUG_EVENT("%s: Starting AFT Hardware Init.\n", + card->devname); + err = wp_xilinx_init(card,conf); + break; + + case WANCONFIG_AFT_TE1: + DEBUG_EVENT("%s: Starting AFT Quad Hardware Init.\n", + card->devname); + err = wp_aft_te1_init(card,conf); + break; + + case WANCONFIG_AFT_ANALOG: + DEBUG_EVENT("%s: Starting AFT Analog Hardware Init.\n", + card->devname); + err = wp_aft_analog_init(card,conf); + break; + + case WANCONFIG_AFT_TE3: + DEBUG_EVENT("%s: Starting AFT TE3 Hardware Init.\n", + card->devname); + err = wp_aft_te3_init(card,conf); + break; + +#if 0 + case WANCONFIG_LIP_ATM: + DEBUG_EVENT("%s: Starting ATM MultiProtocol Driver Init.\n", + card->devname); + err = wp_lip_atm_init(card,conf); + break; +#endif + default: + DEBUG_EVENT("%s: Error, Protocol is not supported %u!\n", + wandev->name, conf->config_id); + + err = -EPROTONOSUPPORT; + } + + if (err != 0){ + if (err == -EPROTONOSUPPORT){ + DEBUG_EVENT("%s: Error, Protocol selected has not been compiled!\n", + card->devname); + DEBUG_EVENT("%s: Re-configure the kernel and re-build the modules!\n", + card->devname); + } + + if (card->disable_comm){ + card->disable_comm(card); + } + + release_hw(card); + wandev->state = WAN_UNCONFIGURED; + + card->configured=0; + sdla_unregister(&card->hw, card->devname); + if (card->next){ + card->next->next=NULL; + card->next=NULL; + } + return err; + } + + /* + * Register Protocol proc directory entry + */ + err = wanrouter_proc_add_protocol(wandev); + + if (err) { + DEBUG_EVENT("%s: can't create /proc/net/wanrouter/ entry!\n", + card->devname); + if (card->disable_comm){ + card->disable_comm(card); + } + release_hw(card); + wandev->state = WAN_UNCONFIGURED; + + card->configured=0; + sdla_unregister(&card->hw, card->devname); + if (card->next){ + card->next->next=NULL; + card->next=NULL; + } + + return err; + } + + /* Reserve I/O region and schedule background task */ + if(conf->card_type == WANOPT_S50X && !card->wandev.piggyback){ + u16 io_range; + card->hw_iface.getcfg(card->hw, SDLA_IORANGE, &io_range); +#if defined(LINUX_2_4) || defined(LINUX_2_6) + if (!request_region(wandev->ioport, io_range, wandev->name)){ + DEBUG_EVENT("%s: Failed to reserve IO region!\n", + card->devname); + wanrouter_proc_delete_protocol(wandev); + if (card->disable_comm){ + card->disable_comm(card); + } + release_hw(card); + wandev->state = WAN_UNCONFIGURED; + + card->configured=0; + sdla_unregister(&card->hw, card->devname); + if (card->next){ + card->next->next=NULL; + card->next=NULL; + } + return -EBUSY; + } +#else + request_region(wandev->ioport, io_range, wandev->name); +#endif + } + + /* Only use the polling routine for the X25 protocol */ + WAN_DEBUG_INIT(card); + + card->wandev.critical=0; + return 0; +} + +/*================================================================== + * configure_s508_card + * + * For a S508 adapter, check for a possible configuration error in that + * we are loading an adapter in the same IO port as a previously loaded S508 + * card. + */ + +static int check_s508_conflicts (sdla_t* card,wandev_conf_t* conf, int *irq) +{ + unsigned long smp_flags; + sdla_t* nxt_card; + + if (conf->ioport <= 0) { + DEBUG_EVENT("%s: can't configure without I/O port address!\n", + card->wandev.name); + return -EINVAL; + } + + if (conf->irq <= 0) { + DEBUG_EVENT("%s: can't configure without IRQ!\n", + card->wandev.name); + return -EINVAL; + } + + if (test_bit(0,&card->configured)) + return 0; + + + /* Check for already loaded card with the same IO port and IRQ + * If found, copy its hardware configuration and use its + * resources (i.e. piggybacking) + */ + + for (nxt_card=card_list;nxt_card;nxt_card=nxt_card->list) { + + /* Skip the current card ptr */ + if (nxt_card == card) + continue; + + /* Find a card that is already configured with the + * same IO Port */ + if (nxt_card->hw == card->hw){ + + /* We found a card the card that has same configuration + * as us. This means, that we must setup this card in + * piggibacking mode. However, only CHDLC and MPPP protocol + * support this setup */ + + if ((nxt_card->next == NULL) && + ((conf->config_id == WANCONFIG_CHDLC && + nxt_card->wandev.config_id == WANCONFIG_CHDLC) || + (conf->config_id == WANCONFIG_MPPP && + nxt_card->wandev.config_id == WANCONFIG_MPPP) || + (conf->config_id == WANCONFIG_ASYHDLC && + nxt_card->wandev.config_id == WANCONFIG_ASYHDLC) || + (conf->config_id == WANCONFIG_BSCSTRM && + nxt_card->wandev.config_id == WANCONFIG_BSCSTRM))){ + + *irq = nxt_card->wandev.irq; //ALEX_TODAY nxt_card->hw.irq; + + /* The master could already be running, we must + * set this as a critical area */ + wan_spin_lock_irq(&nxt_card->wandev.lock, &smp_flags); + + nxt_card->next = card; + card->next = nxt_card; + + card->wandev.piggyback = WANOPT_YES; + + /* We must initialise the piggiback spin lock here + * since isr will try to lock card->next if it + * exists */ + spin_lock_init(&card->wandev.lock); + + wan_spin_unlock_irq(&nxt_card->wandev.lock, &smp_flags); + break; + }else{ + /* Trying to run piggibacking with a wrong protocol */ + DEBUG_EVENT("%s: ERROR: Resource busy, ioport: 0x%x\n" + "%s: This protocol doesn't support\n" + "%s: multi-port operation!\n", + card->devname, nxt_card->wandev.ioport, + card->devname,card->devname); + DEBUG_EVENT("%s: Pri Prot = 0x%X Sec Prot = 0x%X\n", + card->devname,nxt_card->wandev.config_id, + conf->config_id); + return -EEXIST; + } + } + } + + + /* Make sure I/O port region is available only if we are the + * master device. If we are running in piggibacking mode, + * we will use the resources of the master card */ +#ifndef LINUX_2_6 + if (check_region(conf->ioport, SDLA_MAXIORANGE) && + !card->wandev.piggyback) { + DEBUG_EVENT("%s: I/O region 0x%X - 0x%X is in use!\n", + card->wandev.name, conf->ioport, + conf->ioport + SDLA_MAXIORANGE); + return -EINVAL; + } +#endif + + return 0; +} + +/*================================================================== + * configure_s514_card + * + * For a S514 adapter, check for a possible configuration error in that + * we are loading an adapter in the same slot as a previously loaded S514 + * card. + */ + + +static int check_s514_conflicts(sdla_t* card,wandev_conf_t* conf, int *irq) +{ + unsigned long smp_flags; + sdla_t* nxt_card; + + if (test_bit(0,&card->configured)) + return 0; + + /* Check for already loaded card with the same IO port, Bus no and IRQ + * If found, copy its hardware configuration and use its + * resources (i.e. piggybacking) + */ + + for (nxt_card=card_list;nxt_card;nxt_card=nxt_card->list) { + + if (nxt_card == card) + continue; + + if (nxt_card->wandev.state == WAN_UNCONFIGURED) + continue; + + /* Bug Fix: + * If we are using auto PCI slot detection: + * assume that new pci slot is the same as + * the pci slot of the already configured card + * ie. (nxt_card). + * + * The reason for this is, when the pci slot is found + * the card->hw.PCI_slot_no is updated with the + * found slot number + * + * Thus, do not use the PCI_slot_no to detect a + * piggyback condition if the auto_pci_cfg option + * is enabled. + */ + if (nxt_card->hw == card->hw){ + + if ((nxt_card->next == NULL) && + ((conf->config_id == WANCONFIG_CHDLC && + nxt_card->wandev.config_id == WANCONFIG_CHDLC) || + (conf->config_id == WANCONFIG_MPPP && + nxt_card->wandev.config_id == WANCONFIG_MPPP) || + (conf->config_id == WANCONFIG_ASYHDLC && + nxt_card->wandev.config_id == WANCONFIG_ASYHDLC) || + (conf->config_id == WANCONFIG_BSCSTRM && + nxt_card->wandev.config_id == WANCONFIG_BSCSTRM))){ + + *irq = nxt_card->wandev.irq; //ALEX_TODAY nxt_card->hw.irq; + + /* The master could already be running, we must + * set this as a critical area */ + wan_spin_lock_irq(&nxt_card->wandev.lock,&smp_flags); + nxt_card->next = card; + card->next = nxt_card; + + card->wandev.piggyback = WANOPT_YES; + + /* We must initialise the piggiback spin lock here + * since isr will try to lock card->next if it + * exists */ + spin_lock_init(&card->wandev.lock); + + wan_spin_unlock_irq(&nxt_card->wandev.lock,&smp_flags); + + }else{ + /* Trying to run piggibacking with a wrong protocol */ + DEBUG_EVENT("%s: ERROR: Resource busy: CPU %c PCISLOT %i\n" + "%s: This protocol doesn't support\n" + "%s: multi-port operation!\n", + card->devname, + conf->S514_CPU_no[0],conf->PCI_slot_no, + card->devname,card->devname); + DEBUG_EVENT("%s: Pri Prot = 0x%X Sec Prot = 0x%X\n", + card->devname,nxt_card->wandev.config_id, + conf->config_id); + return -EEXIST; + } + } + } + + return 0; +} + + +/*================================================================== + * configure_s514_card + * + * For a S514 adapter, check for a possible configuration error in that + * we are loading an adapter in the same slot as a previously loaded S514 + * card. + */ + + +static int check_adsl_conflicts(sdla_t* card,wandev_conf_t* conf, int *irq) +{ + sdla_t* nxt_card; + + if (test_bit(0,&card->configured)) + return 0; + + + /* Check for already loaded card with the same IO port, Bus no and IRQ + * If found, copy its hardware configuration and use its + * resources (i.e. piggybacking) + */ + + for (nxt_card=card_list;nxt_card;nxt_card=nxt_card->list) { + + if (nxt_card == card) + continue; + + if (nxt_card->wandev.state == WAN_UNCONFIGURED) + continue; + + /* Bug Fix: + * If we are using auto PCI slot detection: + * assume that new pci slot is the same as + * the pci slot of the already configured card + * ie. (nxt_card). + * + * The reason for this is, when the pci slot is found + * the card->hw.PCI_slot_no is updated with the + * found slot number + * + * Thus, do not use the PCI_slot_no to detect a + * piggyback condition if the auto_pci_cfg option + * is enabled. + */ + if (nxt_card->hw == card->hw){ + /* Trying to run piggibacking with a wrong protocol */ + DEBUG_EVENT("%s: ERROR: Resource busy: CPU %c PCISLOT %i\n" + "%s: This protocol doesn't support\n" + "%s: multi-port operation!\n", + card->devname, + conf->S514_CPU_no[0],conf->PCI_slot_no, + card->devname,card->devname); + return -EEXIST; + } + } + + return 0; +} + + +/*================================================================== + * configure_s514_card + * + * For a S514 adapter, check for a possible configuration error in that + * we are loading an adapter in the same slot as a previously loaded S514 + * card. + */ + + +static int check_aft_conflicts(sdla_t* card,wandev_conf_t* conf, int *irq) +{ + sdla_t* nxt_card; + + if (test_bit(0,&card->configured)) + return 0; + + + /* Check for already loaded card with the same IO port, Bus no and IRQ + * If found, copy its hardware configuration and use its + * resources (i.e. piggybacking) + */ + + for (nxt_card=card_list;nxt_card;nxt_card=nxt_card->list) { + + if (nxt_card == card) + continue; + + if (nxt_card->wandev.state == WAN_UNCONFIGURED) + continue; + + /* Bug Fix: + * If we are using auto PCI slot detection: + * assume that new pci slot is the same as + * the pci slot of the already configured card + * ie. (nxt_card). + * + * The reason for this is, when the pci slot is found + * the card->hw.PCI_slot_no is updated with the + * found slot number + * + * Thus, do not use the PCI_slot_no to detect a + * piggyback condition if the auto_pci_cfg option + * is enabled. + */ + if (nxt_card->hw == card->hw){ + u16 CPU_no; + + card->hw_iface.getcfg(card->hw, SDLA_CPU, &CPU_no); + if (CPU_no == conf->S514_CPU_no[0]){ + /* Trying to run piggibacking with a + * wrong protocol */ + DEBUG_EVENT("%s: ERROR: Resource busy: CPU %c PCISLOT %i\n" + "%s: This protocol doesn't support\n" + "%s: multi-port operation!\n", + card->devname, + conf->S514_CPU_no[0],conf->PCI_slot_no, + card->devname,card->devname); + return -EEXIST; + } + } + } + + return 0; +} + + +/*============================================================================ + * Shut down WAN link driver. + * o shut down adapter hardware + * o release system resources. + * + * This function is called by the router when device is being unregistered or + * when it handles ROUTER_DOWN IOCTL. + */ +static int shutdown (wan_device_t* wandev, wandev_conf_t* conf) +{ + sdla_t* card = NULL; + int err=0; + + /* sanity checks */ + if ((wandev == NULL) || (wandev->private == NULL)){ + return -EFAULT; + } + + if (wandev->state == WAN_UNCONFIGURED){ + return 0; + } + + card = wandev->private; + + if (card->tty_opt){ + if (card->tty_open){ + DEBUG_EVENT("%s: Shutdown Failed: TTY is still open\n", + card->devname); + return -EBUSY; + } + } + + wandev->state = WAN_UNCONFIGURED; + + if (wandev->config_id == WANCONFIG_DEBUG){ + wanpipe_debug = NULL; + } + +#ifdef CONFIG_PRODUCT_WANPIPE_ADSL + if (wandev->config_id == WANCONFIG_ADSL && conf != NULL){ + /* Update ADSL VCI/VPI standart list + */ + adsl_vcivpi_update(card, conf); + conf->config_id = wandev->config_id; + } +#endif + set_bit(PERI_CRIT,(void*)&wandev->critical); + + /* Stop debugging sequence: debugging task and timer */ + WAN_DEBUG_END(card); + + /* In case of piggibacking, make sure that + * we never try to shutdown both devices at the same + * time, because they depend on one another */ + + if (card->disable_comm){ + card->disable_comm(card); + } + + wandev->state = WAN_UNCONFIGURED; + + /* Release Resources */ + release_hw(card); + + wandev->state = WAN_UNCONFIGURED; + + /* only free the allocated I/O range if not an S514 adapter */ + if (card->type != SDLA_S514 && + card->type != SDLA_ADSL && + card->type != SDLA_AFT && + wandev->config_id != WANCONFIG_DEBUG && + !card->configured){ + u16 io_range; + card->hw_iface.getcfg(card->hw, SDLA_IORANGE, &io_range); + release_region(wandev->ioport, io_range); + } + + if (!card->configured){ + sdla_unregister(&card->hw, card->devname); + if (card->next){ + sdla_unregister(&card->next->hw, card->next->devname); + card->next->next=NULL; + card->next=NULL; + } + } + + wanrouter_proc_delete_protocol(wandev); + + clear_bit(PERI_CRIT,(void*)&wandev->critical); + + return err; +} + +static void release_hw (sdla_t *card) +{ + sdla_t *nxt_card; + + /* Check if next device exists */ + if (card->next){ + nxt_card = card->next; + /* If next device is down then release resources */ + if (nxt_card->wandev.state == WAN_UNCONFIGURED){ + if (card->wandev.piggyback){ + /* If this device is piggyback then use + * information of the master device + */ + DEBUG_EVENT("%s: Piggyback shutting down\n",card->devname); + if (card->hw_iface.down){ + card->hw_iface.down(card->next->hw); + } + if (card->wandev.config_id != WANCONFIG_BSC && + card->wandev.config_id != WANCONFIG_POS){ + free_irq(card->wandev.irq, card->next); + } + card->configured = 0; + card->next->configured = 0; + card->wandev.piggyback = 0; + + }else{ + /* Master device shutting down */ + DEBUG_EVENT("%s: Master shutting down\n",card->devname); + if (card->hw_iface.down){ + card->hw_iface.down(card->hw); + } + if (card->wandev.config_id != WANCONFIG_BSC && + card->wandev.config_id != WANCONFIG_POS){ + free_irq(card->wandev.irq, card); + } + card->configured = 0; + card->next->configured = 0; + } + + }else{ + DEBUG_EVENT("%s: Device still running state=%i\n", + nxt_card->devname,nxt_card->wandev.state); + + card->configured = 1; + } + }else{ + DEBUG_EVENT("%s: Master shutting down\n",card->devname); + + if (card->hw_iface.down){ + card->hw_iface.down(card->hw); + } + if (card->wandev.config_id != WANCONFIG_BSC && + card->wandev.config_id != WANCONFIG_POS && + card->wandev.config_id != WANCONFIG_DEBUG){ + free_irq(card->wandev.irq, card); + } + card->configured = 0; + } + return; +} + + +/*============================================================================ + * Driver I/O control. + * o verify arguments + * o perform requested action + * + * This function is called when router handles one of the reserved user + * IOCTLs. Note that 'arg' stil points to user address space. + */ +static int ioctl (wan_device_t* wandev, unsigned cmd, unsigned long arg) +{ + sdla_t* card; + int err; + + /* sanity checks */ + if ((wandev == NULL) || (wandev->private == NULL)) + return -EFAULT; + //ALEX-HWABSTR +// if (wandev->state == WAN_UNCONFIGURED) +// return -ENODEV; + + card = wandev->private; + + if (test_bit(SEND_CRIT, (void*)&wandev->critical)) { + return -EAGAIN; + } + + switch (cmd) { + case WANPIPE_DUMP: + err = ioctl_dump(wandev->private, (void*)arg); + break; + + case WANPIPE_EXEC: + err = ioctl_exec(wandev->private, (void*)arg, cmd); + break; + default: + err = -EINVAL; + } + + return err; +} + +/****** Driver IOCTL Handlers ***********************************************/ + +/*============================================================================ + * Dump adapter memory to user buffer. + * o verify request structure + * o copy request structure to kernel data space + * o verify length/offset + * o verify user buffer + * o copy adapter memory image to user buffer + * + * Note: when dumping memory, this routine switches curent dual-port memory + * vector, so care must be taken to avoid racing conditions. + */ +static int ioctl_dump (sdla_t* card, sdla_dump_t* u_dump) +{ + sdla_dump_t dump; + void* data; + u32 memory; + int err = 0; + + if(copy_from_user((void*)&dump, (void*)u_dump, sizeof(sdla_dump_t))) + return -EFAULT; + + card->hw_iface.getcfg(card->hw, SDLA_MEMORY, &memory); + if ((dump.magic != WANPIPE_MAGIC) || + (dump.offset + dump.length > memory)){ + return -EINVAL; + } + + data = kmalloc(dump.length, GFP_KERNEL); + if (data == NULL){ + return -ENOMEM; + } + + card->hw_iface.peek(card->hw, dump.offset, data, dump.length); + + if(copy_to_user((void *)dump.ptr, data, dump.length)){ + err = -EFAULT; + } + kfree(data); + return err; +} + +/*============================================================================ + * Execute adapter firmware command. + * o verify request structure + * o copy request structure to kernel data space + * o call protocol-specific 'exec' function + */ +static int ioctl_exec (sdla_t* card, sdla_exec_t* u_exec, int cmd) +{ + sdla_exec_t exec; + int err=0; + + if (card->exec == NULL && cmd == WANPIPE_EXEC){ + return -ENODEV; + } + + if(copy_from_user((void*)&exec, (void*)u_exec, sizeof(sdla_exec_t))) + return -EFAULT; + + if ((exec.magic != WANPIPE_MAGIC) || (exec.cmd == NULL)) + return -EINVAL; + + switch (cmd) { + case WANPIPE_EXEC: + err = card->exec(card, exec.cmd, exec.data); + break; + } + return err; +} + +/******* Miscellaneous ******************************************************/ + +/*============================================================================ + * SDLA Interrupt Service Routine. + * o acknowledge SDLA hardware interrupt. + * o call protocol-specific interrupt service routine, if any. + */ +STATIC irqreturn_t sdla_isr (int irq, void* dev_id, struct pt_regs *regs) +{ +#define card ((sdla_t*)dev_id) + + if (card && card->type == SDLA_AFT){ + + spin_lock(&card->wandev.lock); + if (card->isr){ + card->isr(card); + } + spin_unlock(&card->wandev.lock); + + WAN_IRQ_RETVAL(IRQ_HANDLED); + } + + if (card && card->type == SDLA_ADSL){ + unsigned long flags; + spin_lock_irqsave(&card->wandev.lock,flags); + if (card->isr){ + card->isr(card); + } + spin_unlock_irqrestore(&card->wandev.lock,flags); + WAN_IRQ_RETVAL(IRQ_HANDLED); + } + + if(card->type == SDLA_S514) { /* handle interrrupt on S514 */ + u32 int_status; + u16 CPU_no; + unsigned char card_found_for_IRQ; + + card->hw_iface.getcfg(card->hw, SDLA_CPU, &CPU_no); + if (card->hw_iface.read_int_stat){ + card->hw_iface.read_int_stat(card->hw, &int_status); + } + + /* check if the interrupt is for this device */ + if(!((unsigned char)int_status & (IRQ_CPU_A | IRQ_CPU_B))){ + WAN_IRQ_RETVAL(IRQ_NONE); + } + + /* if the IRQ is for both CPUs on the same adapter, */ + /* then alter the interrupt status so as to handle */ + /* one CPU at a time */ + if(((unsigned char)int_status & (IRQ_CPU_A | IRQ_CPU_B)) + == (IRQ_CPU_A | IRQ_CPU_B)) { + int_status &= (CPU_no == SDLA_CPU_A) ? + ~IRQ_CPU_B : ~IRQ_CPU_A; + } + + card_found_for_IRQ = 0; + /* check to see that the CPU number for this device */ + /* corresponds to the interrupt status read */ + switch (CPU_no) { + case SDLA_CPU_A: + if((unsigned char)int_status & IRQ_CPU_A){ + card_found_for_IRQ = 1; + } + break; + + case SDLA_CPU_B: + if((unsigned char)int_status & IRQ_CPU_B){ + card_found_for_IRQ = 1; + } + break; + } + + /* exit if the interrupt is for another CPU on the */ + /* same IRQ */ + if(!card_found_for_IRQ){ + WAN_IRQ_RETVAL(IRQ_NONE); + } + + if (!card || + (card->wandev.state == WAN_UNCONFIGURED && !card->configured)){ + DEBUG_EVENT("Received IRQ %d for CPU #%c\n", + irq, SDLA_GET_CPU(CPU_no)); + DEBUG_EVENT("IRQ for unconfigured adapter\n"); + if (card->hw_iface.intack){ + card->hw_iface.intack(card->hw, int_status); + } + WAN_IRQ_RETVAL(IRQ_NONE); + } + + if (card->in_isr) { + DEBUG_EVENT("%s: interrupt re-entrancy on IRQ %d\n", + card->devname, card->wandev.irq); + if (card->hw_iface.intack){ + card->hw_iface.intack(card->hw, int_status); + } + WAN_IRQ_RETVAL(IRQ_NONE); + } + + spin_lock(&card->wandev.lock); + if (card->next){ + spin_lock(&card->next->wandev.lock); + } + + if (card->hw_iface.intack){ + card->hw_iface.intack(card->hw, int_status); + } + + if (card->isr){ + card->isr(card); + clear_bit(0,&card->spurious); + } + + if (card->next && card->next->isr){ + card->next->isr(card->next); + clear_bit(0,&card->next->spurious); + } + + if (card->next){ + spin_unlock(&card->next->wandev.lock); + } + spin_unlock(&card->wandev.lock); + + }else{ /* handle interrupt on S508 adapter */ + + if (!card || ((card->wandev.state == WAN_UNCONFIGURED) && !card->configured)) + WAN_IRQ_RETVAL(IRQ_NONE); + + if (card->in_isr) { + DEBUG_EVENT("%s: interrupt re-entrancy on IRQ %d!\n", + card->devname, card->wandev.irq); + WAN_IRQ_RETVAL(IRQ_NONE); + } + + spin_lock(&card->wandev.lock); + if (card->next){ + spin_lock(&card->next->wandev.lock); + } + + if (card->hw_iface.intack){ + card->hw_iface.intack(card->hw, 0x00); + } + if (card->isr) + card->isr(card); + + if (card->next){ + spin_unlock(&card->next->wandev.lock); + } + spin_unlock(&card->wandev.lock); + + } + + WAN_IRQ_RETVAL(IRQ_HANDLED); + +#undef card +} + +/*============================================================================ + * This routine is called by the protocol-specific modules when network + * interface is being open. The only reason we need this, is because we + * have to call MOD_INC_USE_COUNT, but cannot include 'module.h' where it's + * defined more than once into the same kernel module. + */ +void wanpipe_open (sdla_t* card) +{ + ++card->open_cnt; +#if !defined(LINUX_2_6) + MOD_INC_USE_COUNT; +#endif +} + +/*============================================================================ + * This routine is called by the protocol-specific modules when network + * interface is being closed. The only reason we need this, is because we + * have to call MOD_DEC_USE_COUNT, but cannot include 'module.h' where it's + * defined more than once into the same kernel module. + */ +void wanpipe_close (sdla_t* card) +{ + --card->open_cnt; +#if !defined(LINUX_2_6) + MOD_DEC_USE_COUNT; +#endif +} + +sdla_t * wanpipe_find_card_num (int num) +{ + sdla_t *card; + + if (num < 1 || num > ncards) + return NULL; + + for (card=card_list;card;card=card->list){ + --num; + if (!num) + break; + } + return card; +} + + +int wanpipe_queue_tq (struct tq_struct *bh_pointer) +{ +#if defined(LINUX_2_6) + schedule_work(bh_pointer); +#else + queue_task(bh_pointer,&tq_immediate); +#endif + return 0; +} + +int wanpipe_mark_bh (void) +{ + mark_bh(IMMEDIATE_BH); + return 0; +} + + +int change_dev_flags (netdevice_t *dev, unsigned flags) +{ + int err; + +#ifdef LINUX_2_6 + err=dev_change_flags(dev,flags); +#else + struct ifreq if_info; + mm_segment_t fs = get_fs(); + + memset(&if_info, 0, sizeof(if_info)); + strcpy(if_info.ifr_name, dev->name); + if_info.ifr_flags = flags; + + set_fs(get_ds()); /* get user space block */ + err = wp_devinet_ioctl(SIOCSIFFLAGS, &if_info); + set_fs(fs); +#endif + return err; +} + +unsigned long get_ip_address (netdevice_t *dev, int option) +{ + + struct in_ifaddr *ifaddr; + struct in_device *in_dev; + unsigned long ip=0; + + if ((in_dev = in_dev_get(dev)) == NULL){ + return 0; + } + + if ((ifaddr = in_dev->ifa_list)== NULL ){ + goto wp_get_ip_exit; + } + + switch (option){ + + case WAN_LOCAL_IP: + ip = ifaddr->ifa_local; + break; + + case WAN_POINTOPOINT_IP: + ip = ifaddr->ifa_address; + break; + + case WAN_NETMASK_IP: + ip = ifaddr->ifa_mask; + break; + + case WAN_BROADCAST_IP: + ip = ifaddr->ifa_broadcast; + break; + default: + break; + } + +wp_get_ip_exit: + + in_dev_put(in_dev); + + return ip; +} + +void add_gateway(sdla_t *card, netdevice_t *dev) +{ + mm_segment_t oldfs; + struct rtentry route; + int res; + + memset((char*)&route,0,sizeof(struct rtentry)); + + ((struct sockaddr_in *) + &(route.rt_dst))->sin_addr.s_addr = 0; + ((struct sockaddr_in *) + &(route.rt_dst))->sin_family = AF_INET; + + ((struct sockaddr_in *) + &(route.rt_genmask))->sin_addr.s_addr = 0; + ((struct sockaddr_in *) + &(route.rt_genmask)) ->sin_family = AF_INET; + + + route.rt_flags = 0; + route.rt_dev = dev->name; + + oldfs = get_fs(); + set_fs(get_ds()); + res = wp_ip_rt_ioctl(SIOCADDRT,&route); + set_fs(oldfs); + + if (res == 0){ + DEBUG_EVENT("%s: Gateway added for %s\n", + card->devname,dev->name); + } + + return; +} + + +static int debugging (wan_device_t* wandev) +{ + sdla_t* card = (sdla_t*)wandev->private; + + if (wandev->state == WAN_UNCONFIGURED){ + return 0; + } + WAN_DEBUG_START(card); + + return 0; +} + + + +static sdla_t * wanpipe_find_card (char *name) +{ + sdla_t *card; + + for (card=card_list;card;card=card->list) { + if (!strcmp(card->devname,name) && + card->wandev.state != WAN_UNCONFIGURED){ + return card; + } + } + return NULL; +} + +static sdla_t * wanpipe_find_card_skid (void *sk_id) +{ + sdla_t *card; + + for (card=card_list;card;card=card->list) { + if (card->sk == sk_id) + return card; + } + return NULL; +} + + +static int bind_api_to_svc (char *devname, void *sk_id) +{ + sdla_t *card; + int err=-EOPNOTSUPP; + + WAN_ASSERT2((!devname),-EINVAL); + + card = wanpipe_find_card(devname); + if (!card){ + return -ENODEV; + } + + if (card->bind_api_to_svc){ + err=card->bind_api_to_svc(card,sk_id); + } + + return err; +} + +static int bind_listen_to_link (char *devname, void *sk_id, unsigned short protocol) +{ + sdla_t *card; + unsigned long flags; + + WAN_ASSERT2((!devname),-EINVAL); + + card = wanpipe_find_card(devname); + if (!card){ + DEBUG_EVENT("%s: Error: Wanpipe device not active! \n",devname); + return -ENODEV; + } + + if (card->sk == NULL){ + spin_lock_irqsave(&card->wandev.lock,flags); + card->sk=sk_id; + sock_hold(sk_id); + spin_unlock_irqrestore(&card->wandev.lock,flags); + return 0; + }else{ + + DEBUG_EVENT("%s: Error: Wanpipe device already bound for listen. Sk=%p\n", + devname,card->sk); + } + + return -EBUSY; +} + +static int unbind_listen_from_link(void *sk_id,unsigned short protocol) +{ + sdla_t *card = wanpipe_find_card_skid(sk_id); + unsigned long flags; + + if (!card){ + DEBUG_TEST("%s: Error: No card ptr!\n",__FUNCTION__); + return -ENODEV; + } + + if (card->sk == sk_id){ + spin_lock_irqsave(&card->wandev.lock,flags); + sock_put(card->sk); + card->sk=NULL; + spin_unlock_irqrestore(&card->wandev.lock,flags); + DEBUG_TEST("%s: LISTEN UNBOUND OK\n",__FUNCTION__); + return 0; + } + + DEBUG_TEST("%s: Wanpipe listen device already unbounded!\n", + card->devname); + + return -ENODEV; +} + +static int wanpipe_register_fw_to_api(void) +{ + struct wanpipe_fw_register_struct wp_fw_reg; + + memset(&wp_fw_reg,0,sizeof(struct wanpipe_fw_register_struct)); + + wp_fw_reg.bind_api_to_svc = bind_api_to_svc; + wp_fw_reg.bind_listen_to_link = bind_listen_to_link; + wp_fw_reg.unbind_listen_from_link = unbind_listen_from_link; + + return register_wanpipe_fw_protocol(&wp_fw_reg); +} + +static int wanpipe_unregister_fw_from_api(void) +{ + unregister_wanpipe_fw_protocol(); + return 0; +} + +/*==================================================== + * WANPIPE API COMMON CODE + */ + +void wp_debug_func_add(unsigned char *func) +{ + if (DBG_ARRAY_CNT < 100){ + sprintf(DEBUG_ARRAY[DBG_ARRAY_CNT++].name,"%s",func); + }else{ + DEBUG_EVENT("%s: Error: Max limit for DEBUG_ARRAY reached!\n",__FUNCTION__); + } +} + +void wp_debug_func_print(void) +{ + int i; + + DEBUG_EVENT("\n"); + DEBUG_EVENT("-----------------TRACE START------------------------\n"); + DEBUG_EVENT("\n"); + + for (i=0;i \n",DEBUG_ARRAY[i].name); + } + + DEBUG_EVENT("\n"); + DEBUG_EVENT("-----------------TRACE END------------------------\n"); + DEBUG_EVENT("\n"); +} + + +/****** End *********************************************************/ diff -Nur linux.org/drivers/net/wan/sdla_mp_fr.c linux-2.6.17/drivers/net/wan/sdla_mp_fr.c --- linux.org/drivers/net/wan/sdla_mp_fr.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/drivers/net/wan/sdla_mp_fr.c 2006-08-30 10:07:16.000000000 +0000 @@ -0,0 +1,5156 @@ +/***************************************************************************** +* sdla_mp_fr.c Multi-Port Frame Relay driver module. +* +* Authors: Nenad Corbic +* +* Copyright: (c) 1995-2002 Sangoma Technologies Inc. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version +* 2 of the License, or (at your option) any later version. +* ============================================================================ +* Apr 09,2002 Nenad Corbic Initial version +* Based on raw-hdlc fimrware +* Some of the frame realy protocol was +* taken from linux/drivers/net/wan/hdlc.c +* and from Sangoma's own frame relay firmware. +*****************************************************************************/ + +#include +#include +#include /* WAN router definitions */ +#include /* WANPIPE common user API definitions */ +#include +#include +#include /* Socket Driver common area */ +#include +#include +#include + +#ifdef CONFIG_PRODUCT_WANPIPE_ANNEXG +#include +#endif + +/****** Defines & Macros ****************************************************/ + +#ifdef _DEBUG_ +#define STATIC +#else +#define STATIC static +#endif + +#define MAX_TRACE_BUFFER (MAX_LGTH_UDP_MGNT_PKT- \ + sizeof(struct iphdr)- \ + sizeof(struct udphdr) - \ + sizeof(wan_mgmt_t)- \ + sizeof(wan_cmd_t)) + +/* reasons for enabling the timer interrupt on the adapter */ +#define TMR_INT_ENABLED_UDP 0x01 +#define TMR_INT_ENABLED_UPDATE 0x02 +#define TMR_INT_ENABLED_TE 0x03 + +#define CHDLC_DFLT_DATA_LEN 1500 /* default MTU */ +#define CHDLC_HDR_LEN 1 + +#define IFF_POINTTOPOINT 0x10 + +#define CHDLC_API 0x01 + +#define PORT(x) (x == 0 ? "PRIMARY" : "SECONDARY" ) +#define MAX_BH_BUFF 10 + +#define CRC_LENGTH 2 +#define PPP_HEADER_LEN 4 +#define MAX_TRACE_LEN 25 +#define MAX_TRACE_ASCII_LEN MAX_TRACE_LEN*3+5 + +#define MAX_FR_RX_BUF 80 +#define FR_RX_BUF_LIMIT 1001 + +#define FR_PROT_AREA(a) ((fr_prot_t*)a->u.c.prot) + +#define MODE_FR_CCITT 0 +#define MAX_FR_HEADER_SZ 16 + +#ifndef IS_TE1_CARD +#define IS_TE1_CARD(card) IS_TE1(card->wandev.te_cfg) +#endif + +#ifndef IS_56K_CARD +#define IS_56K_CARD(card) IS_56K(card->wandev.te_cfg) +#endif + + +/* Enable TE1_56K Card support */ +#define TE1_56_CARD_SUPPORT 1 + +#undef _DBG_ANNEXG_ + +/* Private critical flags */ +enum { + SEND_TXIRQ_CRIT = PRIV_CRIT, + ARP_CRIT +}; + + +/******Data Structures*****************************************************/ + +/* This structure is placed in the private data area of the device structure. + * The card structure used to occupy the private area but now the following + * structure will incorporate the card structure along with CHDLC specific data + */ + +typedef struct fr_private_area +{ + wanpipe_common_t common; + sdla_t *card; + + char if_name[WAN_IFNAME_SZ+1]; + unsigned char route_status; + unsigned char route_removed; + unsigned long tick_counter; /* For 5s timeout counter */ + + u32 IP_address; /* IP addressing */ + u32 IP_netmask; + unsigned char mc; /* Mulitcast support on/off */ + unsigned short udp_pkt_lgth; /* udp packet processing */ + char udp_pkt_src; + + unsigned char trace_state; + unsigned char trace_buf [MAX_TRACE_ASCII_LEN]; + + /* Entry in proc fs per each interface */ + struct proc_dir_entry* dent; + + unsigned long router_last_change; + unsigned int dlci_type; + unsigned long rx_DE_set; + unsigned long tx_DE_set; + unsigned long rx_FECN; + unsigned long rx_BECN; + unsigned err_type; + char err_data[SNMP_FR_ERRDATA_LEN]; + unsigned long err_time; + unsigned long err_faults; + unsigned trap_state; + unsigned long trap_max_rate; + unsigned cir; /* committed information rate */ + unsigned bc; /* committed burst size */ + unsigned be; /* excess burst size */ + + unsigned char ignore_modem; + + unsigned short dlci; + unsigned char dlci_state; + unsigned char inarp; + unsigned char route_flag; + unsigned short newstate; + + struct net_device_stats stats; + unsigned char hdr_len; + unsigned char header[MAX_FR_HEADER_SZ]; + + unsigned char udp_pkt_data[sizeof(wan_udp_pkt_t)+10]; + atomic_t udp_pkt_len; + +#ifdef CONFIG_PRODUCT_WANPIPE_ANNEXG + netdevice_t *annexg_dev; + unsigned char label[WAN_IF_LABEL_SZ+1]; +#endif + + if_send_stat_t drvstats_if_send; + rx_intr_stat_t drvstats_rx_intr; + pipe_mgmt_stat_t drvstats_gen; + + unsigned long tracing_enabled; + struct sk_buff_head trace_queue; + unsigned long trace_timeout; + + unsigned int max_trace_queue; + +} fr_channel_t, fr_private_area_t; + +#if 0 +int fr_to_hdlc_cmd_map[] +{ + +} +#endif + + +/* Route Flag options */ +#define NO_ROUTE 0x00 +#define ADD_ROUTE 0x01 +#define ROUTE_ADDED 0x02 +#define REMOVE_ROUTE 0x03 +#define ARP_REQ 0x04 + +/* inarp options */ +#define INARP_NONE 0x00 +#define INARP_REQUEST 0x01 +#define INARP_CONFIGURED 0x02 + +#undef TX_PKT_DEBUG +#undef RX_PKT_DEBUG + + +/* variable for keeping track of enabling/disabling FT1 monitor status */ +static int rCount = 0; + +/* variable for tracking how many interfaces to open for WANPIPE on the + two ports */ + +extern void disable_irq(unsigned int); +extern void enable_irq(unsigned int); +extern unsigned short wan_calc_checksum (char *, int); +//extern void debug_print_udp_pkt(unsigned char *data,int len,char trc_enabled, char direction); + + +/****** Function Prototypes *************************************************/ +/* WAN link driver entry points. These are called by the WAN router module. */ +static int update (wan_device_t* wandev); +static int new_if (wan_device_t* wandev, netdevice_t* dev, + wanif_conf_t* conf); +static int del_if (wan_device_t* wandev, netdevice_t* dev); + +static int fr_snmp_data(sdla_t* card, netdevice_t *dev, void* data); + +static void disable_comm (sdla_t *card); +static unsigned int dec_to_uint (unsigned char* str, int len); +static netdevice_t* find_channel (sdla_t* card, unsigned dlci); +static void fr_timer(unsigned long arg); +static void fr_lmi_send(sdla_t *card, int fullrep); +static int fr_hard_header(sdla_t *card, netdevice_t *dev, u16 type); + + + +/* Network device interface */ +static int if_init (netdevice_t* dev); +static int if_open (netdevice_t* dev); +static int if_close (netdevice_t* dev); +static int if_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); +static int if_send (struct sk_buff* skb, netdevice_t* dev); +static struct net_device_stats* if_stats (netdevice_t* dev); + +static void if_tx_timeout (netdevice_t *dev); + +/* CHDLC Firmware interface functions */ +static int hdlc_configure (sdla_t* card, void* data); +static int hdlc_comm_enable (sdla_t* card); +static int hdlc_comm_disable (sdla_t* card); +static int hdlc_read_version (sdla_t* card, char* str); +static int hdlc_set_intr_mode (sdla_t* card, unsigned mode); +static int hdlc_send (sdla_t* card, void* data, unsigned len); +static int hdlc_send_hdr_data (sdla_t* card, netdevice_t *dev, void* data, unsigned len); + +static int hdlc_read_comm_err_stats (sdla_t* card); +static int hdlc_read_op_stats (sdla_t* card); +static int config_hdlc (sdla_t *card); +#ifdef TE1_56_CARD_SUPPORT +static int set_adapter_config (sdla_t* card); +#endif + +/* Miscellaneous CHDLC Functions */ +static int set_hdlc_config (sdla_t* card); +static void init_hdlc_tx_rx_buff( sdla_t* card); +static int hdlc_error (sdla_t *card, int err, wan_mbox_t *mb); +static int process_hdlc_exception(sdla_t *card); +static int process_global_exception(sdla_t *card); +static int update_comms_stats(sdla_t* card); +static void chan_set_state (netdevice_t *dev, int); + +/* Interrupt handlers */ +static void wp_hdlc_fr_isr (sdla_t* card); +static void rx_intr (sdla_t* card); +static void tx_intr (sdla_t *card); +static void timer_intr(sdla_t *); + +static void fr_bh (unsigned long card_data); + +/* Miscellaneous functions */ +static int reply_udp( unsigned char *data, unsigned int mbox_len ); +static int intr_test( sdla_t* card); +//static int udp_pkt_type( struct sk_buff *skb, sdla_t* card, int direction); +//static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, +// struct sk_buff *skb, netdevice_t* dev, +// fr_private_area_t* chan); +static int process_udp_mgmt_pkt(sdla_t* card, void* local_dev); + +static void s508_s514_lock (sdla_t *card, unsigned long *smp_flags); +static void s508_s514_unlock (sdla_t *card, unsigned long *smp_flags); + +static int fr_get_config_info(void* priv, struct seq_file* m, int*); +static int fr_get_status_info(void* priv, struct seq_file* m, int*); + +static int fr_set_dev_config(struct file*, const char*, unsigned long, void *); +static int fr_set_if_info(struct file*, const char*, unsigned long, void *); + +static int capture_trace_packet (sdla_t *card,fr_private_area_t*chan,struct sk_buff *skb,char dir); + +/* TE1 */ +#ifdef TE1_56_CARD_SUPPORT +static WRITE_FRONT_END_REG_T write_front_end_reg; +static READ_FRONT_END_REG_T read_front_end_reg; +static void hdlc_enable_timer (void* card_id); +static void fr_handle_front_end_state (void* card_id); +#endif + + +#ifdef CONFIG_PRODUCT_WANPIPE_ANNEXG +static int bind_annexg(netdevice_t *dev, netdevice_t *annexg_dev); +static netdevice_t * un_bind_annexg(wan_device_t *wandev, netdevice_t* annexg_dev_name); +static int get_map(wan_device_t *wandev, netdevice_t *dev, struct seq_file* m, int *); +static void get_active_inactive(wan_device_t *wandev, netdevice_t *dev, + void *wp_stats); +#endif + +/****** Public Functions ****************************************************/ + +/*============================================================================ + * Cisco HDLC protocol initialization routine. + * + * This routine is called by the main WANPIPE module during setup. At this + * point adapter is completely initialized and firmware is running. + * o read firmware version (to make sure it's alive) + * o configure adapter + * o initialize protocol-specific fields of the adapter data space. + * + * Return: 0 o.k. + * < 0 failure. + */ +int wp_hdlc_fr_init (sdla_t* card, wandev_conf_t* conf) +{ + unsigned char port_num; + int err; + unsigned long max_permitted_baud = 0; + fr_prot_t *fr_prot; + + int i; + struct timeval tv; + + union{ + char str[80]; + }u; + volatile wan_mbox_t* mb; + wan_mbox_t* mb1; + unsigned long timeout, smp_lock; + + /* Verify configuration ID */ + if (conf->config_id != WANCONFIG_MFR) { + printk(KERN_INFO "%s: invalid configuration ID %u MFR=%u!\n", + card->devname, conf->config_id, WANCONFIG_MFR); + return -EINVAL; + } + + /* Find out which Port to use. HDLC protocol can use both primary + * and secondayr pory */ + if ((conf->comm_port == WANOPT_PRI) || (conf->comm_port == WANOPT_SEC)){ + if (card->next){ + + if (conf->comm_port != card->next->u.c.comm_port){ + card->u.c.comm_port = conf->comm_port; + }else{ + printk(KERN_INFO "%s: ERROR - %s port used!\n", + card->wandev.name, PORT(conf->comm_port)); + return -EINVAL; + } + }else{ + card->u.c.comm_port = conf->comm_port; + } + }else{ + printk(KERN_INFO "%s: ERROR - Invalid Port Selected!\n", + card->wandev.name); + return -EINVAL; + } + + /* Allocate and initialize Frame relay protocol area */ + if (!card->u.c.prot){ + card->u.c.prot=kmalloc(sizeof(fr_prot_t), GFP_KERNEL); + if (!card->u.c.prot){ + return -ENOMEM; + } + memset(card->u.c.prot,0,sizeof(fr_prot_t)); + } + + fr_prot = FR_PROT_AREA(card); + + fr_prot->station = conf->u.fr.station; + memcpy(&fr_prot->cfg, &conf->u.fr, sizeof(wan_fr_conf_t)); + + + /* Setup a shared memory pointers to protocol mailbox + * (set a pointer to the actual mailbox in the allocated + * virtual memory area) */ + /* ALEX Apr 8 2004 Sangoma ISA card */ + if (card->u.c.comm_port == WANOPT_PRI){ + card->mbox_off = PRI_BASE_ADDR_MB_STRUCT; + }else{ + card->mbox_off = SEC_BASE_ADDR_MB_STRUCT; + } + + mb = &card->wan_mbox; + mb1 = &card->wan_mbox; + + /* Check that firmware is up and running by checking for I in + * mail box */ + if (!card->configured){ + + unsigned char return_code = 0x00; + /* The board will place an 'I' in the return code to indicate that it is + ready to accept commands. We expect this to be completed in less + than 1 second. */ + + timeout = jiffies; + do { + return_code = 0x00; + card->hw_iface.peek(card->hw, + card->mbox_off+offsetof(wan_mbox_t, wan_return_code), + &return_code, + sizeof(unsigned char)); + if ((jiffies - timeout) > 1*HZ) break; + }while(return_code != 'I'); + if (return_code != 'I') { + printk(KERN_INFO + "%s: Initialization not completed by adapter\n", + card->devname); + printk(KERN_INFO "Please contact Sangoma representative.\n"); + return -EIO; + } + } + + card->wandev.ignore_front_end_status=WANOPT_NO; + + //err=check_conf_hw_mismatch(card,conf->te_cfg.media); + err = (card->hw_iface.check_mismatch) ? + card->hw_iface.check_mismatch(card->hw,conf->fe_cfg.media) : -EINVAL; + if (err){ + return err; + } + + /* TE1 Make special hardware initialization for T1/E1 board */ + if (IS_TE1_MEDIA(&conf->fe_cfg)) { + +#ifdef TE1_56_CARD_SUPPORT + memcpy(&card->fe.fe_cfg, &conf->fe_cfg, sizeof(sdla_fe_cfg_t)); + sdla_te_iface_init(&card->wandev.fe_iface); + card->fe.name = card->devname; + card->fe.card = card; + card->fe.write_fe_reg = write_front_end_reg; + card->fe.read_fe_reg = read_front_end_reg; + + card->wandev.fe_enable_timer = hdlc_enable_timer; + card->wandev.te_link_state = fr_handle_front_end_state; + conf->interface = + (IS_T1_CARD(card)) ? WANOPT_V35 : WANOPT_RS232; + + if (card->u.c.comm_port == WANOPT_PRI){ + conf->clocking = WANOPT_EXTERNAL; + } +#else + return -EINVAL; +#endif + + }else if (IS_56K_MEDIA(&conf->fe_cfg)) { + +#ifdef TE1_56_CARD_SUPPORT + memcpy(&card->fe.fe_cfg, &conf->fe_cfg, sizeof(sdla_fe_cfg_t)); + sdla_56k_iface_init(&card->wandev.fe_iface); + card->fe.name = card->devname; + card->fe.card = card; + card->fe.write_fe_reg = write_front_end_reg; + card->fe.read_fe_reg = read_front_end_reg; + + if (card->u.c.comm_port == WANOPT_PRI){ + conf->clocking = WANOPT_EXTERNAL; + } +#else + return -EINVAL; +#endif + }else{ + card->fe.fe_status = FE_CONNECTED; + } + + + if (card->wandev.ignore_front_end_status == WANOPT_NO){ + printk(KERN_INFO + "%s: Enabling front end state monitor\n", + card->devname); + }else{ + printk(KERN_INFO + "%s: Disabling front end state monitor\n", + card->devname); + } + + /* Read firmware version. Note that when adapter initializes, it + * clears the mailbox, so it may appear that the first command was + * executed successfully when in fact it was merely erased. To work + * around this, we execute the first command twice. + */ + + if (hdlc_read_version(card, u.str)) + return -EIO; + +#ifdef CONFIG_PRODUCT_WANPIPE_ANNEXG + printk(KERN_INFO "%s: Running Frame Relay AnnexG over Raw-HDLC firmware v%s\n", + card->devname,u.str); +#else + printk(KERN_INFO "%s: Running Frame Relay over Raw-HDLC firmware v%s\n", + card->devname,u.str); +#endif + + +#ifdef TE1_56_CARD_SUPPORT + if (set_adapter_config(card)) { + return -EIO; + } +#endif + + /* Initialize standard function pointer that are used + * to control, configure and interigate currently + * running protocol */ + card->isr = &wp_hdlc_fr_isr; + card->poll = NULL; + card->exec = NULL; + card->wandev.update = &update; + card->wandev.new_if = &new_if; + card->wandev.del_if = &del_if; + card->wandev.udp_port = conf->udp_port; + card->disable_comm = &disable_comm; + + card->wandev.new_if_cnt = 0; + +#ifdef CONFIG_PRODUCT_WANPIPE_ANNEXG + card->wandev.bind_annexg = &bind_annexg; + card->wandev.un_bind_annexg = &un_bind_annexg; + card->wandev.get_map = &get_map; + card->wandev.get_active_inactive= &get_active_inactive; +#endif + + /* Initialize Proc fs functions */ + card->wandev.get_config_info = &fr_get_config_info; + card->wandev.get_status_info = &fr_get_status_info; + card->wandev.set_dev_config = &fr_set_dev_config; + card->wandev.set_if_info = &fr_set_if_info; + + /* SNMP data */ + card->get_snmp_data = &fr_snmp_data; + + /* reset the number of times the 'update()' proc has been called */ + card->u.c.update_call_count = 0; + + card->wandev.ttl = conf->ttl; + card->wandev.interface = conf->interface; + + + /* The secondary port on S508 card can only have RS232 interface */ + if ((card->u.c.comm_port == WANOPT_SEC && conf->interface == WANOPT_V35)&& + card->type != SDLA_S514){ + printk(KERN_INFO "%s: ERROR - V35 Interface not supported on S508 %s port \n", + card->devname, PORT(card->u.c.comm_port)); + return -EIO; + } + + + card->wandev.clocking = conf->clocking; + + port_num = card->u.c.comm_port; + + + /* Setup Port Baud Rate Bps */ + if(card->wandev.clocking) { + if((port_num == WANOPT_PRI) || card->u.c.receive_only) { + /* For Primary Port 0 */ + max_permitted_baud = + (card->type == SDLA_S514) ? + PRI_MAX_BAUD_RATE_S514 : + PRI_MAX_BAUD_RATE_S508; + } + else if(port_num == WANOPT_SEC) { + /* For Secondary Port 1 */ + max_permitted_baud = + (card->type == SDLA_S514) ? + SEC_MAX_BAUD_RATE_S514 : + SEC_MAX_BAUD_RATE_S508; + } + + if(conf->bps > max_permitted_baud) { + conf->bps = max_permitted_baud; + printk(KERN_INFO "%s: Baud too high!\n", + card->wandev.name); + printk(KERN_INFO "%s: Baud rate set to %lu bps\n", + card->wandev.name, max_permitted_baud); + } + + card->wandev.bps = conf->bps; + }else{ + card->wandev.bps = 0; + } + + /* Setup the Port MTU */ + if((port_num == WANOPT_PRI) || card->u.c.receive_only) { + /* For Primary Port 0 */ + card->wandev.mtu = + (conf->mtu >= MIN_LGTH_CHDLC_DATA_CFG) ? + wp_min(conf->mtu, PRI_MAX_NO_DATA_BYTES_IN_FRAME) : + CHDLC_DFLT_DATA_LEN; + + } else if(port_num == WANOPT_SEC) { + /* For Secondary Port 1 */ + card->wandev.mtu = + (conf->mtu >= MIN_LGTH_CHDLC_DATA_CFG) ? + wp_min(conf->mtu, SEC_MAX_NO_DATA_BYTES_IN_FRAME) : + CHDLC_DFLT_DATA_LEN; + } + + + /* Set up the interrupt status area */ + /* Read the CHDLC Configuration and obtain: + * Ptr to shared memory infor struct + * Use this pointer to calculate the value of card->u.c.flags ! + */ + + mb1->wan_data_len = 0; + mb1->wan_command = READ_CHDLC_CONFIGURATION; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb1); + if(err != COMMAND_OK) { + clear_bit(1, (void*)&card->wandev.critical); + + if(card->type != SDLA_S514) + enable_irq(card->wandev.irq/*ALEX_TODAY card->hw.irq*/); + + hdlc_error(card, err, mb1); + return -EIO; + } + + /* ALEX Apr 8 2004 Sangoma ISA card */ + card->flags_off = + ((CHDLC_CONFIGURATION_STRUCT *)mb1->wan_data)-> + ptr_shared_mem_info_struct; + + card->intr_type_off = + card->flags_off + + offsetof(SHARED_MEMORY_INFO_STRUCT, interrupt_info_struct) + + offsetof(INTERRUPT_INFORMATION_STRUCT, interrupt_type); + card->intr_perm_off = + card->flags_off + + offsetof(SHARED_MEMORY_INFO_STRUCT, interrupt_info_struct) + + offsetof(INTERRUPT_INFORMATION_STRUCT, interrupt_permission); + card->fe_status_off = + card->flags_off + + offsetof(SHARED_MEMORY_INFO_STRUCT, FT1_info_struct) + + offsetof(FT1_INFORMATION_STRUCT, parallel_port_A_input); + + skb_queue_head_init(&fr_prot->rx_free); + skb_queue_head_init(&fr_prot->rx_used); + skb_queue_head_init(&fr_prot->lmi_queue); + skb_queue_head_init(&fr_prot->trace_queue); + + fr_prot->max_rx_queue = MAX_FR_RX_BUF; + + if (conf->max_rx_queue && conf->max_rx_queuemax_rx_queue = conf->max_rx_queue; + } + printk(KERN_INFO "%s: Setting Frame Relay global rx queue len to %i\n", + card->devname,fr_prot->max_rx_queue); + + for (i=0;imax_rx_queue;i++){ + struct sk_buff *skb; + skb=dev_alloc_skb(card->wandev.mtu+10); + if (!skb){ + printk(KERN_INFO "%s: Failed to allocate rx queues! No Memory!\n",card->devname); + skb_queue_purge(&fr_prot->rx_free); + return -ENOMEM; + } + skb_queue_tail(&fr_prot->rx_free,skb); + } + + /* This is for the ports link state */ + card->wandev.state = WAN_DUALPORT; + card->u.c.state = WAN_DISCONNECTED; + + tasklet_init(&fr_prot->wanpipe_task,fr_bh,(u32)card); + + fr_prot->max_trace_queue = MAX_TRACE_QUEUE; + if (conf->max_trace_queue && conf->max_trace_queuemax_trace_queue=conf->max_trace_queue; + } + + printk(KERN_INFO "%s: Setting Max LMI trace queue to %i packets\n", + card->devname,fr_prot->max_trace_queue); + + if (!card->wandev.piggyback){ + err = intr_test(card); + + if(err || (card->timer_int_enabled < MAX_INTR_TEST_COUNTER)) { + printk(KERN_INFO "%s: Interrupt test failed (%i)\n", + card->devname, card->timer_int_enabled); + printk(KERN_INFO "%s: Please choose another interrupt\n", + card->devname); + return -EIO; + } + + printk(KERN_INFO "%s: Interrupt test passed (%i)\n", + card->devname, card->timer_int_enabled); + } + + wan_spin_lock_irq(&card->wandev.lock,&smp_lock); + if (config_hdlc(card) < 0){ + wan_spin_unlock_irq(&card->wandev.lock,&smp_lock); + return -EINVAL; + } + wan_spin_unlock_irq(&card->wandev.lock,&smp_lock); + + spin_lock_init(&card->u.c.if_send_lock); + + printk(KERN_INFO "%s: Frame Station=%s, Signalling=%s\n", + card->devname, + fr_prot->station == WANOPT_NODE ? "NODE" : "CPE", + fr_prot->cfg.signalling == WANOPT_FR_ANSI ? "ANSI":"LMI"); + + do_gettimeofday(&tv); + card->u.c.router_start_time = tv.tv_sec; + + fr_prot->state = LINK_STATE_CHANGED; + fr_prot->txseq = fr_prot->rxseq = 0; + fr_prot->last_errors = 0xFFFFFFFF; + fr_prot->n391cnt = 0; + + init_timer(&fr_prot->timer); + fr_prot->timer.function = fr_timer; + fr_prot->timer.data = (unsigned long)card; + fr_prot->timer.expires = (jiffies+HZ); + add_timer(&fr_prot->timer); + + if (fr_prot->station == WANOPT_CPE){ + printk(KERN_INFO "%s: Waiting for DLCI report from frame relay switch...\n\n", + card->devname); + } + + fr_prot->state |= LINK_STATE_RELIABLE; + wanpipe_set_state(card,WAN_CONNECTED); + return 0; +} + +/******* WAN Device Driver Entry Points *************************************/ + +/*============================================================================ + * Update device status & statistics + * This procedure is called when updating the PROC file system and returns + * various communications statistics. These statistics are accumulated from 3 + * different locations: + * 1) The 'if_stats' recorded for the device. + * 2) Communication error statistics on the adapter. + * 3) CHDLC operational statistics on the adapter. + * The board level statistics are read during a timer interrupt. Note that we + * read the error and operational statistics during consecitive timer ticks so + * as to minimize the time that we are inside the interrupt handler. + * + */ +static int update (wan_device_t* wandev) +{ + sdla_t* card = wandev->private; + unsigned long smp_flags; +#if 0 + SHARED_MEMORY_INFO_STRUCT *flags; + unsigned long timeout; +#endif + + + /* sanity checks */ + if((wandev == NULL) || (wandev->private == NULL)) + return -EFAULT; + + if(wandev->state == WAN_UNCONFIGURED) + return -ENODEV; + + /* more sanity checks */ +#if 0 + if(!card->u.c.flags) + return -ENODEV; + flags = card->u.c.flags; +#endif + + if(test_and_set_bit(0,&card->update_comms_stats)){ + return -EAGAIN; + } + + + /* we will need 2 timer interrupts to complete the */ + /* reading of the statistics */ +#if 0 +#ifdef TE1_56_CARD_SUPPORT + card->update_comms_stats = + (IS_TE1_CARD(card) || IS_56K_CARD(card)) ? 3 : 2; +#else + card->update_comms_stats = 2; +#endif + + flags->interrupt_info_struct.interrupt_permission |= APP_INT_ON_TIMER; + card->u.c.timer_int_enabled = TMR_INT_ENABLED_UPDATE; + + /* wait a maximum of 1 second for the statistics to be updated */ + timeout = jiffies; + for(;;) { + if(card->update_comms_stats == 0) + break; + if ((jiffies - timeout) > (1 * HZ)){ + card->update_comms_stats = 0; + card->u.c.timer_int_enabled &= + ~TMR_INT_ENABLED_UPDATE; + return -EAGAIN; + } + schedule(); + } +#else + spin_lock_irqsave(&card->wandev.lock, smp_flags); + update_comms_stats(card); + card->update_comms_stats=0; + spin_unlock_irqrestore(&card->wandev.lock, smp_flags); + +#endif + return 0; +} + + +/*============================================================================ + * Create new logical channel. + * This routine is called by the router when ROUTER_IFNEW IOCTL is being + * handled. + * o parse media- and hardware-specific configuration + * o make sure that a new channel can be created + * o allocate resources, if necessary + * o prepare network device structure for registaration. + * + * Return: 0 o.k. + * < 0 failure (channel will not be created) + */ +static int new_if (wan_device_t* wandev, netdevice_t* dev, wanif_conf_t* conf) +{ + sdla_t* card = wandev->private; + fr_private_area_t* chan; + int err = 0; + unsigned short dlci=0; + fr_prot_t *fr_prot; + unsigned long smp_lock; + + if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) { + printk(KERN_INFO "%s: Error invalid interface name!\n", + card->devname); + return -EINVAL; + } + + /* allocate and initialize private data */ + chan = kmalloc(sizeof(fr_private_area_t), GFP_KERNEL); + + if(chan == NULL) + return -ENOMEM; + + memset(chan, 0, sizeof(fr_private_area_t)); + + strncpy(chan->if_name,conf->name,WAN_IFNAME_SZ); + + chan->card = card; + fr_prot = FR_PROT_AREA(card); + + /* verify media address */ + if (is_digit(conf->addr[0])) { + + dlci = dec_to_uint(conf->addr, 0); + + if (dlci && (dlci <= HIGHEST_VALID_DLCI)) { + + chan->dlci = dlci; + chan->common.lcn=dlci; + + } else { + + printk(KERN_INFO + "%s: Invalid DLCI %u on interface %s Max=%i!\n", + wandev->name, dlci, chan->if_name,HIGHEST_VALID_DLCI); + err = -EINVAL; + } + + } else { + printk(KERN_INFO + "%s: Invalid media address on interface %s, i.e. no DLCI specified!\n", + wandev->name, chan->if_name); + err = -EINVAL; + } + + + if (err != 0){ + kfree(chan); + return err; + } + + printk(KERN_INFO "\n"); + printk(KERN_INFO "%s: Configuring interface %s with DLCI=%i\n", + card->devname,conf->name,chan->dlci); + + /* Disallow duplicate dlci configurations. */ + if (fr_prot->dlci_to_dev_map[chan->dlci] != NULL){ + kfree(chan); + printk(KERN_INFO "%s: %s: DLCI %i already configured!\n", + card->devname,chan->if_name,chan->dlci); + return -EEXIST; + } + + chan->route_status = NO_ROUTE; + chan->route_removed = 0; + + /* Setup wanpipe as a router (WANPIPE) or as an API */ + if( strcmp(conf->usedby, "WANPIPE") == 0) { + printk(KERN_INFO "%s: %s: Interface running in WANPIPE mode!\n", + wandev->name,chan->if_name); + card->u.c.usedby = WANPIPE; + +#ifdef CONFIG_PRODUCT_WANPIPE_ANNEXG + }else if (strcmp(conf->usedby, "ANNEXG") == 0){ + + chan->common.usedby = ANNEXG; + printk(KERN_INFO "%s: %s: Interface Running in ANNEXG mode.\n", + card->devname,chan->if_name); + + +#endif + }else{ + printk(KERN_INFO + "%s: %s: API mode is not supported by Wanpipe Frame Realy!\n", + wandev->name,chan->if_name); + kfree(chan); + return -EINVAL; + } + + /* Get Multicast Information */ + chan->mc = conf->mc; + +#ifdef CONFIG_PRODUCT_WANPIPE_ANNEXG + if (strlen(conf->label)){ + strncpy(chan->label,conf->label,WAN_IF_LABEL_SZ); + } +#endif + + /* + * Create interface file in proc fs. + */ + err = wanrouter_proc_add_interface(wandev, + &chan->dent, + conf->name, + dev); + if (err){ + printk(KERN_INFO + "%s: Failed to create /proc/net/router/fr/%s entry!\n", + card->devname, conf->name); + kfree(chan); + dev->priv=NULL; + return err; + } + + dev->init = NULL; + dev->priv = chan; + + chan->dlci_state=0; + chan->newstate=0; + + chan->max_trace_queue = MAX_TRACE_QUEUE; + if (conf->max_trace_queue){ + chan->max_trace_queue = conf->max_trace_queue; + } + printk(KERN_INFO "%s: %s: Setting DLCI=%i trace queue to %i packets\n", + card->devname,chan->if_name,chan->dlci,chan->max_trace_queue); + + skb_queue_head_init(&chan->trace_queue); + + card->wandev.new_if_cnt++; + chan->common.state = WAN_DISCONNECTED; + + if_init(dev); + + wan_spin_lock_irq(&card->wandev.lock,&smp_lock); + fr_prot->dlci_to_dev_map[chan->dlci] = dev; + wan_spin_unlock_irq(&card->wandev.lock,&smp_lock); + + printk(KERN_INFO "\n"); + return 0; +} + + +/*============================================================================ + * Delete logical channel. + */ +static int del_if (wan_device_t* wandev, netdevice_t* dev) +{ + fr_private_area_t *chan = dev->priv; + sdla_t *card = wandev->private; + fr_prot_t *fr_prot = FR_PROT_AREA(card); + unsigned long smp_flags; + + if (!chan) + return 0; + + wan_spin_lock_irq(&card->wandev.lock,&smp_flags); + if (fr_prot->tx_dev==dev){ + fr_prot->tx_dev=NULL; + } + if (chan->dlci && fr_prot->dlci_to_dev_map[chan->dlci]){ + fr_prot->dlci_to_dev_map[chan->dlci] = NULL; + } + wan_spin_unlock_irq(&card->wandev.lock,&smp_flags); + +#ifdef CONFIG_PRODUCT_WANPIPE_ANNEXG + if (chan->common.usedby == ANNEXG && chan->annexg_dev){ + struct net_device *tmp_dev; + int err; + + printk(KERN_INFO "%s: Unregistering Lapb Protocol\n",wandev->name); + + if (!IS_FUNC_CALL(lapb_protocol,lapb_unregister)){ + wan_spin_lock_irq(&wandev->lock, &smp_flags); + chan->annexg_dev = NULL; + wan_spin_unlock_irq(&wandev->lock, &smp_flags); + return 0; + } + + wan_spin_lock_irq(&wandev->lock, &smp_flags); + tmp_dev=chan->annexg_dev; + chan->annexg_dev=NULL; + wan_spin_unlock_irq(&wandev->lock, &smp_flags); + + if ((err=lapb_protocol.lapb_unregister(tmp_dev))){ + + wan_spin_lock_irq(&wandev->lock, &smp_flags); + chan->annexg_dev=tmp_dev; + wan_spin_unlock_irq(&wandev->lock, &smp_flags); + return err; + } + } +#endif + + /* Delete interface name from proc fs. */ + wanrouter_proc_delete_interface(wandev, chan->if_name); + + skb_queue_purge(&chan->trace_queue); + chan_set_state(dev, WAN_DISCONNECTED); + card->wandev.new_if_cnt--; + + return 0; +} + +static void disable_comm (sdla_t *card) +{ + fr_prot_t* fr_prot = FR_PROT_AREA(card); + unsigned long smp_lock; + + tasklet_kill(&fr_prot->wanpipe_task); + + wan_spin_lock_irq(&card->wandev.lock,&smp_lock); + hdlc_set_intr_mode(card, 0); + if (card->u.c.comm_enabled){ + hdlc_comm_disable(card); + } + wan_spin_unlock_irq(&card->wandev.lock,&smp_lock); + + if (fr_prot){ + del_timer(&fr_prot->timer); + wan_spin_lock_irq(&card->wandev.lock,&smp_lock); + skb_queue_purge(&fr_prot->rx_free); + skb_queue_purge(&fr_prot->rx_used); + skb_queue_purge(&fr_prot->lmi_queue); + skb_queue_purge(&fr_prot->trace_queue); + wan_spin_unlock_irq(&card->wandev.lock,&smp_lock); + kfree(fr_prot); + card->u.c.prot=NULL; + } + +#ifdef TE1_56_CARD_SUPPORT + /* TE1 - Unconfiging */ + if (IS_TE1_CARD(card)) { + if (card->wandev.fe_iface.unconfig){ + card->wandev.fe_iface.unconfig(&card->fe); + } + } +#endif +} + +/****** Network Device Interface ********************************************/ + +/*============================================================================ + * Initialize Linux network interface. + * + * This routine is called only once for each interface, during Linux network + * interface registration. Returning anything but zero will fail interface + * registration. + */ +static int if_init (netdevice_t* dev) +{ + fr_private_area_t* chan = dev->priv; + sdla_t* card = chan->card; + fr_prot_t *fr_prot=FR_PROT_AREA(card); + wan_device_t* wandev = &card->wandev; + + /* NOTE: Most of the dev initialization was + * done in sppp_attach(), called by new_if() + * function. All we have to do here is + * to link four major routines below. + */ + + /* Initialize device driver entry points */ + dev->open = &if_open; + dev->stop = &if_close; + dev->hard_start_xmit = &if_send; + dev->get_stats = &if_stats; +#if defined(LINUX_2_4)||defined(LINUX_2_6) + dev->tx_timeout = &if_tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; +#endif + dev->do_ioctl = if_do_ioctl; + + dev->hard_header = NULL; + dev->hard_header_len = 0; + dev->addr_len = 2; + *(u16*)dev->dev_addr = htons(chan->dlci); + dlci_to_q922(dev->broadcast, fr_prot->lmi_dlci); + + dev->flags |= IFF_POINTOPOINT; + dev->flags |= IFF_NOARP; + + /* Initialize hardware parameters */ + dev->irq = wandev->irq; + dev->dma = wandev->dma; + dev->base_addr = wandev->ioport; + card->hw_iface.getcfg(card->hw, SDLA_MEMBASE, &dev->mem_start); //ALEX_TODAY wandev->maddr; + card->hw_iface.getcfg(card->hw, SDLA_MEMEND, &dev->mem_end); //ALEX_TODAY wandev->maddr + wandev->msize - 1; + + dev->type = ARPHRD_DLCI; + dev->mtu = card->wandev.mtu; + + /* Set transmit buffer queue length + * If we over fill this queue the packets will + * be droped by the kernel. + * sppp_attach() sets this to 10, but + * 100 will give us more room at low speeds. + */ + dev->tx_queue_len = 100; + + /* Initialize socket buffers */ + //dev_init_buffers(dev); + + return 0; +} + + +/*============================================================================ + * Handle transmit timeout event from netif watchdog + */ +static void if_tx_timeout (netdevice_t *dev) +{ + fr_private_area_t* chan = dev->priv; + sdla_t *card = chan->card; + + /* If our device stays busy for at least 5 seconds then we will + * kick start the device by making dev->tbusy = 0. We expect + * that our device never stays busy more than 5 seconds. So this + * is only used as a last resort. + */ + + ++card->wandev.stats.collisions; + + printk (KERN_INFO "%s: Transmit timed out on %s\n", card->devname,dev->name); + netif_wake_queue (dev); +} + + + +/*============================================================================ + * Open network interface. + * o enable communications and interrupts. + * o prevent module from unloading by incrementing use count + * + * Return 0 if O.k. or errno. + */ +static int if_open (netdevice_t* dev) +{ + fr_private_area_t* chan = dev->priv; + sdla_t* card = chan->card; + fr_prot_t *fr_prot = FR_PROT_AREA(card); + + /* Only one open per interface is allowed */ + + if (open_dev_check(dev)) + return -EBUSY; + + netif_start_queue(dev); + wanpipe_open(card); + + if (fr_prot->station == WANOPT_NODE){ + chan->dlci_state = 0; + fr_prot->state |= LINK_STATE_CHANGED; + }else{ + if (chan->dlci_state & PVC_STATE_ACTIVE){ + chan_set_state(dev,WAN_CONNECTED); + }else{ + chan_set_state(dev,WAN_CONNECTING); + chan->dlci_state=0; + } + } + + return 0; +} + +/*============================================================================ + * Close network interface. + * o if this is the last close, then disable communications and interrupts. + * o reset flags. + */ +static int if_close (netdevice_t* dev) +{ + fr_private_area_t* chan = dev->priv; + sdla_t* card = chan->card; + fr_prot_t *fr_prot = FR_PROT_AREA(card); + + stop_net_queue(dev); + +#if defined(LINUX_2_1) + dev->start=0; +#endif + + if (fr_prot->station == WANOPT_NODE){ + chan->dlci_state &= ~(PVC_STATE_ACTIVE|PVC_STATE_NEW); + fr_prot->state |= LINK_STATE_CHANGED; + } + wanpipe_close(card); + + chan_set_state(dev,WAN_DISCONNECTED); + return 0; +} + +/** + * if_do_ioctl - Ioctl handler for fr + * @dev: Device subject to ioctl + * @ifr: Interface request block from the user + * @cmd: Command that is being issued + * + * This function handles the ioctls that may be issued by the user + * to control the settings of a FR. It does both busy + * and security checks. This function is intended to be wrapped by + * callers who wish to add additional ioctl calls of their own. + */ +/* SNMP */ +static int if_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + unsigned long smp_flags; + fr_private_area_t* chan = dev->priv; + sdla_t *card; + wan_udp_pkt_t *wan_udp_pkt; + + if (!chan) + return -ENODEV; + + card = chan->card; + + if(!capable(CAP_NET_ADMIN)) + return -EPERM; + + switch(cmd) + { + case SIOC_WANPIPE_SNMP: + case SIOC_WANPIPE_SNMP_IFSPEED: + return wan_snmp_data(card, dev, cmd, ifr); + + + case SIOC_WANPIPE_PIPEMON: + + if (atomic_read(&chan->udp_pkt_len) != 0){ + return -EBUSY; + } + + atomic_set(&chan->udp_pkt_len,MAX_LGTH_UDP_MGNT_PKT); + + wan_udp_pkt=(wan_udp_pkt_t*)&chan->udp_pkt_data; + if (copy_from_user(&wan_udp_pkt->wan_udp_hdr,ifr->ifr_data,sizeof(wan_udp_hdr_t))){ + atomic_set(&chan->udp_pkt_len,0); + return -EFAULT; + } + + spin_lock_irqsave(&card->wandev.lock, smp_flags); + + /* We have to check here again because we don't know + * what happened during spin_lock */ + if (test_bit(0,&card->in_isr)){ + printk(KERN_INFO "%s:%s pipemon command busy: try again!\n", + card->devname,dev->name); + atomic_set(&chan->udp_pkt_len,0); + spin_unlock_irqrestore(&card->wandev.lock, smp_flags); + return -EBUSY; + } + + + if (process_udp_mgmt_pkt(card,dev) <= 0 ){ + atomic_set(&chan->udp_pkt_len,0); + spin_unlock_irqrestore(&card->wandev.lock, smp_flags); + return -EINVAL; + } + + + spin_unlock_irqrestore(&card->wandev.lock, smp_flags); + + /* This area will still be critical to other + * PIPEMON commands due to udp_pkt_len + * thus we can release the irq */ + + + if (atomic_read(&chan->udp_pkt_len) > sizeof(wan_udp_pkt_t)){ + printk(KERN_INFO "%s: Error: Pipemon buf too bit on the way up! %i\n", + card->devname,atomic_read(&chan->udp_pkt_len)); + atomic_set(&chan->udp_pkt_len,0); + return -EINVAL; + } + + if (copy_to_user(ifr->ifr_data,&wan_udp_pkt->wan_udp_hdr,sizeof(wan_udp_hdr_t))){ + atomic_set(&chan->udp_pkt_len,0); + return -EFAULT; + } + + atomic_set(&chan->udp_pkt_len,0); + return 0; + + default: + return -EOPNOTSUPP; + } + return 0; +} + + +/*============================================================================ + * Send a packet on a network interface. + * o set tbusy flag (marks start of the transmission) to block a timer-based + * transmit from overlapping. + * o check link state. If link is not up, then drop the packet. + * o execute adapter send command. + * o free socket buffer + * + * Return: 0 complete (socket buffer must be freed) + * non-0 packet may be re-transmitted (tbusy must be set) + * + * Notes: + * 1. This routine is called either by the protocol stack or by the "net + * bottom half" (with interrupts enabled). + * 2. Setting tbusy flag will inhibit further transmit requests from the + * protocol stack and can be used for flow control with protocol layer. + */ +static int if_send (struct sk_buff* skb, netdevice_t* dev) +{ + fr_private_area_t *chan = dev->priv; + sdla_t *card = chan->card; + //int udp_type = 0; + unsigned long smp_flags; + int err=0; + +#if defined(LINUX_2_4)||defined(LINUX_2_6) + netif_stop_queue(dev); + dev->trans_start = jiffies; +#endif + + if (skb == NULL){ + /* If we get here, some higher layer thinks we've missed an + * tx-done interrupt. + */ + printk(KERN_INFO "%s: Received NULL skb buffer! interface %s got kicked!\n", + card->devname, dev->name); + + wake_net_dev(dev); + return 0; + } + +#if defined(LINUX_2_1) + if (dev->tbusy){ + + /* If our device stays busy for at least 5 seconds then we will + * kick start the device by making dev->tbusy = 0. We expect + * that our device never stays busy more than 5 seconds. So this + * is only used as a last resort. + */ + if((jiffies - chan->tick_counter) < (5 * HZ)) { + return 1; + } + if_tx_timeout(dev); + } +#endif + + if (test_bit(SEND_TXIRQ_CRIT,&card->wandev.critical)){ + stop_net_queue(dev); + chan->tick_counter = jiffies; + card->hw_iface.set_bit(card->hw, card->intr_perm_off, APP_INT_ON_TX_FRAME); + //printk(KERN_INFO "%s: (Debug): IF send busy: on TXIRQ CRIT \n",dev->name); + return 1; + } + + s508_s514_lock(card, &smp_flags); + + if (test_and_set_bit(SEND_CRIT, (void*)&card->wandev.critical)){ + + printk(KERN_INFO "%s: Critical in if_send: %lx\n", + card->wandev.name,card->wandev.critical); + ++card->wandev.stats.tx_dropped; + ++chan->stats.tx_carrier_errors; + start_net_queue(dev); + goto if_send_crit_exit; + } + + if (card->wandev.state != WAN_CONNECTED){ + ++card->wandev.stats.tx_dropped; + ++chan->stats.tx_carrier_errors; + start_net_queue(dev); + goto if_send_crit_exit; + } + + if (chan->common.state != WAN_CONNECTED){ + ++card->wandev.stats.tx_dropped; + ++chan->stats.tx_carrier_errors; + start_net_queue(dev); + goto if_send_crit_exit; + } + + if (fr_hard_header(card, dev, htons(skb->protocol)) <= 0){ + ++card->wandev.stats.tx_errors; + start_net_queue(dev); + goto if_send_crit_exit; + } + + err=hdlc_send_hdr_data(card, dev, skb->data, skb->len); + + if (err){ + err=-1; + stop_net_queue(dev); + //printk(KERN_INFO "%s: (Debug): IF send failed\n",dev->name); + + }else{ + + if (capture_trace_packet(card,chan,skb,TRC_OUTGOING_FRM) < 0){ + chan->stats.tx_fifo_errors++; + } + + ++card->wandev.stats.tx_packets; + card->wandev.stats.tx_bytes += skb->len; + ++chan->stats.tx_packets; + chan->stats.tx_bytes += skb->len; +#if defined(LINUX_2_4)||defined(LINUX_2_6) + dev->trans_start = jiffies; +#endif + +#ifdef _DBG_ANNEXG_ + check_x25_pr_ps_cnt(card,skb); +#endif + start_net_queue(dev); + + } + +if_send_crit_exit: + if (err==0){ + dev_kfree_skb_any(skb); + }else{ + chan->tick_counter = jiffies; + card->hw_iface.set_bit(card->hw, card->intr_perm_off, APP_INT_ON_TX_FRAME); + } + + clear_bit(SEND_CRIT, (void*)&card->wandev.critical); + s508_s514_unlock(card, &smp_flags); + + return err; +} + +/*============================================================================ + * Reply to UDP Management system. + * Return nothing. + */ +static int reply_udp( unsigned char *data, unsigned int mbox_len ) +{ + unsigned short len, udp_length, temp, ip_length; + unsigned long ip_temp; + int even_bound = 0; + wan_udp_pkt_t *wan_udp_pkt = (wan_udp_pkt_t *)data; + + /* Set length of packet */ + len = //sizeof(fr_encap_hdr_t)+ + sizeof(struct iphdr)+ + sizeof(struct udphdr)+ + sizeof(wan_mgmt_t)+ + sizeof(wan_cmd_t)+ + mbox_len; + + + /* fill in UDP reply */ + wan_udp_pkt->wan_udp_request_reply = UDPMGMT_REPLY; + + /* fill in UDP length */ + udp_length = sizeof(struct udphdr)+ + sizeof(wan_mgmt_t)+ + sizeof(wan_cmd_t)+ + mbox_len; + + + /* put it on an even boundary */ + if ( udp_length & 0x0001 ) { + udp_length += 1; + len += 1; + even_bound = 1; + } + + temp = (udp_length<<8)|(udp_length>>8); + wan_udp_pkt->wan_udp_len = temp; + + /* swap UDP ports */ + temp = wan_udp_pkt->wan_udp_sport; + wan_udp_pkt->wan_udp_sport = + wan_udp_pkt->wan_udp_dport; + wan_udp_pkt->wan_udp_dport = temp; + + + + /* add UDP pseudo header */ + temp = 0x1100; + *((unsigned short *) + (wan_udp_pkt->wan_udp_data+mbox_len+even_bound)) = temp; + temp = (udp_length<<8)|(udp_length>>8); + *((unsigned short *) + (wan_udp_pkt->wan_udp_data+mbox_len+even_bound+2)) = temp; + + /* calculate UDP checksum */ + wan_udp_pkt->wan_udp_sum = 0; + + wan_udp_pkt->wan_udp_sum = + wan_calc_checksum(&data[UDP_OFFSET/*+sizeof(fr_encap_hdr_t)*/], + udp_length+UDP_OFFSET); + + /* fill in IP length */ + ip_length = udp_length + sizeof(struct iphdr); + temp = (ip_length<<8)|(ip_length>>8); + wan_udp_pkt->wan_ip_len = temp; + + /* swap IP addresses */ + ip_temp = wan_udp_pkt->wan_ip_src; + wan_udp_pkt->wan_ip_src = + wan_udp_pkt->wan_ip_dst; + wan_udp_pkt->wan_ip_dst = ip_temp; + + + /* fill in IP checksum */ + wan_udp_pkt->wan_ip_sum = 0; + wan_udp_pkt->wan_ip_sum = + wan_calc_checksum(&data[/*sizeof(fr_encap_hdr_t)*/0], + sizeof(struct iphdr)); + + return len; +} /* reply_udp */ + + +/*============================================================================ + * Get ethernet-style interface statistics. + * Return a pointer to struct enet_statistics. + */ +static struct net_device_stats* if_stats (netdevice_t* dev) +{ + fr_private_area_t* chan; + + if (!dev || !(dev->flags&IFF_UP)) + return NULL; + + /* Shutdown bug fix. In del_if() we kill + * dev->priv pointer. This function, gets + * called after del_if(), thus check + * if pointer has been deleted */ + if ((chan=dev->priv) == NULL) + return NULL; + + return &chan->stats; +} + +/****** Cisco HDLC Firmware Interface Functions *******************************/ + +/*============================================================================ + * Read firmware code version. + * Put code version as ASCII string in str. + */ +static int hdlc_read_version (sdla_t* card, char* str) +{ + wan_mbox_t* mb = &card->wan_mbox; + int len; + char err; + mb->wan_data_len = 0; + mb->wan_command = READ_CHDLC_CODE_VERSION; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + + if(err != COMMAND_OK) { + hdlc_error(card,err,mb); + } + else if (str) { /* is not null */ + len = mb->wan_data_len; + memcpy(str, mb->wan_data, len); + str[len] = '\0'; + } + return (err); +} + +/*----------------------------------------------------------------------------- + * Configure CHDLC firmware. + */ +static int hdlc_configure (sdla_t* card, void* data) +{ + int err; + wan_mbox_t *mbox = &card->wan_mbox; + int data_length = sizeof(CHDLC_CONFIGURATION_STRUCT); + + mbox->wan_data_len = data_length; + memcpy(mbox->wan_data, data, data_length); + mbox->wan_command = SET_CHDLC_CONFIGURATION; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mbox); + + if (err != COMMAND_OK) hdlc_error (card, err, mbox); + + return err; +} + + +/*============================================================================ + * Set interrupt mode -- HDLC Version. + */ + +static int hdlc_set_intr_mode (sdla_t* card, unsigned mode) +{ + wan_mbox_t* mb = &card->wan_mbox; + CHDLC_INT_TRIGGERS_STRUCT* int_data = + (CHDLC_INT_TRIGGERS_STRUCT *)mb->wan_data; + int err; + + int_data->CHDLC_interrupt_triggers = mode; + int_data->IRQ = card->wandev.irq; //ALEX_TODAY card->hw.irq; + int_data->interrupt_timer = 1; + + mb->wan_data_len = sizeof(CHDLC_INT_TRIGGERS_STRUCT); + mb->wan_command = SET_CHDLC_INTERRUPT_TRIGGERS; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != COMMAND_OK) + hdlc_error (card, err, mb); + return err; +} + + +/*============================================================================ + * Enable communications. + */ + +static int hdlc_comm_enable (sdla_t* card) +{ + int err; + wan_mbox_t* mb = &card->wan_mbox; + + mb->wan_data_len = 0; + mb->wan_command = ENABLE_CHDLC_COMMUNICATIONS; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != COMMAND_OK) + hdlc_error(card, err, mb); + else + card->u.c.comm_enabled=1; + + return err; +} + +/*============================================================================ + * Disable communications and Drop the Modem lines (DCD and RTS). + */ +static int hdlc_comm_disable (sdla_t* card) +{ + int err; + wan_mbox_t* mb = &card->wan_mbox; + + mb->wan_data_len = 0; + mb->wan_command = DISABLE_CHDLC_COMMUNICATIONS; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != COMMAND_OK) + hdlc_error(card,err,mb); + + return err; +} + +/*============================================================================ + * Read communication error statistics. + */ +static int hdlc_read_comm_err_stats (sdla_t* card) +{ + int err; + wan_mbox_t* mb = &card->wan_mbox; + + mb->wan_data_len = 0; + mb->wan_command = READ_COMMS_ERROR_STATS; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != COMMAND_OK) + hdlc_error(card,err,mb); + return err; +} + + +/*============================================================================ + * Read CHDLC operational statistics. + */ +static int hdlc_read_op_stats (sdla_t* card) +{ + int err; + wan_mbox_t* mb = &card->wan_mbox; + + mb->wan_data_len = 0; + mb->wan_command = READ_CHDLC_OPERATIONAL_STATS; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != COMMAND_OK) + hdlc_error(card,err,mb); + return err; +} + + +/*============================================================================ + * Update communications error and general packet statistics. + */ +static int update_comms_stats(sdla_t* card) +{ + wan_mbox_t* mb = &card->wan_mbox; + COMMS_ERROR_STATS_STRUCT* err_stats; + CHDLC_OPERATIONAL_STATS_STRUCT *op_stats; + + /* on the first timer interrupt, read the comms error statistics */ +#ifdef TE1_56_CARD_SUPPORT + /* 1. On the first timer interrupt, update T1/E1 alarms + * and PMON counters (only for T1/E1 card) (TE1) + */ + /* TE1 Update T1/E1 alarms */ + if (IS_TE1_CARD(card)) { + card->wandev.fe_iface.read_alarm(&card->fe, 0); + /* TE1 Update T1/E1 perfomance counters */ + card->wandev.fe_iface.read_pmon(&card->fe, 0); + }else if (IS_56K_CARD(card)) { + /* 56K Update CSU/DSU alarms */ + card->wandev.fe_iface.read_alarm(&card->fe, 1); + } +#endif + + if(hdlc_read_comm_err_stats(card)) + return 1; + + err_stats = (COMMS_ERROR_STATS_STRUCT *)mb->wan_data; + card->wandev.stats.rx_over_errors = + err_stats->Rx_overrun_err_count; + card->wandev.stats.rx_crc_errors = + err_stats->CRC_err_count; + card->wandev.stats.rx_frame_errors = + err_stats->Rx_abort_count; + card->wandev.stats.rx_fifo_errors = + err_stats->Rx_dis_pri_bfrs_full_count; + card->wandev.stats.rx_missed_errors = + card->wandev.stats.rx_fifo_errors; + card->wandev.stats.tx_aborted_errors = + err_stats->sec_Tx_abort_count; + + if(hdlc_read_op_stats(card)) + return 1; + op_stats = (CHDLC_OPERATIONAL_STATS_STRUCT *)mb->wan_data; + card->wandev.stats.rx_length_errors = + (op_stats->Rx_Data_discard_short_count + + op_stats->Rx_Data_discard_long_count); + + return 0; +} + +static int hdlc_send_hdr_data (sdla_t* card, netdevice_t *dev, void* data, unsigned len) +{ + CHDLC_DATA_TX_STATUS_EL_STRUCT txbuf; + fr_private_area_t *chan = dev->priv; + + card->hw_iface.peek(card->hw, card->u.c.txbuf_off, &txbuf, sizeof(txbuf)); + if (txbuf.opp_flag) + return 1; + +#if defined(TX_PKT_DEBUG) + if (len <= 5 && !(((char *)data)[1]&0x01)){ + int x; + + if (len == 5 && (((char*)data)[4]&0x01)) + goto tx_skip_error; + + printk(KERN_INFO "ERROR !!! TX: Annexg Tx Frame error %i\n", + len); + + printk(KERN_INFO "Bad Packet : "); + for (x=0;xhdr_len); + + card->hw_iface.poke(card->hw,txbuf.ptr_data_bfr,chan->header,chan->hdr_len); + card->hw_iface.poke(card->hw,(txbuf.ptr_data_bfr+chan->hdr_len),data,len); + + txbuf.opp_flag = 1; /* start transmission */ + card->hw_iface.peek(card->hw, card->u.c.txbuf_off, &txbuf, sizeof(txbuf)); + + /* Update transmit buffer control fields */ + card->u.c.txbuf_off += sizeof(txbuf); + + if (card->u.c.txbuf_off > card->u.c.txbuf_last_off) + card->u.c.txbuf_off = card->u.c.txbuf_base_off; + return 0; +} +/*============================================================================ + * Send packet. + * Return: 0 - o.k. + * 1 - no transmit buffers available + */ +static int hdlc_send (sdla_t* card, void* data, unsigned len) +{ + CHDLC_DATA_TX_STATUS_EL_STRUCT txbuf; + + card->hw_iface.peek(card->hw, card->u.c.txbuf_off, &txbuf, sizeof(txbuf)); + + if (txbuf.opp_flag) + return 1; + + card->hw_iface.poke(card->hw, txbuf.ptr_data_bfr, data, len); + + txbuf.frame_length = len; + txbuf.opp_flag = 1; /* start transmission */ + card->hw_iface.poke(card->hw, card->u.c.txbuf_off, &txbuf, sizeof(txbuf)); + + /* Update transmit buffer control fields */ + card->u.c.txbuf_off += sizeof(txbuf); + + if (card->u.c.txbuf_off > card->u.c.txbuf_last_off) + card->u.c.txbuf_off = card->u.c.txbuf_base_off; + + return 0; +} + +#ifdef TE1_56_CARD_SUPPORT + +static int set_adapter_config (sdla_t* card) +{ + wan_mbox_t* mb = &card->wan_mbox; + ADAPTER_CONFIGURATION_STRUCT* cfg = (ADAPTER_CONFIGURATION_STRUCT*)mb->wan_data; + int err; + + card->hw_iface.getcfg(card->hw, SDLA_ADAPTERTYPE, &cfg->adapter_type); + cfg->adapter_config = 0x00; + cfg->operating_frequency = 00; + mb->wan_data_len = sizeof(ADAPTER_CONFIGURATION_STRUCT); + mb->wan_command = SET_ADAPTER_CONFIGURATION; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + + if(err != COMMAND_OK) { + hdlc_error(card,err,mb); + } + return (err); +} + + + +/*============================================================================ + * Read TE1/56K Front end registers + */ +static unsigned char read_front_end_reg (void* card1, ...) +{ + va_list args; + sdla_t* card = (sdla_t*)card1; + wan_mbox_t* mb = &card->wan_mbox; + u16 reg; + char* data = mb->wan_data; + int err; + + va_start(args, card1); + reg = (u16)va_arg(args, int); + va_end(args); + + ((FRONT_END_REG_STRUCT *)data)->register_number = (unsigned short)reg; + mb->wan_data_len = sizeof(FRONT_END_REG_STRUCT); + mb->wan_command = READ_FRONT_END_REGISTER; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != COMMAND_OK) + hdlc_error(card,err,mb); + + return(((FRONT_END_REG_STRUCT *)data)->register_value); +} + + +/*============================================================================ + * Write to TE1/56K Front end registers + */ +static int write_front_end_reg (void* card1, ...) +{ + va_list args; + sdla_t* card = (sdla_t*)card1; + wan_mbox_t* mb = &card->wan_mbox; + u16 reg; + u8 value; + char* data = mb->wan_data; + int err; + + va_start(args, card1); + reg = (u16)va_arg(args, int); + value = (u8)va_arg(args, int); + va_end(args); + + ((FRONT_END_REG_STRUCT *)data)->register_number = (unsigned short)reg; + ((FRONT_END_REG_STRUCT *)data)->register_value = value; + mb->wan_data_len = sizeof(FRONT_END_REG_STRUCT); + mb->wan_command = WRITE_FRONT_END_REGISTER; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != COMMAND_OK) + hdlc_error(card,err,mb); + return err; +} + +/*============================================================================ + * Enable timer interrupt + */ +static void hdlc_enable_timer (void* card_id) +{ + sdla_t* card = (sdla_t*)card_id; + + card->u.c.timer_int_enabled |= TMR_INT_ENABLED_TE; + card->hw_iface.set_bit(card->hw, card->intr_perm_off, APP_INT_ON_TIMER); + return; +} + +#endif +/****** Firmware Error Handler **********************************************/ + +/*============================================================================ + * Firmware error handler. + * This routine is called whenever firmware command returns non-zero + * return code. + * + * Return zero if previous command has to be cancelled. + */ +static int hdlc_error (sdla_t *card, int err, wan_mbox_t *mb) +{ + unsigned cmd = mb->wan_command; + + switch (err) { + + case CMD_TIMEOUT: + printk(KERN_INFO "%s: command 0x%02X timed out!\n", + card->devname, cmd); + break; + + case S514_BOTH_PORTS_SAME_CLK_MODE: + if(cmd == SET_CHDLC_CONFIGURATION) { + printk(KERN_INFO + "%s: Configure both ports for the same clock source\n", + card->devname); + break; + } + + default: + printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n", + card->devname, cmd, err); + } + + return 0; +} + +/****** Interrupt Handlers **************************************************/ + +/*============================================================================ + * Cisco HDLC interrupt service routine. + */ +STATIC void wp_hdlc_fr_isr (sdla_t* card) +{ + SHARED_MEMORY_INFO_STRUCT flags; + int i; + + + /* Check for which port the interrupt has been generated + * Since Secondary Port is piggybacking on the Primary + * the check must be done here. + */ + + /* Start card isr critical area */ + set_bit(0,&card->in_isr); + + card->hw_iface.peek(card->hw, card->flags_off, &flags, sizeof(flags)); + + /* if critical due to peripheral operations + * ie. update() or getstats() then reset the interrupt and + * wait for the board to retrigger. + */ + if(test_bit(PERI_CRIT, (void*)&card->wandev.critical)) { + printk(KERN_INFO "%s: ISR: Critical due to PERI\n", + card->devname); + card->hw_iface.poke_byte(card->hw, card->intr_type_off, 0x00); + goto isr_done; + } + + /* On a 508 Card, if critical due to if_send + * Major Error !!! + */ + if(card->type != SDLA_S514) { + if(test_bit(0, (void*)&card->wandev.critical)) { + printk(KERN_INFO "%s: ISR: Critical due to SEND %lx\n", + card->devname, card->wandev.critical); + goto isr_done; + } + } + + switch(flags.interrupt_info_struct.interrupt_type) { + case RX_APP_INT_PEND: /* 0x01: receive interrupt */ + rx_intr(card); + break; + + case TX_APP_INT_PEND: /* 0x02: transmit interrupt */ + tx_intr(card); + break; + + case COMMAND_COMPLETE_APP_INT_PEND:/* 0x04: cmd cplt */ + ++ card->timer_int_enabled; + break; + + case CHDLC_EXCEP_COND_APP_INT_PEND: /* 0x20 */ + process_hdlc_exception(card); + break; + + case GLOBAL_EXCEP_COND_APP_INT_PEND: + process_global_exception(card); + +#ifdef TE1_56_CARD_SUPPORT + /* Reset the 56k or T1/E1 front end exception condition */ + if(IS_56K_CARD(card) || IS_TE1_CARD(card)) { + FRONT_END_STATUS_STRUCT FE_status; + card->hw_iface.peek(card->hw, card->fe_status_off, + &FE_status, sizeof(FE_status)); + FE_status.opp_flag = 0x01; + card->hw_iface.poke(card->hw, card->fe_status_off, + &FE_status, sizeof(FE_status)); + } +#endif + break; + + case TIMER_APP_INT_PEND: + timer_intr(card); + break; + + default: + + if (card->next){ + set_bit(0,&card->spurious); + break; + } + + printk(KERN_INFO "%s: spurious interrupt 0x%02X!\n", + card->devname, + flags.interrupt_info_struct.interrupt_type); + printk(KERN_INFO "Code name: "); + for(i = 0; i < 4; i ++) + printk("%c", + flags.global_info_struct.codename[i]); + printk("\n"); + printk(KERN_INFO "Code version: "); + for(i = 0; i < 4; i ++) + printk("%c", + flags.global_info_struct.codeversion[i]); + printk("\n"); + break; + } + +isr_done: + card->in_isr = 0; + card->hw_iface.poke_byte(card->hw, card->intr_type_off, 0x00); +} + +/*============================================================================ + * Receive interrupt handler. + */ +static void rx_intr (sdla_t* card) +{ + SHARED_MEMORY_INFO_STRUCT flags; + CHDLC_DATA_RX_STATUS_EL_STRUCT rxbuf; + struct sk_buff *skb; + unsigned len; + unsigned addr; + void *buf; + int i; + fr_prot_t *fr_prot = FR_PROT_AREA(card); + + if (!fr_prot){ + printk(KERN_INFO "%s: Fr prot area not allocated!\n", + card->devname); + goto rx_exit; + } + + card->hw_iface.peek(card->hw, card->flags_off, &flags, sizeof(flags)); + card->hw_iface.peek(card->hw, card->u.c.rxmb_off, &rxbuf, sizeof(rxbuf)); + addr = rxbuf.ptr_data_bfr; + if (rxbuf.opp_flag != 0x01) { + printk(KERN_INFO + "%s: corrupted Rx buffer @ 0x%lX, flag = 0x%02X!\n", + card->devname, card->u.c.rxmb_off, rxbuf.opp_flag); + printk(KERN_INFO "Code name: "); + for(i = 0; i < 4; i ++) + printk(KERN_INFO "%c", + flags.global_info_struct.codename[i]); + printk(KERN_INFO "\n"); + printk(KERN_INFO "Code version: "); + for(i = 0; i < 4; i ++) + printk(KERN_INFO "%c", + flags.global_info_struct.codeversion[i]); + printk(KERN_INFO "\n"); + + /* Bug Fix: Mar 6 2000 + * If we get a corrupted mailbox, it measn that driver + * is out of sync with the firmware. There is no recovery. + * If we don't turn off all interrupts for this card + * the machine will crash. + */ + printk(KERN_INFO "%s: Critical router failure ...!!!\n", + card->devname); + printk(KERN_INFO "Please contact Sangoma Technologies !\n"); + hdlc_set_intr_mode(card,0); + return; + } + + if (rxbuf.error_flag){ + printk(KERN_INFO "%s: Rx bad frame: error_flag=%i : len=%i\n", + card->devname,rxbuf.error_flag, rxbuf.frame_length); + goto rx_exit_kick; + } + + + if ((rxbuf.frame_length < (4+CRC_LENGTH)) || + (rxbuf.frame_length > (card->wandev.mtu+CRC_LENGTH))){ + printk(KERN_INFO "%s: Rx bad frame: invalid length : len=%i\n", + card->devname,rxbuf.frame_length); + goto rx_exit_kick; + } + + /* Take off two CRC bytes */ + len = rxbuf.frame_length - CRC_LENGTH; + + /* Allocate socket buffer */ + skb = skb_dequeue(&fr_prot->rx_free); + if (skb == NULL) { + if (net_ratelimit()){ + printk(KERN_INFO "%s: FR skb rx queue, Qlen=%i, is empty: no rx buffers available!\n", + card->devname,MAX_FR_RX_BUF); + + printk(KERN_INFO "%s: The rx queue should be increased via config file!\n", + card->devname); + + printk(KERN_INFO "%s: TQ Critical 0x%lX\n", + card->devname,fr_prot->tq_working); + } + ++card->wandev.stats.rx_dropped; + goto rx_exit_kick; + } + + /* Copy data to the socket buffer */ + if((addr + len) > card->u.c.rx_top_off + 1) { + unsigned tmp = card->u.c.rx_top_off - addr + 1; + buf = skb_put(skb, tmp); + card->hw_iface.peek(card->hw, addr, buf, tmp); + addr = card->u.c.rx_base_off; + len -= tmp; + } + + buf = skb_put(skb, len); + card->hw_iface.peek(card->hw, addr, buf, len); + skb->mac.raw = skb->data; + +#ifdef RX_PKT_DEBUG + if (skb->len <= 7 && !(skb->data[3]&0x01)){ + int x; + + if (skb->len == 7 && (skb->data[6]&0x01)) + goto rx_skip_error; + + DEBUG_EVNET("ERROR !!! RX ISR: Annexg Rx Frame received %i : orig %i\n", + skb->len,(rxbuf.frame_length-CRC_LENGTH)); + + printk(KERN_INFO "Bad Packet : "); + for (x=0;xlen;x++){ + printk("%X ",skb->data[x]); + } + printk("\n"); + printk(KERN_INFO "\n"); + + printk(KERN_INFO "Element=%x Curr Ptr %x Len=%i Top %x\n", + card->u.c.rxmb_off, + (u32)addr,rxbuf.frame_length, + (u32)card->u.c.rx_top_off); + + printk(KERN_INFO "ERROR WE ARE DEAD !!!\n"); + + hdlc_set_intr_mode(card,0); + goto rx_exit; + +rx_skip_error: + } +#endif + + skb_queue_tail(&fr_prot->rx_used,skb); + +rx_exit_kick: + if (!test_and_set_bit(0,&fr_prot->tq_working)){ + tasklet_schedule(&fr_prot->wanpipe_task); + } + +rx_exit: + /* Release buffer element and calculate a pointer to the next one */ + rxbuf.opp_flag = 0x00; + + card->hw_iface.poke_byte(card->hw, + card->u.c.rxmb_off+offsetof(CHDLC_DATA_RX_STATUS_EL_STRUCT, opp_flag), + rxbuf.opp_flag); + + card->u.c.rxmb_off += sizeof(rxbuf); + if (card->u.c.rxmb_off > card->u.c.rxbuf_last_off){ + card->u.c.rxmb_off = card->u.c.rxbuf_base_off; + } +} + +static netdevice_t * move_dev_to_next (sdla_t *card, netdevice_t *dev) +{ + struct wan_dev_le *devle; + + if (!dev){ + return dev; + } + + if (card->wandev.new_if_cnt == 1){ + return dev; + } + + WAN_LIST_FOREACH(devle, &card->wandev.dev_head, dev_link){ + if (devle->dev == dev){ + dev = WAN_DEVLE2DEV(WAN_LIST_NEXT(devle, dev_link)); + if (!dev){ + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + } + return dev; + } + } + return dev; +} + +static void tx_intr (sdla_t *card) +{ + fr_prot_t *fr_prot=FR_PROT_AREA(card); + struct sk_buff *skb; + netdevice_t *dev; + int i=0,no_dev_busy=0; + + if (test_bit(SEND_CRIT,&card->wandev.critical)){ + return; + } + + set_bit(SEND_TXIRQ_CRIT,&card->wandev.critical); + while ((skb=skb_dequeue(&fr_prot->lmi_queue))!=NULL){ + if (hdlc_send(card, skb->data, skb->len)){ + skb_queue_head(&fr_prot->lmi_queue,skb); + + /* We do not clear the critical flag because + * we want to stop the if_send() from + * attempting to tx. Since we have to + * tx the fr stuff first */ + return; + } + //card->wandev.stats.tx_aborted_errors++; + dev_kfree_skb_any(skb); + } + clear_bit(SEND_TXIRQ_CRIT,&card->wandev.critical); + + if (fr_prot->tx_dev == NULL){ + fr_prot->tx_dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + } + + dev = fr_prot->tx_dev; + if (!dev){ + printk(KERN_INFO "%s: No dev in tx intr\n",card->devname); + card->hw_iface.clear_bit(card->hw, card->intr_perm_off, APP_INT_ON_TX_FRAME); + return; + } + + for (;;){ + + if (!dev || !(dev->flags & IFF_UP)){ + goto tx_skip; + } + + if (is_queue_stopped(dev)){ + wake_net_dev(dev); + +#ifdef CONFIG_PRODUCT_WANPIPE_ANNEXG + { + fr_private_area_t *chan=dev->priv; + if (chan && chan->common.usedby == ANNEXG && chan->annexg_dev){ + if (IS_FUNC_CALL(lapb_protocol,lapb_mark_bh)) + lapb_protocol.lapb_mark_bh(chan->annexg_dev); + } + } +#endif + dev=move_dev_to_next(card,dev); + break; + } + +tx_skip: + dev=move_dev_to_next(card,dev); + if (++i >= card->wandev.new_if_cnt){ + no_dev_busy=1; + break; + } + } + + fr_prot->tx_dev = dev; + + if (no_dev_busy){ + card->hw_iface.clear_bit(card->hw, card->intr_perm_off, APP_INT_ON_TX_FRAME); + } +} + + +/*============================================================================ + * Timer interrupt handler. + * The timer interrupt is used for two purposes: + * 1) Processing udp calls from 'cpipemon'. + * 2) Reading board-level statistics for updating the proc file system. + */ +void timer_intr(sdla_t *card) +{ + + if (test_bit(SEND_CRIT,&card->wandev.critical)){ + return; + } + +#ifdef TE1_56_CARD_SUPPORT + /* TE timer interrupt */ + if (card->u.c.timer_int_enabled & TMR_INT_ENABLED_TE) { + DEBUG_EVENT("%s: TE Polling\n",card->devname); + card->wandev.fe_iface.polling(&card->fe); + card->u.c.timer_int_enabled &= ~TMR_INT_ENABLED_TE; + } +#endif + + /* only disable the timer interrupt if there are no udp or statistic */ + /* updates pending */ + if(!card->u.c.timer_int_enabled) { + card->hw_iface.clear_bit(card->hw, card->intr_perm_off, APP_INT_ON_TIMER); + } +} + +/*------------------------------------------------------------------------------ + Miscellaneous Functions + - set_hdlc_config() used to set configuration options on the board +------------------------------------------------------------------------------*/ + +static int set_hdlc_config(sdla_t* card) +{ + + CHDLC_CONFIGURATION_STRUCT cfg; + + memset(&cfg, 0, sizeof(CHDLC_CONFIGURATION_STRUCT)); + + if(card->wandev.clocking) + cfg.baud_rate = card->wandev.bps; + + cfg.line_config_options = (card->wandev.interface == WANOPT_RS232) ? + INTERFACE_LEVEL_RS232 : INTERFACE_LEVEL_V35; + + cfg.modem_config_options = 0; + //API OPTIONS + cfg.CHDLC_API_options = DISCARD_RX_ERROR_FRAMES; + cfg.modem_status_timer = 100; + cfg.CHDLC_protocol_options = HDLC_STREAMING_MODE; + cfg.percent_data_buffer_for_Tx = 50; + cfg.CHDLC_statistics_options = (CHDLC_TX_DATA_BYTE_COUNT_STAT | + CHDLC_RX_DATA_BYTE_COUNT_STAT); + cfg.max_CHDLC_data_field_length = card->wandev.mtu+CRC_LENGTH; + + cfg.transmit_keepalive_timer = 0; + cfg.receive_keepalive_timer = 0; + cfg.keepalive_error_tolerance = 0; + cfg.SLARP_request_timer = 0; + + cfg.IP_address = 0; + cfg.IP_netmask = 0; + + return hdlc_configure(card, &cfg); +} + +/*============================================================================ + * Process global exception condition + */ +static int process_global_exception(sdla_t *card) +{ + wan_mbox_t* mbox = &card->wan_mbox; + int err; + + mbox->wan_data_len = 0; + mbox->wan_command = READ_GLOBAL_EXCEPTION_CONDITION; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mbox); + + if(err != CMD_TIMEOUT ){ + + switch(mbox->wan_return_code) { + + case EXCEP_MODEM_STATUS_CHANGE: + + +#ifdef TE1_56_CARD_SUPPORT + if (IS_56K_CARD(card)) { + + FRONT_END_STATUS_STRUCT FE_status; + + card->hw_iface.peek(card->hw, + card->fe_status_off, + &FE_status, + sizeof(FE_status)); + + card->fe.fe_param.k56_param.RR8_reg_56k = + FE_status.FE_U.stat_56k.RR8_56k; + card->fe.fe_param.k56_param.RRA_reg_56k = + FE_status.FE_U.stat_56k.RRA_56k; + card->fe.fe_param.k56_param.RRC_reg_56k = + FE_status.FE_U.stat_56k.RRC_56k; + card->wandev.fe_iface.read_alarm(&card->fe, 0); + + fr_handle_front_end_state(card); + break; + + } + + if (IS_TE1_CARD(card)) { + + /* TE1 T1/E1 interrupt */ + card->wandev.fe_iface.isr(&card->fe); + fr_handle_front_end_state(card); + break; + } +#endif + + if (mbox->wan_data[0] & DCD_HIGH){ + card->fe.fe_status = FE_CONNECTED; + }else{ + card->fe.fe_status = FE_DISCONNECTED; + } + + printk(KERN_INFO "%s: Modem status change\n", + card->devname); + + switch(mbox->wan_data[0] & (DCD_HIGH | CTS_HIGH)) { + case (DCD_HIGH): + printk(KERN_INFO "%s: DCD high, CTS low\n",card->devname); + break; + case (CTS_HIGH): + printk(KERN_INFO "%s: DCD low, CTS high\n",card->devname); + break; + case ((DCD_HIGH | CTS_HIGH)): + printk(KERN_INFO "%s: DCD high, CTS high\n",card->devname); + break; + default: + printk(KERN_INFO "%s: DCD low, CTS low\n",card->devname); + break; + } + fr_handle_front_end_state(card); + break; + + case EXCEP_TRC_DISABLED: + printk(KERN_INFO "%s: Line trace disabled\n", + card->devname); + break; + + case EXCEP_IRQ_TIMEOUT: + printk(KERN_INFO "%s: IRQ timeout occurred\n", + card->devname); + break; + + case 0x16: + break; + + default: + printk(KERN_INFO "%s: Global exception %x\n", + card->devname, mbox->wan_return_code); + break; + } + } + return 0; +} + + +/*============================================================================ + * Process fr exception condition + */ +static int process_hdlc_exception(sdla_t *card) +{ + wan_mbox_t* mb = &card->wan_mbox; + int err; + + mb->wan_data_len = 0; + mb->wan_command = READ_CHDLC_EXCEPTION_CONDITION; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if(err != CMD_TIMEOUT) { + + switch (err) { + + case EXCEP_LINK_ACTIVE: + card->fe.fe_status = FE_CONNECTED; + fr_handle_front_end_state (card); + break; + + case EXCEP_LINK_INACTIVE_MODEM: + card->fe.fe_status = FE_DISCONNECTED; + fr_handle_front_end_state (card); + break; + + case EXCEP_LOOPBACK_CONDITION: + printk(KERN_INFO "%s: Loopback Condition Detected.\n", + card->devname); + break; + + case NO_CHDLC_EXCEP_COND_TO_REPORT: + printk(KERN_INFO "%s: No exceptions reported.\n", + card->devname); + break; + default: + printk(KERN_INFO "%s: Exception Condition %x!\n", + card->devname,err); + break; + } + + } + return 0; +} + + +/*============================================================================= + * Store a UDP management packet for later processing. + */ +#if 0 +static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, + struct sk_buff *skb, netdevice_t* dev, + fr_private_area_t* chan ) +{ + int udp_pkt_stored = 0; + + if(!chan->udp_pkt_lgth && + (skb->len <= MAX_LGTH_UDP_MGNT_PKT)) { + chan->udp_pkt_lgth = skb->len; + chan->udp_pkt_src = udp_pkt_src; + memcpy(chan->udp_pkt_data, skb->data, skb->len); + card->u.c.timer_int_enabled = TMR_INT_ENABLED_UDP; + udp_pkt_stored = 1; + } + + if(udp_pkt_src == UDP_PKT_FRM_STACK) + dev_kfree_skb_any(skb); + else + dev_kfree_skb_any(skb); + + return(udp_pkt_stored); +} +#endif + +static void fr_handle_front_end_state (void* card_id) +{ + struct wan_dev_le *devle; + sdla_t *card = (sdla_t*)card_id; + netdevice_t *dev; + fr_private_area_t *chan; + + if (card->wandev.ignore_front_end_status == WANOPT_YES){ + return; + } + + WAN_LIST_FOREACH(devle, &card->wandev.dev_head, dev_link){ + dev = WAN_DEVLE2DEV(devle); + if (!dev || !wan_netif_priv(dev)) + continue; + chan = wan_netif_priv(dev); + if (card->fe.fe_status == FE_CONNECTED){ + if (chan->dlci_state & PVC_STATE_ACTIVE && + card->wandev.state == WAN_CONNECTED && + chan->common.state != WAN_CONNECTED){ + chan_set_state(dev,WAN_CONNECTED); + } + }else{ + if (chan->common.state != WAN_DISCONNECTED){ + if (chan->route_flag == ROUTE_ADDED) { + chan->route_flag = REMOVE_ROUTE; + /* The state change will trigger + * the fr polling routine */ + } + + if (chan->inarp == INARP_CONFIGURED) { + chan->inarp = INARP_REQUEST; + } + + chan_set_state(dev,WAN_DISCONNECTED); + } + } + } +} + +/*============================================================================== + * Initializes the Statistics values in the fr_channel structure. + */ +void init_chan_statistics( fr_channel_t* chan) +{ + memset(&chan->drvstats_if_send.if_send_entry, 0, + sizeof(if_send_stat_t)); + memset(&chan->drvstats_rx_intr.rx_intr_no_socket, 0, + sizeof(rx_intr_stat_t)); + memset(&chan->drvstats_gen.UDP_PIPE_mgmt_kmalloc_err, 0, + sizeof(pipe_mgmt_stat_t)); +} + +/*============================================================================== + * Initializes the Statistics values in the Sdla_t structure. + */ +void init_global_statistics( sdla_t* card ) +{ + /* Intialize global statistics for a card */ + memset(&card->statistics.isr_entry, 0, sizeof(global_stats_t)); +} + + + +/*============================================================================== + * Process UDP call of type FPIPE8ND + */ +static int process_udp_mgmt_pkt(sdla_t* card, void *local_dev) +{ + unsigned char frames; + unsigned int len; + unsigned short buffer_length; + wan_mbox_t *mbox = &card->wan_mbox; + int err; + struct timeval tv; + int udp_mgmt_req_valid = 1; + netdevice_t* dev; + fr_channel_t* chan; + wan_udp_pkt_t *wan_udp_pkt; + fpipemon_trc_t* fpipemon_trc; + fr_prot_t *fr_prot = FR_PROT_AREA(card); + SHARED_MEMORY_INFO_STRUCT flags; + int dlci = 0; + int orig_cmd=0; + + if (local_dev == NULL){ + + return 0; +#if 0 + /* Find network interface for this packet */ + dev = find_channel(card, dlci); + if (!dev){ + card->u.f.udp_pkt_lgth = 0; + return -ENODEV; + } + if ((chan = dev->priv) == NULL){ + card->u.f.udp_pkt_lgth = 0; + return -ENODEV; + } + + /* If the UDP packet is from the network, we are going to have to + transmit a response. Before doing so, we must check to see that + we are not currently transmitting a frame (in 'if_send()') and + that we are not already in a 'delayed transmit' state. + */ + if(udp_pkt_src == UDP_PKT_FRM_NETWORK) { + if (check_tx_status(card,dev)){ + card->u.f.udp_pkt_lgth = 0; + return -EBUSY; + } + } + + wan_udp_pkt = (wan_udp_pkt_t *)card->u.f.udp_pkt_data; + + + if(udp_pkt_src == UDP_PKT_FRM_NETWORK) { + + switch(wan_udp_pkt->wan_udp_command) { + + case FR_READ_MODEM_STATUS: + case FR_READ_STATUS: + case FPIPE_ROUTER_UP_TIME: + case FR_READ_ERROR_STATS: + case FPIPE_DRIVER_STAT_GEN: + case FR_READ_STATISTICS: + case FR_READ_ADD_DLC_STATS: + case FR_READ_CONFIG: + case FR_READ_CODE_VERSION: + case WAN_GET_MEDIA_TYPE: + case WAN_FE_GET_STAT: + udp_mgmt_req_valid = 1; + break; + default: + udp_mgmt_req_valid = 0; + break; + } + } +#endif + }else{ + dev = (netdevice_t *) local_dev; + if ((chan = dev->priv) == NULL){ + return -ENODEV; + } + dlci=chan->dlci; + + if (atomic_read(&chan->udp_pkt_len) == 0){ + return -ENODEV; + } + + wan_udp_pkt = (wan_udp_pkt_t *)chan->udp_pkt_data; + udp_mgmt_req_valid=1; + } + + //debug_print_udp_pkt((u8*)wan_udp_pkt,sizeof(wan_udp_pkt_t),0,1); + card->hw_iface.peek(card->hw, card->flags_off, &flags, sizeof(flags)); + if(!udp_mgmt_req_valid) { + /* set length to 0 */ + wan_udp_pkt->wan_udp_data_len = 0; + /* set return code */ + wan_udp_pkt->wan_udp_return_code = 0xCD; + + chan->drvstats_gen.UDP_PIPE_mgmt_direction_err ++; + + if (net_ratelimit()){ + printk(KERN_INFO + "%s: Warning, Illegal UDP command attempted from network: %x\n", + card->devname,wan_udp_pkt->wan_udp_command); + } + + } else { + + struct sk_buff *skb; + struct sk_buff_head *trace_queue; + + switch(wan_udp_pkt->wan_udp_command) { + + case FR_READ_CONFIG: + case FR_READ_CODE_VERSION: + wan_udp_pkt->wan_udp_return_code = 0; + wan_udp_pkt->wan_udp_data_len=0; + break; + + case FR_LIST_ACTIVE_DLCI: + { + unsigned short *data_buf = (unsigned short*)wan_udp_pkt->wan_udp_data; + int ch,data_len=0; + + for (ch=0;chglobal_dlci_map[ch]) + continue; + + if (fr_prot->global_dlci_map[ch] & PVC_STATE_ACTIVE){ + *data_buf=ch; + data_buf ++; + data_len +=2; + } + } + wan_udp_pkt->wan_udp_return_code = 0; + wan_udp_pkt->wan_udp_data_len = data_len; + } + break; + + case FR_READ_STATUS: + { + unsigned char *data_buf = (unsigned char*)wan_udp_pkt->wan_udp_data; + int ch, data_len=0; + + *data_buf = (card->wandev.state == WAN_CONNECTED) ? 1:0; + data_buf++; + data_len+=1; + + for (ch=0;chglobal_dlci_map[ch]) + continue; + + *(unsigned short*)data_buf=ch; + data_buf +=2; + *data_buf = (fr_prot->global_dlci_map[ch] | 0x40); + data_buf++; + data_len += 3; + } + + wan_udp_pkt->wan_udp_return_code = 0; + wan_udp_pkt->wan_udp_data_len = data_len; + } + break; + + case FR_READ_STATISTICS: + + memcpy(wan_udp_pkt->wan_udp_data,&fr_prot->link_stats,sizeof(fr_link_stat_t)); + wan_udp_pkt->wan_udp_data_len = sizeof(fr_link_stat_t); + wan_udp_pkt->wan_udp_return_code = 0; + break; + + + case FPIPE_ENABLE_TRACING: + + wan_udp_pkt->wan_udp_return_code = 0; + + if (wan_udp_pkt->wan_udp_data[0] & TRC_ACTIVE){ + + if (!test_bit(0,&chan->tracing_enabled)){ + + chan->stats.tx_fifo_errors=0; + chan->stats.rx_over_errors=0; + chan->trace_timeout=jiffies; + + skb_queue_purge(&chan->trace_queue); + + set_bit (0,&chan->tracing_enabled); + printk(KERN_INFO "%s: %s: Frame Relay DLCI=%i trace enabled!\n", + card->devname,chan->if_name,chan->dlci); + }else{ + printk(KERN_INFO "%s: %s: Error: Frame Relay DLCI=%i trace running!\n", + card->devname,chan->if_name,chan->dlci); + wan_udp_pkt->wan_udp_return_code = 2; + } + + }else if (wan_udp_pkt->wan_udp_data[0] & (TRC_SIGNALLING_FRMS|TRC_INFO_FRMS)){ + + if (test_bit(0,&chan->tracing_enabled)){ + printk(KERN_INFO "\n"); + printk(KERN_INFO "%s: %s: Error: FR DLCI=%i trace running!\n", + card->devname,chan->if_name,chan->dlci); + wan_udp_pkt->wan_udp_return_code = 2; + + }else if (test_bit(1,&chan->tracing_enabled)){ + + printk(KERN_INFO "\n"); + printk(KERN_INFO "%s: Error: Frame Relay LMI trace running!\n", + card->devname); + wan_udp_pkt->wan_udp_return_code = 1; + + }else if(!test_bit(0,&fr_prot->tracing_enabled)){ + + skb_queue_purge(&fr_prot->trace_queue); + fr_prot->trace_timeout=jiffies; + + set_bit (1,&chan->tracing_enabled); + set_bit (0,&fr_prot->tracing_enabled); + printk(KERN_INFO "%s: Frame Relay LMI trace enabled!\n", + card->devname); + }else{ + printk(KERN_INFO "\n"); + printk(KERN_INFO "%s: %s: Error: FR LMI trace running!\n", + card->devname,chan->if_name); + wan_udp_pkt->wan_udp_return_code = 2; + } + + }else{ + printk(KERN_INFO "%s: %s: Invalid trace command options!\n", + card->devname,chan->if_name); + wan_udp_pkt->wan_udp_return_code = 1; + } + + if (wan_udp_pkt->wan_udp_return_code == 0){ + chan->stats.rx_fifo_errors=0; + chan->stats.tx_fifo_errors=0; + } + + wan_udp_pkt->wan_udp_data_len=0; + break; + + + case FPIPE_DISABLE_TRACING: + + wan_udp_pkt->wan_udp_return_code = 0; + + if(test_bit(0,&chan->tracing_enabled)) { + + clear_bit(0,&chan->tracing_enabled); + skb_queue_purge(&chan->trace_queue); + printk(KERN_INFO "%s: %s: Disabling FR DLCI=%i trace\n", + card->devname,chan->if_name, chan->dlci); + + }else if (test_bit(1,&chan->tracing_enabled)){ + + clear_bit(1,&chan->tracing_enabled); + clear_bit(0,&fr_prot->tracing_enabled); + skb_queue_purge(&fr_prot->trace_queue); + printk(KERN_INFO "%s: %s: Disabling FR LMI trace\n", + card->devname,chan->if_name); + + }else{ + /* set return code to line trace already + disabled */ + //printk(KERN_INFO "%s: %s: Frame Relay trace already disabled!\n", + // card->devname,chan->if_name); + wan_udp_pkt->wan_udp_return_code = 1; + } + + /* set return code */ + wan_udp_pkt->wan_udp_data_len=0; + break; + + case FPIPE_GET_TRACE_INFO: + + if(test_bit(0,&chan->tracing_enabled)){ + trace_queue=&chan->trace_queue; + chan->trace_timeout=jiffies; + }else if (test_bit(1,&chan->tracing_enabled)){ + trace_queue=&fr_prot->trace_queue; + fr_prot->trace_timeout=jiffies; + }else{ + printk(KERN_INFO "%s: %s: Error FR trace not enabled\n", + card->devname,chan->if_name); + /* set return code */ + wan_udp_pkt->wan_udp_return_code = 1; + wan_udp_pkt->wan_udp_data_len=0; + break; + } + + frames=0; + buffer_length = 0; + wan_udp_pkt->wan_udp_data[0x00] = 0x00; + + while ((skb=skb_dequeue(trace_queue)) != NULL){ + + fr_trc_el_t *trc_el = (fr_trc_el_t*)skb->data; + + if (trc_el->length > skb->len){ + /* The frame is invalid or corrupted, + * drop it */ + dev_kfree_skb_any(skb); + continue; + } + + if((trc_el->length + sizeof(fpipemon_trc_hdr_t) + 1) > + (MAX_TRACE_BUFFER - buffer_length)){ + wan_udp_pkt->wan_udp_data[0x00] |= MORE_TRC_DATA; + skb_queue_head(trace_queue,skb); + break; + } + + fpipemon_trc = + (fpipemon_trc_t *)&wan_udp_pkt->wan_udp_data[buffer_length]; + fpipemon_trc->fpipemon_trc_hdr.status = + trc_el->attr; + fpipemon_trc->fpipemon_trc_hdr.tmstamp = + trc_el->tmstamp; + fpipemon_trc->fpipemon_trc_hdr.length = + trc_el->length; + + if(!trc_el->length) { + + fpipemon_trc->fpipemon_trc_hdr.data_passed = 0x00; + + }else { + fpipemon_trc->fpipemon_trc_hdr.data_passed = 0x01; + memcpy(fpipemon_trc->data, (skb->data+sizeof(fr_trc_el_t)), trc_el->length); + } + + buffer_length += sizeof(fpipemon_trc_hdr_t); + if(fpipemon_trc->fpipemon_trc_hdr.data_passed) { + buffer_length += trc_el->length; + } + + dev_kfree_skb_any(skb); + + if (++frames >= MAX_FRMS_TRACED){ + break; + } + + if(wan_udp_pkt->wan_udp_data[0x00] & MORE_TRC_DATA) { + break; + } + } + + if(frames == MAX_FRMS_TRACED) { + wan_udp_pkt->wan_udp_data[0x00] |= MORE_TRC_DATA; + } + + /* set the total number of frames passed */ + wan_udp_pkt->wan_udp_data[0x00] |= + ((frames << 1) & (MAX_FRMS_TRACED << 1)); + + /* set the data length and return code */ + wan_udp_pkt->wan_udp_data_len = buffer_length; + wan_udp_pkt->wan_udp_return_code = 0; + break; + + case FPIPE_FT1_READ_STATUS: + ((unsigned char *)wan_udp_pkt->wan_udp_data )[0] = + flags.FT1_info_struct.parallel_port_A_input; + + ((unsigned char *)wan_udp_pkt->wan_udp_data )[1] = + flags.FT1_info_struct.parallel_port_B_input; + wan_udp_pkt->wan_udp_return_code = 0; + wan_udp_pkt->wan_udp_data_len = 2; + break; + + + case FPIPE_FLUSH_DRIVER_STATS: + init_chan_statistics(chan); + init_global_statistics(card); + wan_udp_pkt->wan_udp_data_len=0; + break; + + case FPIPE_ROUTER_UP_TIME: + do_gettimeofday( &tv ); + card->u.c.router_up_time = tv.tv_sec - + card->u.c.router_start_time; + *(unsigned long *)&wan_udp_pkt->wan_udp_data = + card->u.c.router_up_time; + wan_udp_pkt->wan_udp_data_len = sizeof(unsigned long); + wan_udp_pkt->wan_udp_return_code = COMMAND_OK; + break; + + case FPIPE_DRIVER_STAT_IFSEND: + memcpy(wan_udp_pkt->wan_udp_data, + &chan->drvstats_if_send.if_send_entry, + sizeof(if_send_stat_t)); + wan_udp_pkt->wan_udp_data_len =sizeof(if_send_stat_t); + wan_udp_pkt->wan_udp_return_code = 0; + break; + + case FPIPE_DRIVER_STAT_INTR: + + memcpy(wan_udp_pkt->wan_udp_data, + &card->statistics.isr_entry, + sizeof(global_stats_t)); + + memcpy(&wan_udp_pkt->wan_udp_data[sizeof(global_stats_t)], + &chan->drvstats_rx_intr.rx_intr_no_socket, + sizeof(rx_intr_stat_t)); + + wan_udp_pkt->wan_udp_data_len = + sizeof(global_stats_t) + + sizeof(rx_intr_stat_t); + wan_udp_pkt->wan_udp_return_code = 0; + break; + + case FPIPE_DRIVER_STAT_GEN: + memcpy(wan_udp_pkt->wan_udp_data, + &chan->drvstats_gen.UDP_PIPE_mgmt_kmalloc_err, + sizeof(pipe_mgmt_stat_t)); + + memcpy(&wan_udp_pkt->wan_udp_data[sizeof(pipe_mgmt_stat_t)], + &card->statistics, sizeof(global_stats_t)); + + wan_udp_pkt->wan_udp_data_len = sizeof(global_stats_t)+ + sizeof(rx_intr_stat_t); + wan_udp_pkt->wan_udp_return_code = 0; + break; + + + case FR_FT1_STATUS_CTRL: + /* Enable FT1 MONITOR STATUS */ + mbox->wan_command = 0x1C; + if ((wan_udp_pkt->wan_udp_data[0] & ENABLE_READ_FT1_STATUS) || + (wan_udp_pkt->wan_udp_data[0] & ENABLE_READ_FT1_OP_STATS)) { + + if( rCount++ != 0 ) { + wan_udp_pkt->wan_udp_return_code = COMMAND_OK; + wan_udp_pkt->wan_udp_data_len=1; + mbox->wan_data_len = 1; + break; + } + } + + /* Disable FT1 MONITOR STATUS */ + if( wan_udp_pkt->wan_udp_data[0] == 0) { + + if( --rCount != 0) { + wan_udp_pkt->wan_udp_return_code = COMMAND_OK; + wan_udp_pkt->wan_udp_data_len=1; + mbox->wan_data_len = 1; + break; + } + } + goto dflt_1; + + case FR_SET_FT1_MODE: + mbox->wan_command = 0x1E; + goto dflt_1; + + +#ifdef TE1_56_CARD_SUPPORT + case WAN_GET_MEDIA_TYPE: + case WAN_FE_GET_STAT: + case WAN_FE_SET_LB_MODE: + case WAN_FE_FLUSH_PMON: + case WAN_FE_GET_CFG: + + if (IS_TE1_CARD(card)){ + card->wandev.fe_iface.process_udp( + &card->fe, + &wan_udp_pkt->wan_udp_cmd, + &wan_udp_pkt->wan_udp_data[0]); + }else if (IS_56K_CARD(card)){ + card->wandev.fe_iface.process_udp( + &card->fe, + &wan_udp_pkt->wan_udp_cmd, + &wan_udp_pkt->wan_udp_data[0]); + }else{ + if (wan_udp_pkt->wan_udp_command == WAN_GET_MEDIA_TYPE){ + wan_udp_pkt->wan_udp_data_len = sizeof(unsigned char); + wan_udp_pkt->wan_udp_return_code = CMD_OK; + }else{ + wan_udp_pkt->wan_udp_return_code = WAN_UDP_INVALID_CMD; + } + } + break; + +#if 0 + case WAN_FE_SET_LB_MODE: + /* Activate/Deactivate Line Loopback modes */ + if (IS_TE1_CARD(card)){ + err = card->wandev.fe_iface.set_fe_lbmode( + &card->fe, + wan_udp_pkt->wan_udp_data[0], + wan_udp_pkt->wan_udp_data[1]); + wan_udp_pkt->wan_udp_return_code = + (!err) ? CMD_OK : WAN_UDP_FAILED_CMD; + }else{ + wan_udp_pkt->wan_udp_return_code = WAN_UDP_INVALID_CMD; + } + wan_udp_pkt->wan_udp_data_len = 0x00; + break; + + case WAN_GET_MEDIA_TYPE: + wan_udp_pkt->wan_udp_data[0] = + (IS_T1_CARD(card) ? WAN_MEDIA_T1 : + IS_E1_CARD(card) ? WAN_MEDIA_E1 : + IS_56K_CARD(card) ? WAN_MEDIA_56K : + WAN_MEDIA_NONE); + wan_udp_pkt->wan_udp_data_len = sizeof(unsigned char); + wan_udp_pkt->wan_udp_return_code = COMMAND_OK; + break; + + case WAN_FE_GET_STAT: + if (IS_TE1_CARD(card)) { + /* TE1_56K Read T1/E1/56K alarms */ + *(unsigned long *)&wan_udp_pkt->wan_udp_data = + card->wandev.fe_iface.read_alarm( + &card->fe, 0); + /* TE1 Update T1/E1 perfomance counters */ + sdla_te_pmon(card); + memcpy(&wan_udp_pkt->wan_udp_data[sizeof(unsigned long)], + &card->wandev.te_pmon, + sizeof(sdla_te_pmon_t)); + wan_udp_pkt->wan_udp_return_code = COMMAND_OK; + wan_udp_pkt->wan_udp_data_len = + sizeof(unsigned long) + sizeof(sdla_te_pmon_t); + }else if (IS_56K_CARD(card)){ + /* 56K Update CSU/DSU alarms */ + card->wandev.k56_alarm = sdla_56k_alarm(card, 1); + *(unsigned long *)&wan_udp_pkt->wan_udp_data = + card->wandev.k56_alarm; + wan_udp_pkt->wan_udp_return_code = COMMAND_OK; + wan_udp_pkt->wan_udp_data_len = sizeof(unsigned long); + } + break; + + case WAN_FE_FLUSH_PMON: + /* TE1 Flush T1/E1 pmon counters */ + if (IS_TE1_CARD(card)){ + card->wandev.fe_iface.flush_pmon(&card->fe); + wan_udp_pkt->wan_udp_return_code = COMMAND_OK; + } + wan_udp_pkt->wan_udp_data_len=0; + break; + + case WAN_FE_GET_CFG: + /* Read T1/E1 configuration */ + if (IS_TE1_CARD(card)){ + memcpy(&wan_udp_pkt->wan_udp_data[0], + &card->wandev.te_cfg, + sizeof(sdla_te_cfg_t)); + wan_udp_pkt->wan_udp_return_code = COMMAND_OK; + wan_udp_pkt->wan_udp_data_len = sizeof(sdla_te_cfg_t); + } + break; +#endif + + case WAN_GET_PROTOCOL: + wan_udp_pkt->wan_udp_data[0] = card->wandev.config_id; + wan_udp_pkt->wan_udp_return_code = CMD_OK; + wan_udp_pkt->wan_udp_data_len = 1; + break; + + case WAN_GET_PLATFORM: + wan_udp_pkt->wan_udp_data[0] = WAN_LINUX_PLATFORM; + wan_udp_pkt->wan_udp_return_code = CMD_OK; + wan_udp_pkt->wan_udp_data_len = 1; + break; + +#endif + + + default: + orig_cmd=wan_udp_pkt->wan_udp_command; + switch(wan_udp_pkt->wan_udp_command){ + + case FR_READ_MODEM_STATUS: + mbox->wan_command = READ_MODEM_STATUS; + break; + + case FR_READ_ERROR_STATS: + mbox->wan_command = READ_COMMS_ERROR_STATS; + break; + + case FR_FLUSH_ERROR_STATS: + mbox->wan_command = FLUSH_COMMS_ERROR_STATS; + break; + + default: + mbox->wan_return_code=1; + goto udp_cmd_done; + + } +dflt_1: + + /* it's a board command */ + mbox->wan_data_len = wan_udp_pkt->wan_udp_data_len; + if (mbox->wan_data_len) { + memcpy(&mbox->wan_data, (unsigned char *) wan_udp_pkt-> + wan_udp_data, mbox->wan_data_len); + } + + /* run the command on the board */ + err = card->hw_iface.cmd(card->hw, card->mbox_off, mbox); + if (err != COMMAND_OK) { + hdlc_error(card,err,mbox); + break; + } + + /* copy the result back to our buffer */ + memcpy(&wan_udp_pkt->wan_udp_hdr.wan_cmd, mbox, sizeof(wan_cmd_t)); + + if (mbox->wan_data_len) { + memcpy(&wan_udp_pkt->wan_udp_data, &mbox->wan_data, + mbox->wan_data_len); + } + + wan_udp_pkt->wan_udp_data_len=mbox->wan_data_len; + wan_udp_pkt->wan_udp_return_code=err; + + if(!err) + chan->drvstats_gen. + UDP_PIPE_mgmt_adptr_cmnd_OK ++; + else + chan->drvstats_gen. + UDP_PIPE_mgmt_adptr_cmnd_timeout ++; + + + switch(orig_cmd){ + + case FR_READ_ERROR_STATS: + { + COMMS_ERROR_STATS_STRUCT *comm_stats = + (COMMS_ERROR_STATS_STRUCT *)mbox->wan_data; + + wan_udp_pkt->wan_udp_data[8]=comm_stats->DCD_state_change_count; + wan_udp_pkt->wan_udp_data[9]=comm_stats->CTS_state_change_count; + wan_udp_pkt->wan_udp_data_len=mbox->wan_data_len=10; + wan_udp_pkt->wan_udp_return_code=0; + } + break; + + } + } + } + +udp_cmd_done: + + /* Fill UDP TTL */ + wan_udp_pkt->wan_ip_ttl = card->wandev.ttl; + + len=0; + if (local_dev){ + len = reply_udp(chan->udp_pkt_data, wan_udp_pkt->wan_udp_data_len); + }else{ + //len = reply_udp(card->u.f.udp_pkt_data, mbox->wan_data_len); + } + + //debug_print_udp_pkt((u8*)wan_udp_pkt,sizeof(wan_udp_pkt_t),0,0); + + if (local_dev){ + atomic_set(&chan->udp_pkt_len,len); + return len; + + } +#if 0 + else if(udp_pkt_src == UDP_PKT_FRM_NETWORK) { + + chan->fr_header_len=2; + chan->fr_header[0]=chan->fr_encap_0; + chan->fr_header[1]=chan->fr_encap_1; + + err = fr_send_data_header(card, dlci, 0, len, + card->u.f.udp_pkt_data,chan->fr_header_len); + if (err){ + chan->drvstats_gen.UDP_PIPE_mgmt_adptr_send_passed ++; + }else{ + chan->drvstats_gen.UDP_PIPE_mgmt_adptr_send_failed ++; + } + + }else{ + /* Allocate socket buffer */ + if((new_skb = dev_alloc_skb(len)) != NULL) { + + /* copy data into new_skb */ + buf = skb_put(new_skb, len); + memcpy(buf, card->u.f.udp_pkt_data, len); + + chan->drvstats_gen. + UDP_PIPE_mgmt_passed_to_stack ++; + new_skb->dev = dev; + new_skb->protocol = htons(ETH_P_IP); + new_skb->mac.raw = new_skb->data; + netif_rx(new_skb); + + } else { + chan->drvstats_gen.UDP_PIPE_mgmt_no_socket ++; + printk(KERN_INFO + "%s: UDP mgmt cmnd, no socket buffers available!\n", + card->devname); + } + } + + + card->u.f.udp_pkt_lgth = 0; +#endif + + return len; + +} + + +/*============================================================================ + * Initialize Receive and Transmit Buffers. + */ + +static void init_hdlc_tx_rx_buff( sdla_t* card) +{ + wan_mbox_t* mb = &card->wan_mbox; + unsigned long tx_config_off; + unsigned long rx_config_off; + CHDLC_TX_STATUS_EL_CFG_STRUCT tx_config; + CHDLC_RX_STATUS_EL_CFG_STRUCT rx_config; + char err; + + mb->wan_data_len = 0; + mb->wan_command = READ_CHDLC_CONFIGURATION; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + + if(err != COMMAND_OK) { + hdlc_error(card,err,mb); + return; + } + + /* ALEX Apr 8 2004 Sangoma ISA card */ + tx_config_off = + ((CHDLC_CONFIGURATION_STRUCT *)mb->wan_data)-> + ptr_CHDLC_Tx_stat_el_cfg_struct; + rx_config_off = + ((CHDLC_CONFIGURATION_STRUCT *)mb->wan_data)-> + ptr_CHDLC_Rx_stat_el_cfg_struct; + + /* Setup Head and Tails for buffers */ + card->hw_iface.peek(card->hw, tx_config_off, &tx_config, sizeof(tx_config)); + card->hw_iface.peek(card->hw, rx_config_off, &rx_config, sizeof(rx_config)); + card->u.c.txbuf_base_off = + tx_config.base_addr_Tx_status_elements; + card->u.c.txbuf_last_off = + card->u.c.txbuf_base_off + + (tx_config.number_Tx_status_elements - 1) * + sizeof(CHDLC_DATA_TX_STATUS_EL_STRUCT); + card->hw_iface.peek(card->hw, tx_config_off, &tx_config, sizeof(tx_config)); + card->u.c.rxbuf_base_off = + rx_config.base_addr_Rx_status_elements; + card->u.c.rxbuf_last_off = + card->u.c.rxbuf_base_off + + (rx_config.number_Rx_status_elements - 1) * + sizeof(CHDLC_DATA_RX_STATUS_EL_STRUCT); + + /* Set up next pointer to be used */ + card->u.c.txbuf_off = + tx_config.next_Tx_status_element_to_use; + card->u.c.rxmb_off = + rx_config.next_Rx_status_element_to_use; + + /* Setup Actual Buffer Start and end addresses */ + card->u.c.rx_base_off = rx_config.base_addr_Rx_buffer; + card->u.c.rx_top_off = rx_config.end_addr_Rx_buffer; + +} + +/*============================================================================= + * Perform Interrupt Test by running READ_CHDLC_CODE_VERSION command MAX_INTR + * _TEST_COUNTER times. + */ +static int intr_test( sdla_t* card) +{ + wan_mbox_t* mb = &card->wan_mbox; + int err,i; + + card->timer_int_enabled = 0; + + /* The critical flag is unset because during intialization (if_open) + * we want the interrupts to be enabled so that when the wpc_isr is + * called it does not exit due to critical flag set. + */ + + err = hdlc_set_intr_mode(card, APP_INT_ON_COMMAND_COMPLETE); + + if (err == CMD_OK) { + for (i = 0; i < MAX_INTR_TEST_COUNTER; i ++) { + mb->wan_data_len = 0; + mb->wan_command = READ_CHDLC_CODE_VERSION; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + } + }else{ + return err; + } + + err = hdlc_set_intr_mode(card, 0); + + if (err != CMD_OK) + return err; + + return 0; +} + +/*============================================================================== + * Determine what type of UDP call it is. FPIPE8ND ? + */ +#if 0 +static int udp_pkt_type( struct sk_buff *skb, sdla_t* card, int direction) +{ + wan_udp_pkt_t *wan_udp_pkt = (wan_udp_pkt_t *)skb->data; + + if (skb->len < sizeof(wan_udp_pkt_t)){ + return UDP_INVALID_TYPE; + } + + + /* Quick HACK */ + if (direction == UDP_PKT_FRM_NETWORK){ + wan_udp_pkt = (wan_udp_pkt_t *)&skb->data[2]; + } + + if((wan_udp_pkt->ip_pkt.protocol == UDPMGMT_UDP_PROTOCOL) && + (wan_udp_pkt->ip_pkt.ver_inet_hdr_length == 0x45) && + (wan_udp_pkt->udp_pkt.udp_dst_port == + ntohs(card->wandev.udp_port)) && + (wan_udp_pkt->wp_mgmt.request_reply == + UDPMGMT_REQUEST)) { + if(!strncmp(wan_udp_pkt->wp_mgmt.signature, + UDPMGMT_FPIPE_SIGNATURE, 8)){ + return UDP_FPIPE_TYPE; + } + } + return UDP_INVALID_TYPE; +} +#endif + +/*============================================================================ + * Set PORT state. + */ +static void chan_set_state (netdevice_t *dev, int state) +{ + fr_private_area_t *chan; + sdla_t *card; + + if (!dev || !dev->priv){ + return; + } + + chan=dev->priv; + card = chan->card; + + if (chan->common.state != state){ + + chan->common.state = state; + + switch (state){ + + case WAN_CONNECTED: + printk (KERN_INFO "%s: %s: DLCI %i: link connected!\n", + card->devname,chan->if_name,chan->dlci); +#ifdef CONFIG_PRODUCT_WANPIPE_ANNEXG + if (chan->common.usedby == ANNEXG && chan->annexg_dev){ + if (IS_FUNC_CALL(lapb_protocol,lapb_link_up)) + lapb_protocol.lapb_link_up(chan->annexg_dev); + } +#endif + break; + + case WAN_CONNECTING: + printk (KERN_INFO "%s: %s: DLCI %i: link connecting...\n", + card->devname,chan->if_name,chan->dlci); + break; + + case WAN_DISCONNECTED: + printk (KERN_INFO "%s: %s: DLCI %i: link disconnected!\n", + card->devname,chan->if_name,chan->dlci); + +#ifdef CONFIG_PRODUCT_WANPIPE_ANNEXG + if (chan->common.usedby == ANNEXG && chan->annexg_dev){ + if (IS_FUNC_CALL(lapb_protocol,lapb_link_down)) + lapb_protocol.lapb_link_down(chan->annexg_dev); + } +#endif + break; + } + } +} + +/*=========================================================================== + * config_hdlc + * + * Configure the fr protocol and enable communications. + * + * The if_open() function binds this function to the poll routine. + * Therefore, this function will run every time the fr interface + * is brought up. We cannot run this function from the if_open + * because if_open does not have access to the remote IP address. + * + * If the communications are not enabled, proceed to configure + * the card and enable communications. + * + * If the communications are enabled, it means that the interface + * was shutdown by ether the user or driver. In this case, we + * have to check that the IP addresses have not changed. If + * the IP addresses have changed, we have to reconfigure the firmware + * and update the changed IP addresses. Otherwise, just exit. + * + */ + +static int config_hdlc (sdla_t *card) +{ + + if (card->u.c.comm_enabled){ + hdlc_comm_disable(card); + wanpipe_set_state(card, WAN_DISCONNECTED); + } + + if (set_hdlc_config(card)) { + printk(KERN_INFO "%s: CHDLC Configuration Failed!\n", + card->devname); + return -EIO; + } + +#ifdef TE1_56_CARD_SUPPORT + + card->hw_iface.poke_byte(card->hw, card->intr_type_off, 0x00); + card->hw_iface.poke_byte(card->hw, card->intr_perm_off, 0x00); + if (IS_TE1_CARD(card)) { + int err = -EINVAL; + printk(KERN_INFO "%s: Configuring onboard %s CSU/DSU\n", + card->devname, + (IS_T1_CARD(card))?"T1":"E1"); + + if (card->wandev.fe_iface.config){ + err = card->wandev.fe_iface.config(&card->fe); + } + if (err){ + printk(KERN_INFO "%s: Failed %s configuratoin!\n", + card->devname, + (IS_T1_CARD(card))?"T1":"E1"); + return -EINVAL; + } + } + + + if (IS_56K_CARD(card)) { + int err = -EINVAL; + printk(KERN_INFO "%s: Configuring 56K onboard CSU/DSU\n", + card->devname); + + if (card->wandev.fe_iface.config){ + err = card->wandev.fe_iface.config(&card->fe); + } + if (err){ + printk (KERN_INFO "%s: Failed 56K configuration!\n", + card->devname); + return -EINVAL; + } + } + +#endif + + /* Set interrupt mode and mask */ + if (hdlc_set_intr_mode(card, APP_INT_ON_RX_FRAME | + APP_INT_ON_GLOBAL_EXCEP_COND | + APP_INT_ON_TX_FRAME | + APP_INT_ON_CHDLC_EXCEP_COND | APP_INT_ON_TIMER)){ + printk (KERN_INFO "%s: Failed to set interrupt triggers!\n", + card->devname); + return -EIO; + } + + + /* Mask All interrupts */ + card->hw_iface.clear_bit(card->hw, card->intr_perm_off, + (APP_INT_ON_RX_FRAME | APP_INT_ON_TX_FRAME | + APP_INT_ON_TIMER | APP_INT_ON_GLOBAL_EXCEP_COND | + APP_INT_ON_CHDLC_EXCEP_COND)); + + if (hdlc_comm_enable(card) != 0) { + printk(KERN_INFO "%s: Failed to enable fr communications!\n", + card->devname); + card->hw_iface.poke_byte(card->hw, card->intr_perm_off, 0x00); + card->u.c.comm_enabled=0; + hdlc_set_intr_mode(card,0); + return -EIO; + } + + init_hdlc_tx_rx_buff(card); + +#ifdef TE1_56_CARD_SUPPORT + /* Manually poll the 56K CSU/DSU to get the status */ + if (IS_56K_CARD(card)) { + /* 56K Update CSU/DSU alarms */ + card->wandev.fe_iface.read_alarm(&card->fe, 1); + } +#endif + + /* Unmask all interrupts except the Transmit and Timer interrupts */ + card->hw_iface.set_bit(card->hw, card->intr_perm_off, + (APP_INT_ON_RX_FRAME | APP_INT_ON_GLOBAL_EXCEP_COND | + APP_INT_ON_CHDLC_EXCEP_COND)); + card->hw_iface.poke_byte(card->hw, card->intr_type_off, 0x00); + + + printk(KERN_INFO "%s: Enabling data link layer!\n",card->devname); + return 0; +} + + +/* + * ****************************************************************** + * Proc FS function + */ + +#define PROC_CFG_FRM "%-15s| %-12s| %-5u|\n" +#define PROC_STAT_FRM "%-15s| %-12s| %-14s|\n" +static char fr_config_hdr[] = + "Interface name | Device name | DLCI |\n"; +static char fr_status_hdr[] = + "Interface name | Device name | Status |\n"; + +static int fr_get_config_info(void* priv, struct seq_file* m, int* stop_cnt) +{ + fr_private_area_t* chan = priv; + sdla_t* card = NULL; + + if (chan == NULL){ + return m->count; + }else{ + card = chan->card; + + if ((m->from == 0 && m->count == 0) || (m->from && m->from == *stop_cnt)){ + PROC_ADD_LINE(m, + "%s", fr_config_hdr); + } + + PROC_ADD_LINE(m, + PROC_CFG_FRM, chan->if_name, card->devname, chan->dlci); + + } + return m->count; +} + + +static int fr_get_status_info(void* priv, struct seq_file* m, int* stop_cnt) +{ + fr_channel_t* chan = (fr_channel_t*)priv; + sdla_t* card = chan->card; + + if (chan == NULL) + return m->count; + + if ((m->from == 0 && m->count == 0) || (m->from && m->from == *stop_cnt)){ + PROC_ADD_LINE(m, + "%s", fr_status_hdr); + } + + PROC_ADD_LINE(m, + PROC_STAT_FRM, chan->if_name, card->devname, STATE_DECODE(chan->common.state)); + return m->count; +} + + +#define PROC_DEV_FR_S_FRM "%-20s| %-14s|\n" +#define PROC_DEV_FR_D_FRM "%-20s| %-14d|\n" +#define PROC_DEV_SEPARATE "=====================================\n" + + /* DevName, DLCI, DlciState, DlciNewS, GDlciState, DevState */ +#define PROC_DEV_FR_SDDD_TITLE_FRM "%-12s| %-5s | %-6s | %-7s | %-8s | %-13s |\n" +#define PROC_DEV_FR_SDDD_FRM "%-12s| %-5d | %-6d | %-7d | %-8d | %-13s |\n" + +#define PROC_DEV_SEPARATE1 "===================================================================\n" + +static int fr_set_dev_config(struct file *file, + const char *buffer, + unsigned long count, + void *data) +{ + int cnt = 0; + wan_device_t* wandev = (void*)data; + sdla_t* card = NULL; + + if (wandev == NULL) + return cnt; + + card = (sdla_t*)wandev->private; + + printk(KERN_INFO "%s: New device config (%s)\n", + wandev->name, buffer); + /* Parse string */ + + return count; +} + + +#define PROC_IF_FR_S_FRM "%-30s\t%-14s\n" +#define PROC_IF_FR_D_FRM "%-30s\t%-14d\n" +#define PROC_IF_FR_L_FRM "%-30s\t%-14ld\n" +#define PROC_IF_SEPARATE "====================================================\n" + + +static int fr_set_if_info(struct file *file, + const char *buffer, + unsigned long count, + void *data) +{ + netdevice_t* dev = (void*)data; + fr_private_area_t* chan = NULL; + sdla_t* card = NULL; + + if (dev == NULL || dev->priv == NULL) + return count; + chan = (fr_private_area_t*)dev->priv; + if (chan->card == NULL) + return count; + card = chan->card; + + printk(KERN_INFO "%s: New interface config (%s)\n", + chan->if_name, buffer); + /* Parse string */ + + return count; +} + + +static void s508_s514_lock(sdla_t *card, unsigned long *smp_flags) +{ + if (card->type != SDLA_S514){ + + spin_lock_irqsave(&card->wandev.lock, *smp_flags); + }else{ + spin_lock(&card->u.c.if_send_lock); + } + return; +} + +static void s508_s514_unlock(sdla_t *card, unsigned long *smp_flags) +{ + if (card->type != SDLA_S514){ + + spin_unlock_irqrestore (&card->wandev.lock, *smp_flags); + }else{ + spin_unlock(&card->u.c.if_send_lock); + } + return; +} + + +/*============================================================================ + * Convert decimal string to unsigned integer. + * If len != 0 then only 'len' characters of the string are converted. + */ +static unsigned int dec_to_uint (unsigned char* str, int len) +{ + unsigned val; + + if (!len) + len = strlen(str); + + for (val = 0; len && is_digit(*str); ++str, --len) + val = (val * 10) + (*str - (unsigned)'0'); + + return val; +} + + +/* =============== Frame Relay Protocol ============================ */ + + +static int fr_hard_header(sdla_t *card, netdevice_t *dev, u16 type) +{ + fr_private_area_t *chan = dev->priv; + + if (!chan) + return -ENODEV; + +#ifdef CONFIG_PRODUCT_WANPIPE_ANNEXG + if (chan->common.usedby == ANNEXG){ + dlci_to_q922(chan->header, chan->dlci); + chan->hdr_len = 2; + return chan->hdr_len; + } +#endif + + switch(type) { + + case ETH_P_IP: + chan->hdr_len = 4; + chan->header[3]=NLPID_IP; + break; + + case ETH_P_IPV6: + chan->hdr_len = 4; + chan->header[3]=NLPID_IPV6; + break; + + default: + chan->hdr_len = 10; + chan->header[3] = FR_PAD; + chan->header[4] = NLPID_SNAP; + chan->header[5] = FR_PAD; + chan->header[6] = FR_PAD; + chan->header[7] = FR_PAD; + chan->header[8] = type>>8; + chan->header[9] = (u8)type; + } + + dlci_to_q922(chan->header, chan->dlci); + chan->header[2] = FR_UI; + + return chan->hdr_len; +} + + +static __inline__ void dlci_to_status(sdla_t *card, u16 dlci, u8 *status, + u8 state) +{ + status[0] = (dlci>>4) & 0x3F; + status[1] = ((dlci<<3) & 0x78) | 0x80; + status[2] = 0x80; + + if (state & PVC_STATE_NEW) + status[2] |= 0x08; + else if (state & PVC_STATE_ACTIVE) + status[2] |= 0x02; +} + + +static inline void fr_log_dlci_active(fr_private_area_t *chan) +{ + printk(KERN_INFO "%s: %s: DLCI %i: %sactive%s\n", + ((sdla_t*)chan->card)->devname, + chan->if_name, + chan->dlci, + chan->dlci_state & PVC_STATE_ACTIVE ? "" : "in", + chan->dlci_state & PVC_STATE_NEW ? " new" : ""); +} + +static void fr_timer(unsigned long arg) +{ + sdla_t *card = (sdla_t*)arg; + fr_prot_t *fr_prot = FR_PROT_AREA(card); + int i, cnt = 0, reliable; + netdevice_t *dev; + fr_private_area_t *chan; + u32 list; + + +// printk(KERN_INFO "FR TIMER FR:State=0x%X LastErrors=0x%X\n", +// fr_prot->state,fr_prot->last_errors); + + + if (fr_prot->station == WANOPT_NODE){ + reliable = ((jiffies - fr_prot->last_rx_poll) < (fr_prot->cfg.t392*HZ)); + if (!reliable){ + fr_prot->link_stats.T392_timeouts++; + } + }else{ + fr_prot->last_errors <<= 1; /* Shift the list */ + + if (fr_prot->state & LINK_STATE_REQUEST) { + printk(KERN_INFO "%s: Frame Relay: No LMI status reply received\n", + card->devname); + fr_prot->last_errors |= 1; + fr_prot->link_stats.T391_timeouts++; + } + + for (i = 0, list = fr_prot->last_errors; i < fr_prot->cfg.n393; + i++, list >>= 1){ + cnt += (list & 1); /* errors count */ + } + reliable = (cnt < fr_prot->cfg.n392); + } + + if ((fr_prot->state & LINK_STATE_RELIABLE) != (reliable ? LINK_STATE_RELIABLE : 0)){ + struct wan_dev_le *devle; + + WAN_LIST_FOREACH(devle, &card->wandev.dev_head, dev_link){ + dev = WAN_DEVLE2DEV(devle); + if (!dev || !wan_netif_priv(dev)) + continue; + if (!(dev->flags & IFF_UP)) + continue; + chan = wan_netif_priv(dev); + chan->dlci_state &= ~(PVC_STATE_NEW | PVC_STATE_ACTIVE); + chan_set_state(dev,WAN_DISCONNECTED); + } + + fr_prot->state ^= LINK_STATE_RELIABLE; + + if (reliable){ + wanpipe_set_state(card,WAN_CONNECTED); + }else{ + printk(KERN_INFO "%s: Link unreliable !\n", + card->devname); + wanpipe_set_state(card,WAN_DISCONNECTED); + } + + //printk(KERN_INFO "%s: Link %sreliable\n", card->devname, + // reliable ? "" : "un"); + + if (reliable) { + fr_prot->n391cnt = 0; /* Request full status */ + fr_prot->state |= LINK_STATE_CHANGED; + } + } + + if (fr_prot->station == WANOPT_NODE){ + fr_prot->timer.expires = jiffies + fr_prot->cfg.t392*HZ; + }else{ + if (fr_prot->n391cnt) + fr_prot->n391cnt--; + + fr_lmi_send(card, (fr_prot->n391cnt == 0)); + + fr_prot->state |= LINK_STATE_REQUEST; + fr_prot->timer.expires = jiffies + (fr_prot->cfg.t391*HZ); + } + + add_timer(&fr_prot->timer); +} + + + +static void fr_lmi_send(sdla_t *card, int fullrep) +{ + struct sk_buff *skb; + fr_prot_t *fr_prot = FR_PROT_AREA(card); + netdevice_t *dev; + fr_private_area_t *chan; + int len = (fr_prot->cfg.signalling == WANOPT_FR_ANSI) ? LMI_ANSI_LENGTH : LMI_LENGTH; + int stat_len = 3; + u8 *data; + int i = 0,ch; + int dlci_cnt=0; + + if (fr_prot->station == WANOPT_NODE && fullrep) { + dlci_cnt=card->wandev.new_if_cnt; + len += dlci_cnt * (2 + stat_len); + + if (len > card->wandev.mtu) { + printk(KERN_INFO "\n"); + printk(KERN_INFO "%s: Error: Full status report size %i exceeds MTU=%i\n", + card->devname,len,card->wandev.mtu); + printk(KERN_INFO "%s: Error: Too many DLCI's configured or increase MTU\n", + card->devname); + card->wandev.stats.tx_errors++; + return; + } + } + + skb = dev_alloc_skb(len); + if (!skb) { + printk(KERN_INFO "%s: Memory squeeze on fr_lmi_send()\n", + card->devname); + card->wandev.stats.tx_errors++; + return; + } + + memset(skb->data, 0, len); + + skb_reserve(skb, 4); + skb_push(skb, 4); + skb->data[3] = LMI_PROTO; + dlci_to_q922(skb->data, fr_prot->lmi_dlci); + skb->data[2] = FR_UI; + + data = skb->tail; + data[i++] = LMI_CALLREF; + data[i++] = (fr_prot->station == WANOPT_NODE) ? LMI_STATUS : LMI_STATUS_ENQUIRY; + + if (fr_prot->cfg.signalling == WANOPT_FR_ANSI){ + data[i++] = LMI_ANSI_LOCKSHIFT; + } + + data[i++] = MODE_FR_CCITT ? LMI_CCITT_REPTYPE : LMI_REPTYPE; + + data[i++] = LMI_REPT_LEN; + data[i++] = fullrep ? LMI_FULLREP : LMI_INTEGRITY; + + data[i++] = MODE_FR_CCITT ? LMI_CCITT_ALIVE : LMI_ALIVE; + data[i++] = LMI_INTEG_LEN; + data[i++] = fr_prot->txseq = fr_lmi_nextseq(fr_prot->txseq); + data[i++] = fr_prot->rxseq; + + + if (fr_prot->station == WANOPT_NODE && fullrep) { + + for (ch=0;chdlci_to_dev_map[ch]) == NULL) + continue; + + if (--dlci_cnt < 0) + break; + + chan=dev->priv; + if (!chan) + continue; + + //printk(KERN_INFO "Interigating %s DLCI=%i\n",chan->if_name,chan->dlci); + + data[i++] = MODE_FR_CCITT ? LMI_CCITT_PVCSTAT:LMI_PVCSTAT; + data[i++] = stat_len; + + if ((fr_prot->state & LINK_STATE_RELIABLE) && + (dev->flags & IFF_UP) && + !(chan->dlci_state & (PVC_STATE_ACTIVE|PVC_STATE_NEW))) { + + chan->dlci_state |= PVC_STATE_NEW; + fr_log_dlci_active(chan); + + if (!(chan->dlci_state & PVC_STATE_ACTIVE)){ + chan_set_state(dev,WAN_DISCONNECTED); + } + } + + dlci_to_status(card, chan->dlci, + data+i, chan->dlci_state); + i += stat_len; + } + } + + if (fr_prot->station == WANOPT_NODE){ + if (fullrep){ + fr_prot->link_stats.node_tx_FSR++; + }else{ + fr_prot->link_stats.node_tx_LIV++; + } + }else{ + if (fullrep){ + fr_prot->link_stats.cpe_tx_FSE++; + }else{ + fr_prot->link_stats.cpe_tx_LIV++; + } + } + + skb_put(skb, i); + skb->priority = TC_PRIO_CONTROL; + + capture_trace_packet(card,NULL,skb,TRC_OUTGOING_FRM); + + skb_queue_tail(&fr_prot->lmi_queue,skb); + card->hw_iface.set_bit(card->hw, card->intr_perm_off, APP_INT_ON_TX_FRAME); +} + +void init_global_dlci_state(sdla_t *card) +{ + fr_prot_t *fr_prot = FR_PROT_AREA(card); + memset(fr_prot->global_dlci_map,0,sizeof(fr_prot->global_dlci_map)); + return; +} + +void set_global_dlci_state(sdla_t *card, u16 dlci, u8 state) +{ + fr_prot_t *fr_prot = FR_PROT_AREA(card); + if (dlci > HIGHEST_VALID_DLCI){ + return; + } + fr_prot->global_dlci_map[dlci] = state; +} + + +static int fr_lmi_recv(sdla_t* card, struct sk_buff *skb) +{ + struct wan_dev_le *devle; + int stat_len; + int reptype = -1, error; + u8 rxseq, txseq; + fr_prot_t *fr_prot=FR_PROT_AREA(card); + netdevice_t *dev; + fr_private_area_t *chan; + int i; + +// printk(KERN_INFO "\n"); +// printk(KERN_INFO "FR LMI REC: Len=%i Min=%i\n",skb->len, LMI_ANSI_LENGTH); + + if (skb->len < ((fr_prot->cfg.signalling == WANOPT_FR_ANSI) ? LMI_ANSI_LENGTH : LMI_LENGTH)) { + printk(KERN_INFO "%s: Short LMI frame\n", card->devname); + fr_prot->link_stats.rx_dropped++; + return 1; + } + + if (skb->data[5] != ((fr_prot->station != WANOPT_NODE) ? + LMI_STATUS : LMI_STATUS_ENQUIRY)) { + printk(KERN_INFO "%s: LMI msgtype=%x, Not LMI status %s\n", + card->devname, skb->data[2], + (fr_prot->station != WANOPT_NODE) ? "enquiry" : "reply"); + fr_prot->link_stats.rx_bad_format++; + return 1; + } + + i = (fr_prot->cfg.signalling == WANOPT_FR_ANSI) ? 7 : 6; + + if (skb->data[i] != + (MODE_FR_CCITT ? LMI_CCITT_REPTYPE : LMI_REPTYPE)) { + printk(KERN_INFO "%s: Not a report type=%x\n", + card->devname, skb->data[i]); + fr_prot->link_stats.rx_bad_format++; + return 1; + } + i++; + i++; /* Skip length field */ + + reptype = skb->data[i++]; + //printk(KERN_INFO "(Debug) RepType = 0x%x, Inc=%i\n",reptype,i); + + if (skb->data[i] != ((MODE_FR_CCITT) ? LMI_CCITT_ALIVE : LMI_ALIVE)) { + printk(KERN_INFO "%s: Unsupported status element=%x\n", + card->devname, skb->data[i]); + fr_prot->link_stats.rx_bad_format++; + return 1; + } + i++; + + i++; /* Skip length field */ + + fr_prot->rxseq = skb->data[i++]; /* TX sequence from peer */ + rxseq = skb->data[i++]; /* Should confirm our sequence */ + + txseq = fr_prot->txseq; + + //printk(KERN_INFO "TxSeqOrig=%i TxSeqFrame=%i RxSeqFrame=%i Inc=%i\n", + // txseq, fr_prot->rxseq, rxseq,i); + + if (fr_prot->station == WANOPT_NODE) { + switch (reptype){ + + case LMI_INTEGRITY: + fr_prot->link_stats.node_rx_LIV++; + //card->wandev.stats.rx_crc_errors++; + break; + case LMI_FULLREP: + fr_prot->link_stats.node_rx_FSE++; + //card->wandev.stats.rx_frame_errors++; + break; + + default: + printk(KERN_INFO "%s: Unsupported report type=%x\n", + card->devname, reptype); + fr_prot->link_stats.rx_bad_format++; + return 1; + } + }else{ + switch (reptype){ + + case LMI_INTEGRITY: + fr_prot->link_stats.cpe_rx_LIV++; + break; + case LMI_FULLREP: + fr_prot->link_stats.cpe_rx_FSR++; + break; + } + + } + + error = 0; + if (!(fr_prot->state & LINK_STATE_RELIABLE)){ + //printk(KERN_INFO "FR Link State ! Reliable\n"); + error = 1; + } + + if (rxseq == 0 || rxseq != txseq) { + //printk(KERN_INFO "Rxseq =0 or != TxSeq ask for full status again\n"); + fr_prot->n391cnt = 0; /* Ask for full report next time */ + error = 1; + } + + if (fr_prot->station == WANOPT_NODE) { + + if ((fr_prot->state & LINK_STATE_FULLREP_SENT) && !error) { + /* Stop sending full report - the last one has been confirmed by DTE */ + fr_prot->state &= ~LINK_STATE_FULLREP_SENT; + + WAN_LIST_FOREACH(devle, &card->wandev.dev_head, dev_link){ + dev = WAN_DEVLE2DEV(devle); + if (!dev || !wan_netif_priv(dev)) + continue; + chan = wan_netif_priv(dev); + + if (chan->dlci_state & PVC_STATE_NEW) { + chan->dlci_state &= ~PVC_STATE_NEW; + chan->dlci_state |= PVC_STATE_ACTIVE; + fr_log_dlci_active(chan); + + if (card->fe.fe_status == FE_CONNECTED){ + chan_set_state(dev,WAN_CONNECTED); + } + + /* Tell DTE that new PVC is now active */ + fr_prot->state |= LINK_STATE_CHANGED; + } + } + } + + if (fr_prot->state & LINK_STATE_CHANGED) { + reptype = LMI_FULLREP; + fr_prot->state |= LINK_STATE_FULLREP_SENT; + fr_prot->state &= ~LINK_STATE_CHANGED; + } + + fr_lmi_send(card, (reptype == LMI_FULLREP ? 1 : 0)); + return 0; + } + + /* DTE */ + if (reptype != LMI_FULLREP || error){ + //printk(KERN_INFO "RepType=%i != LMI_FULLREP(0) Error=%i\n", + // reptype,error); + return 0; + } + + stat_len = 3; + + //printk(KERN_INFO "JUST BEFORE DEV LIST Cnt=%i Cnt=%i\n",i,(i + 2 + stat_len)); + + WAN_LIST_FOREACH(devle, &card->wandev.dev_head, dev_link){ + dev = WAN_DEVLE2DEV(devle); + if (!dev || !wan_netif_priv(dev)) + continue; + chan = wan_netif_priv(dev); + chan->newstate=0; + } + + //printk(KERN_INFO "Starting to go through dlcis\n"); + init_global_dlci_state(card); + + while (skb->len >= (i + 2 + stat_len)) { + + u16 dlci; + u8 state = 0; + + if (skb->data[i] != ((MODE_FR_CCITT) ? LMI_CCITT_PVCSTAT : LMI_PVCSTAT)) { + printk(KERN_INFO "%s: Invalid PVCSTAT ID: %x\n", + card->devname, skb->data[i]); + fr_prot->link_stats.rx_bad_format++; + return 1; + } + i++; + + if (skb->data[i] != stat_len) { + printk(KERN_INFO "%s: Invalid PVCSTAT length: %x\n", + card->devname, skb->data[i]); + fr_prot->link_stats.rx_bad_format++; + return 1; + } + i++; + + //printk(KERN_INFO "DLCI TO STATUS starting at I=%i\n",i); + + dlci = status_to_dlci((skb->data+i), &state); + + //printk(KERN_INFO "DLCI IS %i State 0x%x\n",dlci,state); + + dev = find_channel(card,dlci); + if (dev){ + chan=dev->priv; + if (!chan){ + fr_prot->link_stats.rx_dropped++; + return 1; + } + chan->newstate = state; + + }else if (state == PVC_STATE_NEW){ + printk(KERN_INFO "%s: New PVC available, DLCI=%u\n", + card->devname, dlci); + } + + set_global_dlci_state(card,dlci,state); + + i += stat_len; + } + + //printk(KERN_INFO "End of dlci report\n"); + + WAN_LIST_FOREACH(devle, &card->wandev.dev_head, dev_link){ + dev = WAN_DEVLE2DEV(devle); + if (!dev || !wan_netif_priv(dev)) + continue; + chan = wan_netif_priv(dev); + if (chan->newstate == PVC_STATE_NEW) + chan->newstate = PVC_STATE_ACTIVE; + + chan->newstate |= (chan->dlci_state & ~(PVC_STATE_NEW|PVC_STATE_ACTIVE)); + if (chan->dlci_state != chan->newstate) { + chan->dlci_state = chan->newstate; + fr_log_dlci_active(chan); + + if ((chan->dlci_state & PVC_STATE_ACTIVE) && + card->fe.fe_status == FE_CONNECTED){ + chan_set_state(dev,WAN_CONNECTED); + } + + if (!(chan->dlci_state & PVC_STATE_ACTIVE)){ + chan_set_state(dev,WAN_DISCONNECTED); + } + }else{ + if (!(chan->dlci_state & PVC_STATE_ACTIVE) && + chan->common.state != WAN_DISCONNECTED){ + chan_set_state(dev,WAN_DISCONNECTED); + } + } + + } + + /* Next full report after N391 polls */ + fr_prot->n391cnt = fr_prot->cfg.n391; + return 0; +} + + + +static void fr_netif(sdla_t *card, struct sk_buff *skb) +{ + fr_hdr *fh = (fr_hdr*)skb->data; + u8 *data = skb->data; + netdevice_t *dev; + u16 dlci; + fr_private_area_t *chan=NULL; + fr_prot_t *fr_prot = FR_PROT_AREA(card); + + if (skb->len<4 || fh->ea1){ + fr_prot->link_stats.rx_bad_format++; + goto fr_rx_error; + } + + dlci = q922_to_dlci(skb->data); + + if (dlci == LMI_ANSI_DLCI || dlci == LMI_LMI_DLCI) { + + capture_trace_packet(card,NULL,skb,TRC_INCOMING_FRM); + + if (data[2] != FR_UI){ + goto fr_rx_error; + } + + if (data[3] == LMI_PROTO) { + + if (fr_lmi_recv(card, skb)) + goto fr_rx_error; + else { + /* No request pending */ + fr_prot->state &= ~LINK_STATE_REQUEST; + fr_prot->last_rx_poll = jiffies; + return; + } + } + + printk(KERN_INFO "%s: Received non-LMI frame with LMI DLCI\n",card->devname); + fr_prot->link_stats.rx_bad_format++; + goto fr_rx_error; + } + + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + if (!dev){ + printk(KERN_INFO "%s: FR Protocol no dev!\n",card->devname); + return; + } + + dev = find_channel(card, dlci); + if (!dev) { + fr_prot->link_stats.rx_bad_dlci++; + goto fr_rx_error; + } + + if ((dev->flags & IFF_UP) == 0) { + printk(KERN_INFO "%s: Interface for receive DLCI %d is down\n", + card->devname, dlci); + fr_prot->link_stats.rx_bad_dlci++; + goto fr_rx_error; + } + + chan=(fr_private_area_t*)dev->priv; + if (!chan){ + printk(KERN_INFO "%s: PVC for received frame's DLCI %d is down\n", + card->devname, dlci); + fr_prot->link_stats.rx_bad_dlci++; + goto fr_rx_error; + } + + if ((chan->dlci_state & PVC_STATE_FECN) != (fh->fecn ? PVC_STATE_FECN : 0)) { + chan->rx_FECN++; + printk(KERN_INFO "%s: FECN O%s\n", dev->name, + fh->fecn ? "N" : "FF"); + chan->dlci_state ^= PVC_STATE_FECN; + } + + if ((chan->dlci_state & PVC_STATE_BECN) != (fh->becn ? PVC_STATE_BECN : 0)) { + chan->rx_BECN++; + printk(KERN_INFO "%s: BECN O%s\n", dev->name, + fh->becn ? "N" : "FF"); + chan->dlci_state ^= PVC_STATE_BECN; + } + + if (chan->dlci_state & PVC_STATE_BECN){ + chan->stats.rx_compressed++; + } + + if( capture_trace_packet(card,chan,skb,TRC_INCOMING_FRM) < 0){ + chan->stats.rx_fifo_errors++; + } + +#ifdef CONFIG_PRODUCT_WANPIPE_ANNEXG + if (chan->common.usedby == ANNEXG){ + if (chan->annexg_dev){ + if (IS_FUNC_CALL(lapb_protocol,lapb_rx)){ + struct sk_buff *new_skb; + + skb_pull(skb, 2); + new_skb=dev_alloc_skb(skb->len); + if (!new_skb){ + chan->stats.rx_errors++; + card->wandev.stats.rx_dropped++; + fr_prot->link_stats.rx_dropped++; + printk(KERN_INFO "%s: Annexg: Failed to allocate memory\n", + card->devname); + return; + } + + new_skb->protocol = htons(ETH_P_X25); + new_skb->dev = chan->annexg_dev; + + memcpy(skb_put(new_skb,skb->len),skb->data,skb->len); + +#if 0 + if (new_skb->len <= 5 && !(new_skb->data[1]&0x01)){ + int x; + + if (new_skb->len == 5 && (new_skb->data[4]&0x01)) + goto skip_error; + + printk(KERN_INFO "%s: ERROR: Rx bad annexg frame len=%i\n", + card->devname, new_skb->len); + + printk(KERN_INFO "Bad Packet : "); + for (x=0;xlen;x++){ + printk("%X ",new_skb->data[x]); + } + printk("\n"); + printk(KERN_INFO "\n"); + chan->stats.rx_dropped++; + card->wandev.stats.rx_dropped++; + dev_kfree_skb_any(new_skb); + return; +skip_error: + } +#endif + + chan->stats.rx_packets++; + chan->stats.rx_bytes += new_skb->len; + card->wandev.stats.rx_packets++; + card->wandev.stats.rx_bytes += new_skb->len; + + lapb_protocol.lapb_rx(chan->annexg_dev,new_skb); + }else{ + chan->stats.rx_errors++; + card->wandev.stats.rx_dropped++; + fr_prot->link_stats.rx_dropped++; + } + }else{ + chan->stats.rx_errors++; + fr_prot->link_stats.rx_dropped++; + card->wandev.stats.rx_dropped++; + } + return; + } +#endif + + if (data[2] != FR_UI){ + fr_prot->link_stats.rx_bad_format++; + chan->stats.rx_errors++; + goto fr_rx_error; + } + + if (data[3] == NLPID_IP) { + struct sk_buff *new_skb; + skb_pull(skb, 4); /* Remove 4-byte header (hdr, UI, NLPID) */ + skb->protocol = htons(ETH_P_IP); + skb->dev = dev; + + new_skb=skb_clone(skb,GFP_ATOMIC); + if (!new_skb){ + chan->stats.rx_errors++; + fr_prot->link_stats.rx_dropped++; + return; + } + + ++card->wandev.stats.rx_packets; + card->wandev.stats.rx_bytes += skb->len; + + chan->stats.rx_packets++; /* PVC traffic */ + chan->stats.rx_bytes += skb->len; + + netif_rx(new_skb); + return; + } + + if (data[3] == NLPID_IPV6) { + + struct sk_buff *new_skb; + skb_pull(skb, 4); /* Remove 4-byte header (hdr, UI, NLPID) */ + skb->protocol = htons(ETH_P_IPV6); + skb->dev = dev; + + new_skb=skb_clone(skb,GFP_ATOMIC); + if (!new_skb){ + chan->stats.rx_errors++; + fr_prot->link_stats.rx_dropped++; + return; + } + + ++card->wandev.stats.rx_packets; + card->wandev.stats.rx_bytes += skb->len; + + chan->stats.rx_packets++; /* PVC traffic */ + chan->stats.rx_bytes += skb->len; + + netif_rx(new_skb); + return; + } + + if (data[3] == FR_PAD && data[4] == NLPID_SNAP && data[5] == FR_PAD && + data[6] == FR_PAD && data[7] == FR_PAD && + ((data[8]<<8) | data[9]) == ETH_P_ARP) { + + struct sk_buff *new_skb; + + skb_pull(skb, 10); + skb->protocol = htons(ETH_P_ARP); + skb->dev = dev; + + new_skb=skb_clone(skb,GFP_ATOMIC); + if (!new_skb){ + chan->stats.rx_errors++; + fr_prot->link_stats.rx_dropped++; + return; + } + + ++card->wandev.stats.rx_packets; + card->wandev.stats.rx_bytes += skb->len; + + chan->stats.rx_packets++; /* PVC traffic */ + chan->stats.rx_bytes += skb->len; + + netif_rx(new_skb); + return; + } + + printk(KERN_INFO "%s: Unusupported protocol %x\n", + card->devname, data[3]); + + fr_prot->link_stats.rx_bad_format++; + card->wandev.stats.rx_dropped++; + chan->stats.rx_dropped++; + return; + +fr_rx_error: + card->wandev.stats.rx_dropped++; + return; +} + +/*============================================================================ + * Find network device by its channel number. + * + * We need this critical flag because we change + * the dlci_to_dev_map outside the interrupt. + * + * NOTE: del_if() functions updates this array, it uses + * the spin locks to avoid corruption. + */ +static netdevice_t* find_channel (sdla_t* card, unsigned dlci) +{ + fr_prot_t *fr_prot=FR_PROT_AREA(card); + + if(dlci > HIGHEST_VALID_DLCI) + return NULL; + + return(fr_prot->dlci_to_dev_map[dlci]); +} + + +static void fr_bh (unsigned long card_data) +{ +#define card ((sdla_t*)card_data) + fr_prot_t *fr_prot = FR_PROT_AREA(card); + struct sk_buff *skb; + unsigned long timeout=jiffies; + + if (!skb_queue_len(&fr_prot->rx_used)){ + clear_bit(0, &fr_prot->tq_working); + return; + } + + while ((skb=skb_dequeue(&fr_prot->rx_used)) != NULL){ + + fr_netif(card,skb); + + skb->data = skb->head+16; + skb_trim(skb,0); + skb_queue_tail(&fr_prot->rx_free,skb); + + if ((jiffies-timeout) >= 4){ + printk(KERN_INFO "%s: FR BH Kicking out, bh timeout 40ms\n", + card->devname); + break; + } + } + + clear_bit(0, &fr_prot->tq_working); + return; +#undef card +} + + +static int capture_trace_packet (sdla_t *card,fr_private_area_t*chan,struct sk_buff *skb,char direction) +{ + fr_prot_t *fr_prot = FR_PROT_AREA(card); + + if (!chan){ + goto trace_protocol; + } + + + if (test_bit(0,&chan->tracing_enabled)){ + + if ((jiffies-chan->trace_timeout) > MAX_TRACE_TIMEOUT){ + printk(KERN_INFO "%s: %s: Disabling DLCI=%i trace, timeout!\n", + card->devname,chan->if_name,chan->dlci); + clear_bit(0,&chan->tracing_enabled); + return 0; + } + + + if (skb_queue_len(&chan->trace_queue) < chan->max_trace_queue){ + + struct sk_buff *new_skb; + + new_skb=dev_alloc_skb(skb->len+sizeof(fr_trc_el_t)+chan->hdr_len); + if (new_skb){ + fr_trc_el_t *trc_el = (fr_trc_el_t*)skb_put(new_skb,sizeof(fr_trc_el_t)); + trc_el->attr = direction; + trc_el->tmstamp = (unsigned short)(jiffies%0xFFFF); + trc_el->length = skb->len; + + if (direction == TRC_OUTGOING_FRM){ + trc_el->length += chan->hdr_len; + memcpy(skb_put(new_skb,chan->hdr_len),chan->header,chan->hdr_len); + } + + memcpy(skb_put(new_skb,skb->len),skb->data,skb->len); + skb_queue_tail(&chan->trace_queue,new_skb); + }else{ + //ALEX + //printk(KERN_INFO "%s: %s: %i: Failed allocate memory for new packets in trace queue!\n", + // card->devname, chan->if_name, chan->dlci); + return -ENOMEM; + } + }else{ + //ALEX + //printk(KERN_INFO "%s: %s: %i: Too many packets in trace queue (%i)!\n", + // card->devname, chan->if_name, chan->dlci, + // skb_queue_len(&chan->trace_queue)); + return -ENOBUFS; + } + } + + return 0; + +trace_protocol: + + if (test_bit(0,&fr_prot->tracing_enabled)){ + + if ((jiffies-fr_prot->trace_timeout) > MAX_TRACE_TIMEOUT){ + printk(KERN_INFO "%s: Disabling LMI trace, timeout!\n", + card->devname); + clear_bit(0,&fr_prot->tracing_enabled); + return 0; + } + + if (skb_queue_len(&fr_prot->trace_queue) < fr_prot->max_trace_queue){ + + struct sk_buff *new_skb; + + new_skb=dev_alloc_skb(skb->len+sizeof(fr_trc_el_t)); + if (new_skb){ + fr_trc_el_t *trc_el = (fr_trc_el_t*)skb_put(new_skb,sizeof(fr_trc_el_t)); + trc_el->attr = direction; + trc_el->tmstamp = (unsigned short)(jiffies%0xFFFF); + trc_el->length = skb->len; + memcpy(skb_put(new_skb,skb->len),skb->data,skb->len); + skb_queue_tail(&fr_prot->trace_queue,new_skb); + }else{ + //ALEX + printk(KERN_INFO "%s: Failed to allocate memory for new packets in trace queue!\n", + card->devname); + return -ENOMEM; + } + }else{ + //ALEX + printk(KERN_INFO "%s: Too many packets in trace queue (%i)!\n", + card->devname, skb_queue_len(&fr_prot->trace_queue)); + return -ENOBUFS; + } + } + return 0; +} + + +/* SNMP + ****************************************************************************** + * fr_snmp_data() + * + * Description: Save snmp request and parameters in private structure, enable + * TIMER interrupt, put current process in sleep. + * Arguments: + * Returns: + ****************************************************************************** + */ +#define FRDLCMIIFINDEX 3 +#define FRDLCMISTATE 4 +#define FRDLCMIADDRESS 5 +#define FRDLCMIADDRESSLEN 6 +#define FRDLCMIPOLLINGINTERVAL 7 +#define FRDLCMIFULLENQUIRYINTERVAL 8 +#define FRDLCMIERRORTHRESHOLD 9 +#define FRDLCMIMONITOREDEVENTS 10 +#define FRDLCMIMAXSUPPORTEDVCS 11 +#define FRDLCMIMULTICAST 12 +#define FRDLCMISTATUS 13 +#define FRDLCMIROWSTATUS 14 +#define FRCIRCUITIFINDEX 17 +#define FRCIRCUITDLCI 18 +#define FRCIRCUITSTATE 19 +#define FRCIRCUITRECEIVEDFECNS 20 +#define FRCIRCUITRECEIVEDBECNS 21 +#define FRCIRCUITSENTFRAMES 22 +#define FRCIRCUITSENTOCTETS 23 +#define FRCIRCUITRECEIVEDFRAMES 24 +#define FRCIRCUITRECEIVEDOCTETS 25 +#define FRCIRCUITCREATIONTIME 26 +#define FRCIRCUITLASTTIMECHANGE 27 +#define FRCIRCUITCOMMITTEDBURST 28 +#define FRCIRCUITEXCESSBURST 29 +#define FRCIRCUITTHROUGHPUT 30 +#define FRCIRCUITMULTICAST 31 +#define FRCIRCUITTYPE 32 +#define FRCIRCUITDISCARDS 33 +#define FRCIRCUITRECEIVEDDES 34 +#define FRCIRCUITSENTDES 35 +#define FRCIRCUITLOGICALIFINDEX 36 +#define FRCIRCUITROWSTATUS 37 +#define FRERRIFINDEX 40 +#define FRERRTYPE 41 +#define FRERRDATA 42 +#define FRERRTIME 43 +#define FRERRFAULTS 44 +#define FRERRFAULTTIME 45 +#define FRTRAPSTATE 46 +#define FRTRAPMAXRATE 47 + +static int fr_snmp_data(sdla_t* card, netdevice_t *dev, void* data) +{ + fr_channel_t* chan = NULL; + wanpipe_snmp_t* snmp = NULL; + struct timeval tv; + fr_prot_t *fr_prot; + + if (dev == NULL || dev->priv == NULL) + return -EFAULT; + chan = (fr_channel_t*)dev->priv; + fr_prot=FR_PROT_AREA(card); + /* Update device statistics */ + if (card->wandev.update) { + int rslt = 0; + fr_prot->update_dlci = chan; + rslt = card->wandev.update(&card->wandev); + if(rslt) { + return (rslt) ? (-EBUSY) : (-EINVAL); + } + } + + snmp = (wanpipe_snmp_t*)data; + + switch(snmp->snmp_magic){ + /***** Data Link Connection Management Interface ****/ + case FRDLCMIIFINDEX: + break; + + case FRDLCMISTATE: + snmp->snmp_val = + (card->wandev.signalling == WANOPT_FR_ANSI) ? SNMP_FR_ANSIT1617D : + (card->wandev.signalling == WANOPT_FR_Q933) ? SNMP_FR_ITUT933A : + (card->wandev.signalling == WANOPT_FR_LMI) ? SNMP_FR_LMIREV: + SNMP_FR_NOLMICONF; + break; + + case FRDLCMIADDRESS: + snmp->snmp_val = SNMP_FR_Q922; + break; + + case FRDLCMIADDRESSLEN: + snmp->snmp_val = SNMP_FR_4BYTE_ADDR; + break; + + case FRDLCMIPOLLINGINTERVAL: + snmp->snmp_val = fr_prot->cfg.t391; + break; + + case FRDLCMIFULLENQUIRYINTERVAL: + snmp->snmp_val = fr_prot->cfg.n391; + break; + + case FRDLCMIERRORTHRESHOLD: + snmp->snmp_val = fr_prot->cfg.n392; + break; + + case FRDLCMIMONITOREDEVENTS: + snmp->snmp_val = fr_prot->cfg.n393; + break; + + case FRDLCMIMAXSUPPORTEDVCS: + snmp->snmp_val = HIGHEST_VALID_DLCI; + break; + + case FRDLCMIMULTICAST: + snmp->snmp_val = SNMP_FR_NONBROADCAST; + break; + + case FRDLCMISTATUS: /* FIXME */ + snmp->snmp_val = SNMP_FR_RUNNING; + break; + + case FRDLCMIROWSTATUS: /* FIXME */ + snmp->snmp_val = 0; + break; + + /****************** Circuit Table *******************/ + case FRCIRCUITIFINDEX: + break; + + case FRCIRCUITDLCI: + snmp->snmp_val = chan->dlci; + break; + + case FRCIRCUITSTATE: + snmp->snmp_val = (chan->common.state == WAN_CONNECTED) ? SNMP_FR_ACTIVE : SNMP_FR_INACTIVE; + break; + + case FRCIRCUITRECEIVEDFECNS: + snmp->snmp_val = chan->rx_FECN; + break; + + case FRCIRCUITRECEIVEDBECNS: + snmp->snmp_val = chan->rx_BECN; + break; + + case FRCIRCUITSENTFRAMES: + snmp->snmp_val = chan->stats.tx_packets; + break; + + case FRCIRCUITSENTOCTETS: + snmp->snmp_val = chan->stats.tx_bytes; + break; + + case FRCIRCUITRECEIVEDFRAMES: + snmp->snmp_val = chan->stats.rx_packets; + break; + + case FRCIRCUITRECEIVEDOCTETS: + snmp->snmp_val = chan->stats.rx_bytes; + break; + + case FRCIRCUITCREATIONTIME: + do_gettimeofday( &tv ); + snmp->snmp_val = tv.tv_sec - card->u.c.router_start_time; + break; + + case FRCIRCUITLASTTIMECHANGE: + do_gettimeofday( &tv ); + snmp->snmp_val = tv.tv_sec - chan->router_last_change; + break; + + case FRCIRCUITCOMMITTEDBURST: + snmp->snmp_val = (unsigned long)chan->bc; + break; + + case FRCIRCUITEXCESSBURST: + snmp->snmp_val = (unsigned long)chan->be; + break; + + case FRCIRCUITTHROUGHPUT: /* FIXME */ + snmp->snmp_val = (unsigned long)0; + break; + + case FRCIRCUITMULTICAST: + snmp->snmp_val = (chan->mc) ? SNMP_FR_ONEWAY : SNMP_FR_UNICAST; + break; + + case FRCIRCUITTYPE: + snmp->snmp_val = chan->dlci_type; + break; + + case FRCIRCUITDISCARDS: + snmp->snmp_val = chan->stats.rx_errors; + break; + + case FRCIRCUITRECEIVEDDES: + snmp->snmp_val = chan->rx_DE_set; + break; + + case FRCIRCUITSENTDES: + snmp->snmp_val = chan->tx_DE_set; + break; + + case FRCIRCUITLOGICALIFINDEX: /* FIXME */ + snmp->snmp_val = 0; + break; + + case FRCIRCUITROWSTATUS: /* FIXME */ + snmp->snmp_val = 0; + break; + + /****************** Errort Table *******************/ + case FRERRIFINDEX: + break; + + case FRERRTYPE: /* FIXME */ + snmp->snmp_val = chan->err_type; + break; + + case FRERRDATA: /* FIXME */ + strcpy((void*)snmp->snmp_data, chan->err_data); + break; + + case FRERRTIME: /* FIXME */ + snmp->snmp_val = chan->err_time; + break; + + case FRERRFAULTS: /* FIXME */ + snmp->snmp_val = chan->err_faults; + break; + + case FRERRFAULTTIME: /* FIXME */ + snmp->snmp_val = (unsigned long)0; + break; + + /************ Frame Relay Trap Control **************/ + case FRTRAPSTATE: + snmp->snmp_val = chan->trap_state; + break; + + case FRTRAPMAXRATE: + snmp->snmp_val = chan->trap_max_rate; + break; + + default: + return -EAFNOSUPPORT; + } + + return 0; + +} + +#ifdef CONFIG_PRODUCT_WANPIPE_ANNEXG + +static int bind_annexg(netdevice_t *dev, netdevice_t *annexg_dev) +{ + unsigned long smp_flags=0; + fr_channel_t* chan = dev->priv; + sdla_t *card = chan->card; + if (!chan) + return -EINVAL; + + if (chan->common.usedby != ANNEXG) + return -EPROTONOSUPPORT; + + if (chan->annexg_dev) + return -EBUSY; + + spin_lock_irqsave(&card->wandev.lock,smp_flags); + chan->annexg_dev = annexg_dev; + spin_unlock_irqrestore(&card->wandev.lock,smp_flags); + return 0; +} + +static netdevice_t * un_bind_annexg(wan_device_t *wandev, netdevice_t *annexg_dev) +{ + struct wan_dev_le *devle; + netdevice_t *dev; + unsigned long smp_flags=0; + sdla_t *card = wandev->private; + + WAN_LIST_FOREACH(devle, &card->wandev.dev_head, dev_link){ + fr_channel_t *chan; + + dev = WAN_DEVLE2DEV(devle); + if (!dev || !wan_netif_priv(dev)) + continue; + chan = wan_netif_priv(dev); + + if (!chan->annexg_dev || chan->common.usedby != ANNEXG) + continue; + + if (chan->annexg_dev == annexg_dev){ + spin_lock_irqsave(&card->wandev.lock,smp_flags); + chan->annexg_dev = NULL; + spin_unlock_irqrestore(&card->wandev.lock,smp_flags); + return dev; + } + } + return NULL; +} + +static void get_active_inactive(wan_device_t *wandev, netdevice_t *dev, + void *wp_stats_ptr) +{ + fr_channel_t* chan = dev->priv; + wp_stack_stats_t *wp_stats = (wp_stack_stats_t *)wp_stats_ptr; + + if (chan->common.usedby == ANNEXG && chan->annexg_dev){ + if (IS_FUNC_CALL(lapb_protocol,lapb_get_active_inactive)){ + lapb_protocol.lapb_get_active_inactive(chan->annexg_dev,wp_stats); + } + } + + if (chan->common.state == WAN_CONNECTED){ + wp_stats->fr_active++; + }else{ + wp_stats->fr_inactive++; + } +} + + +static int +get_map(wan_device_t *wandev, netdevice_t *dev, struct seq_file* m, int *stop_cnt) +{ + fr_channel_t* chan = dev->priv; + + if (!(dev->flags&IFF_UP)){ + return m->count; + } + + if (chan->common.usedby == ANNEXG && chan->annexg_dev){ + if (IS_FUNC_CALL(lapb_protocol,lapb_get_map)){ + return lapb_protocol.lapb_get_map(chan->annexg_dev, + m); + } + } + + PROC_ADD_LINE(m, + "%15s:%s:%c:%s:%c\n", + chan->label, + wandev->name,(wandev->state == WAN_CONNECTED) ? '*' : ' ', + dev->name,(chan->common.state == WAN_CONNECTED) ? '*' : ' '); + + return m->count; +} + + +#endif + + + + +#ifdef _DBG_ANNEXG_ + +#undef DBG_LAPB +#define DBG_X25 +static int g_ps_cnt=0; +static unsigned int g_skb_ptr=0; +void check_x25_pr_ps_cnt(sdla_t *card,struct sk_buff *skb) +{ + int ps_cnt; + int lcn; + +#ifdef DBG_LAPB + if (skb->len >= 2 && !test_bit(0,&skb->data[1])){ + + ps_cnt = (skb->data[1]&0x0F)>>1; + + if (ps_cnt == g_ps_cnt){ + printk(KERN_INFO "%s: Sending Len=%i Ps=%i Old=%i : New ptr=%u Prev=%u\n", + card->devname,skb->len,ps_cnt,g_ps_cnt, + (u32)skb,g_skb_ptr); + } + g_ps_cnt=ps_cnt; + g_skb_ptr=(u32)skb; + } +#endif + +#ifdef DBG_X25 + if (skb->len >= 5 && !test_bit(0,&skb->data[1])){ + if (!test_bit(0,&skb->data[4])){ + + lcn=((skb->data[2]&0x0F)<<8) | skb->data[3]; + if (lcn!=2) + return; + + + ps_cnt = (skb->data[4]&0x0F)>>1; + + if (ps_cnt == g_ps_cnt){ + printk(KERN_INFO "%s: Sending Lcn=%i Len=%i Ps=%i Old=%i : New ptr=%u Prev=%u\n", + card->devname,lcn,skb->len,ps_cnt,g_ps_cnt, + (u32)skb,g_skb_ptr); + } + + g_ps_cnt=ps_cnt; + g_skb_ptr=(u32)skb; + } + } +#endif + return; +} +#endif + + +/****** End ****************************************************************/ diff -Nur linux.org/drivers/net/wan/sdla_pos.c linux-2.6.17/drivers/net/wan/sdla_pos.c --- linux.org/drivers/net/wan/sdla_pos.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/drivers/net/wan/sdla_pos.c 2006-08-30 10:07:16.000000000 +0000 @@ -0,0 +1,897 @@ +/***************************************************************************** +* sdla_temp.c WANPIPE(tm) Multiprotocol WAN Link Driver. +* +* Template Driver +* +* Authors: Nenad Corbic +* +* Copyright: (c) 1995-2003 Sangoma Technologies Inc. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version +* 2 of the License, or (at your option) any later version. +* ============================================================================ +* Jan 07, 2002 Nenad Corbic Initial version. +*****************************************************************************/ + +#include +#include +#include +#include +#include +#include /* Socket Driver common area */ +#include + + +/****** Defines & Macros ****************************************************/ + +/* Private critical flags */ +enum { + POLL_CRIT = PRIV_CRIT, + TX_INTR, + TASK_POLL +}; + +#define MAX_IP_ERRORS 10 + +#define PORT(x) (x == 0 ? "PRIMARY" : "SECONDARY" ) +#define MAX_RX_BUF 50 +#define POLL_PERIOD (HZ/100) + +/******Data Structures*****************************************************/ + +/* This structure is placed in the private data area of the device structure. + * The card structure used to occupy the private area but now the following + * structure will incorporate the card structure along with Protocol specific data + */ + +typedef struct private_area +{ + wanpipe_common_t common; + sdla_t *card; + int TracingEnabled; /* For enabling Tracing */ + unsigned long curr_trace_addr; /* Used for Tracing */ + unsigned long start_trace_addr; + unsigned long end_trace_addr; + unsigned long base_addr_trace_buffer; + unsigned long end_addr_trace_buffer; + unsigned short number_trace_elements; + unsigned available_buffer_space; + unsigned long router_start_time; + unsigned char route_status; + unsigned char route_removed; + unsigned long tick_counter; /* For 5s timeout counter */ + unsigned long router_up_time; + u8 config_frmw; + u8 config_frmw_timeout; + unsigned char mc; /* Mulitcast support on/off */ + unsigned char udp_pkt_src; /* udp packet processing */ + unsigned short timer_int_enabled; + + bh_data_t *bh_head; /* Circular buffer for bh */ + unsigned long tq_working; + volatile int bh_write; + volatile int bh_read; + atomic_t bh_buff_used; + + unsigned char interface_down; + + /* Polling task queue. Each interface + * has its own task queue, which is used + * to defer events from the interrupt */ + struct timer_list poll_timer; + + u8 gateway; + u8 true_if_encoding; + + //FIXME: add driver stats as per frame relay! + + /* Entry in proc fs per each interface */ + struct proc_dir_entry *dent; + + unsigned char udp_pkt_data[sizeof(wan_udp_pkt_t)+10]; + atomic_t udp_pkt_len; + + char if_name[WAN_IFNAME_SZ+1]; + struct net_device_stats if_stats; + +}private_area_t; + +/* Route Status options */ +#define NO_ROUTE 0x00 +#define ADD_ROUTE 0x01 +#define ROUTE_ADDED 0x02 +#define REMOVE_ROUTE 0x03 + + +/* variable for keeping track of enabling/disabling FT1 monitor status */ +extern void disable_irq(unsigned int); +extern void enable_irq(unsigned int); + +/**SECTOIN************************************************** + * + * Function Prototypes + * + ***********************************************************/ +/* WAN link driver entry points. These are called by the WAN router module. */ +static int update (wan_device_t* wandev); +static int new_if (wan_device_t* wandev, struct net_device* dev, wanif_conf_t* conf); +static int del_if(wan_device_t *wandev, struct net_device *dev); + +/* Network device interface */ +static int if_init (struct net_device* dev); +static int if_open (struct net_device* dev); +static int if_close (struct net_device* dev); +static int if_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); + + +static struct net_device_stats* if_stats (struct net_device* dev); + +static int if_send (struct sk_buff* skb, struct net_device* dev); + +/* Firmware interface functions */ +static int frmw_error (sdla_t *card, int err, wan_mbox_t *mb); +static int disable_comm_shutdown (sdla_t *card); + +/* Miscellaneous Functions */ +static void disable_comm (sdla_t *card); + + +/**SECTION********************************************************* + * + * Public Functions + * + ******************************************************************/ + + +/*============================================================================ + * wppos_init - Cisco HDLC protocol initialization routine. + * + * @card: Wanpipe card pointer + * @conf: User hardware/firmware/general protocol configuration + * pointer. + * + * This routine is called by the main WANPIPE module + * during setup: ROUTER_SETUP ioctl(). + * + * At this point adapter is completely initialized + * and firmware is running. + * o read firmware version (to make sure it's alive) + * o configure adapter + * o initialize protocol-specific fields of the adapter data space. + * + * Return: 0 o.k. + * < 0 failure. + */ + +int wp_pos_init (sdla_t* card, wandev_conf_t* conf) +{ + int err; + volatile wan_mbox_t* mb; + + /* Verify configuration ID */ + + if (conf->config_id != WANCONFIG_POS) { + DEBUG_EVENT( "%s: invalid configuration ID %u!\n", + card->devname, conf->config_id); + return -EINVAL; + } + + /* Initialize protocol-specific fields */ + /* Initialize the card mailbox and obtain the mailbox pointer */ + /* Set a pointer to the actual mailbox in the allocated virtual + * memory area */ + /* Alex Apr 8 2004 Sangom ISA card */ + card->mbox_off = PRI_BASE_ADDR_MB_STRUCT; + + mb = &card->wan_mbox; + /* Obtain hardware configuration parameters */ + card->wandev.clocking = conf->clocking; + card->wandev.ignore_front_end_status = conf->ignore_front_end_status; + card->wandev.ttl = conf->ttl; + card->wandev.interface = conf->interface; + card->wandev.comm_port = conf->comm_port; + card->wandev.udp_port = conf->udp_port; + card->wandev.new_if_cnt = 0; + wan_atomic_set(&card->wandev.if_cnt,0); + + err = (card->hw_iface.check_mismatch) ? + card->hw_iface.check_mismatch(card->hw,conf->fe_cfg.media) : -EINVAL; + if (err){ + return err; + } + + card->fe.fe_status = FE_CONNECTED; + card->wandev.mtu = conf->mtu; + + if (card->wandev.ignore_front_end_status == WANOPT_NO){ + DEBUG_EVENT( + "%s: Enabling front end link monitor\n", + card->devname); + }else{ + DEBUG_EVENT( + "%s: Disabling front end link monitor\n", + card->devname); + } + + + /* Read firmware version. Note that when adapter initializes, it + * clears the mailbox, so it may appear that the first command was + * executed successfully when in fact it was merely erased. To work + * around this, we execute the first command twice. + */ + + DEBUG_EVENT( "%s: Running POS firmware\n",card->devname); + + card->isr = NULL; + card->wandev.update = &update; + card->wandev.new_if = &new_if; + card->wandev.del_if = &del_if; + card->disable_comm = &disable_comm; + + /* Set protocol link state to disconnected, + * After seting the state to DISCONNECTED this + * function must return 0 i.e. success */ + card->u.pos.state = WAN_DISCONNECTED; + card->wandev.state = WAN_DISCONNECTED; + + DEBUG_EVENT( "%s: Pos Firmware Ready!\n",card->devname); + return 0; +} + + + +/**SECTION************************************************************** + * + * WANPIPE Device Driver Entry Points + * + * *********************************************************************/ + + +/*============================================================================ + * update - Update wanpipe device status & statistics + * + * @wandev: Wanpipe device pointer + * + * This procedure is called when updating the PROC file system. + * It returns various communications statistics. + * + * cat /proc/net/wanrouter/wanpipe# (where #=1,2,3...) + * + * These statistics are accumulated from 3 + * different locations: + * 1) The 'if_stats' recorded for the device. + * 2) Communication error statistics on the adapter. + * 3) Operational statistics on the adapter. + * + * The board level statistics are read during a timer interrupt. + * Note that we read the error and operational statistics + * during consecitive timer ticks so as to minimize the time + * that we are inside the interrupt handler. + * + */ +static int update (wan_device_t* wandev) +{ + sdla_t* card = wandev->private; + struct net_device* dev; + volatile private_area_t* priv_area; + + DEBUG_EVENT("%s: %d\n",__FUNCTION__, __LINE__); + + /* sanity checks */ + if((wandev == NULL) || (wandev->private == NULL)) + return -EFAULT; + + if(wandev->state == WAN_UNCONFIGURED) + return -ENODEV; + + if(test_bit(PERI_CRIT, (void*)&card->wandev.critical)) + return -EAGAIN; + + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + if(dev == NULL) + return -ENODEV; + + if((priv_area=dev->priv) == NULL) + return -ENODEV; + + + if(card->update_comms_stats){ + return -EAGAIN; + } + + /* FIXME: DO THE STATS HERE */ + + return -ENODEV; +} + + +/*============================================================================ + * new_if - Create new logical channel. + * + * &wandev: Wanpipe device pointer + * &dev: Network device pointer + * &conf: User configuration options pointer + * + * This routine is called by the ROUTER_IFNEW ioctl, + * in wanmain.c. The ioctl passes us the user configuration + * options which we use to configure the driver and + * firmware. + * + * This functions main purpose is to allocate the + * private structure for protocol and bind it + * to dev->priv pointer. + * + * Also the dev->init pointer should also be initialized + * to the if_init() function. + * + * Any allocation necessary for the private strucutre + * should be done here, as well as proc/ file initializetion + * for the network interface. + * + * o parse media- and hardware-specific configuration + * o make sure that a new channel can be created + * o allocate resources, if necessary + * o prepare network device structure for registaration. + * o add network interface to the /proc/net/wanrouter + * + * The opposite of this function is del_if() + * + * Return: 0 o.k. + * < 0 failure (channel will not be created) + */ +static int new_if (wan_device_t* wandev, struct net_device* dev, wanif_conf_t* conf) +{ + sdla_t* card = wandev->private; + private_area_t* priv_area; + + DEBUG_EVENT("%s: %d\n",__FUNCTION__, __LINE__); + + DEBUG_EVENT( "%s: Configuring Interface: %s\n", + card->devname, conf->name); + + if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) { + DEBUG_EVENT( "%s: Invalid interface name!\n", + card->devname); + return -EINVAL; + } + + /* This protocol only supports a single network interface + * If developing a multi-interface protocol, one should + * alter this check to allow multiple interfaces */ + if (wan_atomic_read(&card->wandev.if_cnt) > 0){ + return -EEXIST; + } + + /* allocate and initialize private data */ + priv_area = wan_malloc(sizeof(private_area_t)); + if(priv_area == NULL){ + WAN_MEM_ASSERT(card->devname); + return -ENOMEM; + } + memset(priv_area, 0, sizeof(private_area_t)); + + strncpy(priv_area->if_name, conf->name, WAN_IFNAME_SZ); + + priv_area->card = card; + + /* Setup interface as: + * WANPIPE = IP over Protocol (Firmware) + * API = Raw Socket access to Protocol (Firmware) + * BRIDGE = Ethernet over Protocol, no ip info + * BRIDGE_NODE = Ethernet over Protocol, with ip info + */ + priv_area->common.usedby = API; + DEBUG_EVENT( "%s:%s: Running in API mode !\n", + wandev->name,priv_area->if_name); + + + /* The network interface "dev" has been passed as + * an argument from the above layer. We must initialize + * it so it can be registered into the kernel. + * + * The "dev" structure is the link between the kernel + * stack and the wanpipe driver. It contains all + * access hooks that kernel uses to communicate to + * the our driver. + * + * For now, just set the "dev" name to the user + * defined name and initialize: + * dev->if_init : function that will be called + * to further initialize + * dev structure on "ifconfig up" + * + * dev->priv : private structure allocated above + * + */ + + /* Only setup the dev pointer once the new_if function has + * finished successfully. DO NOT place any code below that + * can return an error */ + dev->init = &if_init; + dev->priv = priv_area; + + /* Increment the number of network interfaces + * configured on this card. + */ + wan_atomic_inc(&card->wandev.if_cnt); + + DEBUG_EVENT( "\n"); + + return 0; +} + +/*============================================================================ + * del_if - Delete logical channel. + * + * @wandev: Wanpipe private device pointer + * @dev: Netowrk interface pointer + * + * This function is called by ROUTER_DELIF ioctl call + * to deallocate the network interface. + * + * The network interface and the private structure are + * about to be deallocated by the upper layer. + * We have to clean and deallocate any allocated memory. + * + * NOTE: DO NOT deallocate dev->priv here! It will be + * done by the upper layer. + * + */ +static int del_if (wan_device_t* wandev, struct net_device* dev) +{ + private_area_t* priv_area = dev->priv; + sdla_t* card = priv_area->card; + + /* Decrement the number of network interfaces + * configured on this card. + */ + wan_atomic_dec(&card->wandev.if_cnt); + + DEBUG_SUB_MEM(sizeof(private_area_t)); + return 0; +} + + +/**SECTION*********************************************************** + * + * KERNEL Device Entry Interfaces + * + ********************************************************************/ + + + +/*============================================================================ + * if_init - Initialize Linux network interface. + * + * @dev: Network interface pointer + * + * During "ifconfig up" the upper layer calls this function + * to initialize dev access pointers. Such as transmit, + * stats and header. + * + * It is called only once for each interface, + * during Linux network interface registration. + * + * Returning anything but zero will fail interface + * registration. + */ +static int if_init (struct net_device* dev) +{ + private_area_t* priv_area = dev->priv; + sdla_t* card = priv_area->card; + wan_device_t* wandev = &card->wandev; + + /* Initialize device driver entry points */ + dev->open = &if_open; + dev->stop = &if_close; + dev->hard_header = NULL; + dev->rebuild_header = NULL; + dev->hard_start_xmit = &if_send; + dev->get_stats = &if_stats; + dev->do_ioctl = if_do_ioctl; + + /* Initialize media-specific parameters */ + dev->flags |= IFF_POINTOPOINT; + dev->flags |= IFF_NOARP; + dev->type = ARPHRD_PPP; + + dev->mtu = card->wandev.mtu; + + dev->hard_header_len = 0; + + /* Initialize hardware parameters */ + dev->irq = wandev->irq; + dev->dma = wandev->dma; + dev->base_addr = wandev->ioport; + card->hw_iface.getcfg(card->hw, SDLA_MEMBASE, &dev->mem_start); + card->hw_iface.getcfg(card->hw, SDLA_MEMEND, &dev->mem_end); + + /* Set transmit buffer queue length + * If too low packets will not be retransmitted + * by stack. + */ + dev->tx_queue_len = 100; + + return 0; +} + +/*============================================================================ + * if_open - Open network interface. + * + * @dev: Network device pointer + * + * On ifconfig up, this function gets called in order + * to initialize and configure the private area. + * Driver should be configured to send and receive data. + * + * This functions starts a timer that will call + * frmw_config() function. This function must be called + * because the IP addresses could have been changed + * for this interface. + * + * Return 0 if O.k. or errno. + */ +static int if_open (struct net_device* dev) +{ + private_area_t* priv_area = dev->priv; + sdla_t* card = priv_area->card; + struct timeval tv; + int err = 0; + + /* Only one open per interface is allowed */ + if (open_dev_check(dev)) + return -EBUSY; + + /* Initialize the router start time. + * Used by wanpipemon debugger to indicate + * how long has the interface been up */ + do_gettimeofday(&tv); + priv_area->router_start_time = tv.tv_sec; + + netif_start_queue(dev); + + /* Increment the module usage count */ + wanpipe_open(card); + + return err; +} + +/*============================================================================ + * if_close - Close network interface. + * + * @dev: Network device pointer + * + * On ifconfig down, this function gets called in order + * to cleanup interace private area. + * + * IMPORTANT: + * + * No deallocation or unconfiguration should ever occur in this + * function, because the interface can come back up + * (via ifconfig up). + * + * Furthermore, in dynamic interfacace configuration mode, the + * interface will come up and down to reflect the protocol state. + * + * Any deallocation and cleanup can occur in del_if() + * function. That function is called before the dev interface + * itself is deallocated. + * + * Thus, we should only stop the net queue and decrement + * the wanpipe usage counter via wanpipe_close() function. + */ + +static int if_close (struct net_device* dev) +{ + private_area_t* priv_area = dev->priv; + sdla_t* card = priv_area->card; + + stop_net_queue(dev); + +#if defined(LINUX_2_1) + dev->start=0; +#endif + wanpipe_close(card); + return 0; +} + + +/*============================================================= + * disable_comm - Main shutdown function + * + * @card: Wanpipe device pointer + * + * The command 'wanrouter stop' has been called + * and the whole wanpipe device is going down. + * This is the last function called to disable + * all comunications and deallocate any memory + * that is still allocated. + * + * o Disable communications, turn off interrupts + * o Deallocate memory used, if any + * o Unconfigure TE1 card + */ + +static void disable_comm (sdla_t *card) +{ + unsigned long smp_flags; + + wan_spin_lock_irq(&card->wandev.lock,&smp_flags); + if (card->comm_enabled){ + disable_comm_shutdown (card); + } + wan_spin_unlock_irq(&card->wandev.lock,&smp_flags); + + return; +} + + +/*============================================================================ + * if_send - Send a packet on a network interface. + * + * @dev: Network interface pointer + * @skb: Packet obtained from the stack or API + * that should be sent out the port. + * + * o Mark interface as stopped + * (marks start of the transmission) to indicate + * to the stack that the interface is busy. + * + * o Check link state. + * If link is not up, then drop the packet. + * + * o Copy the tx packet into the protocol tx buffers on + * the adapter. + * + * o If tx successful: + * Free the skb buffer and mark interface as running + * and return 0. + * + * o If tx failed, busy: + * Keep interface marked as busy + * Do not free skb buffer + * Enable Tx interrupt (which will tell the stack + * that interace is not busy) + * Return a non-zero value to tell the stack + * that the tx should be retried. + * + * Return: 0 complete (socket buffer must be freed) + * non-0 packet may be re-transmitted + * + */ +static int if_send (struct sk_buff* skb, struct net_device* dev) +{ + private_area_t *chan = dev->priv; + sdla_t *card = chan->card; + + if (skb){ + wan_skb_free(skb); + } + DEBUG_EVENT("%s: if_send() dropping packet!\n",card->devname); + + start_net_queue(dev); + + return 0; +} + + +/*============================================================================ + * if_stats + * + * Used by /proc/net/dev and ifconfig to obtain interface + * statistics. + * + * Return a pointer to struct net_device_stats. + */ +static struct net_device_stats* if_stats (struct net_device* dev) +{ + private_area_t* priv_area; + + if ((priv_area=dev->priv) == NULL) + return NULL; + + return &priv_area->if_stats; +} + + + + +/*======================================================================== + * + * if_do_ioctl - Ioctl handler for fr + * + * @dev: Device subject to ioctl + * @ifr: Interface request block from the user + * @cmd: Command that is being issued + * + * This function handles the ioctls that may be issued by the user + * to control or debug the protocol or hardware . + * + * It does both busy and security checks. + * This function is intended to be wrapped by callers who wish to + * add additional ioctl calls of their own. + * + * Used by: SNMP Mibs + * wanpipemon debugger + * + */ +static int if_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + private_area_t* chan= (private_area_t*)dev->priv; + //unsigned long smp_flags; + wan_mbox_t *mb,*usr_mb; + sdla_t *card; + int err=0; + + if (!chan){ + return -ENODEV; + } + card=chan->card; + mb = &card->wan_mbox; + + NET_ADMIN_CHECK(); + + if (test_and_set_bit(0,&card->wandev.critical)){ + return -EBUSY; + } + + switch(cmd) + { + case SIOC_WANPIPE_POS_STATUS_CMD: + + usr_mb=(wan_mbox_t*)ifr->ifr_data; + if (!usr_mb){ + DEBUG_EVENT ( + "%s: Ioctl command %x, has no Mbox attached\n", + card->devname, cmd); + err=-EINVAL; + break; + } + + if (copy_to_user((unsigned char*)usr_mb+1, (unsigned char*)mb+1,2)){ + err= -EFAULT; + break; + } + + break; + + case SIOC_WANPIPE_EXEC_CMD: + + usr_mb=(wan_mbox_t*)ifr->ifr_data; + if (!usr_mb){ + DEBUG_EVENT ( + "%s: Ioctl command %x, has no Mbox attached\n", + card->devname, cmd); + err=-EINVAL; + break; + } + + if (copy_from_user((unsigned char*)mb, (unsigned char *)usr_mb, 0x16)){ + printk(KERN_INFO "%s: SDLC Cmd: Failed to copy mb \n",card->devname); + err = -EFAULT; + break; + } + + if (mb->wan_pos_data_len > 0){ + + if (mb->wan_pos_data_len > 1030){ + DEBUG_EVENT("MAJORE ERROR !! DATA LEN > 1030\n"); + err=-EFAULT; + break; + } + + + if (copy_from_user((unsigned char*)&mb->wan_pos_data[0], + (unsigned char*)&usr_mb->wan_pos_data[0], + mb->wan_pos_data_len)){ + printk(KERN_INFO "%s: SDLC Cmd: Failed to copy mb data: len=%i\n", + card->devname, mb->wan_pos_data_len); + err = -EFAULT; + break; + } + } + + //spin_lock_irqsave(&card->wandev.lock,smp_flags); + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + //spin_unlock_irqrestore(&card->wandev.lock,smp_flags); + + if (err != COMMAND_OK) { + err = frmw_error(card,err,mb); + break; + } + + if (!err && mb->wan_pos_command == CONFIGURE){ + CONFIGURATION_STRUCT *cfg=(CONFIGURATION_STRUCT *)mb->wan_pos_data; + dev->mtu = cfg->sdlc_maxdata; + } + + /* copy the result back to our buffer */ + if (copy_to_user((unsigned char*)usr_mb, (unsigned char*)mb,0x16)){ + err= -EFAULT; + break; + } + + if (mb->wan_pos_data_len>0) { + + if (mb->wan_pos_data_len > 1030){ + DEBUG_EVENT("MAJORE ERROR !! DATA LEN > 1030\n"); + err=-EFAULT; + break; + } + + if (copy_to_user(&usr_mb->wan_pos_data[0], + &mb->wan_pos_data[0], + mb->wan_pos_data_len)){ + err= -EFAULT; + break; + } + } + + break; + + + default: + err= -EOPNOTSUPP; + break; + } + + clear_bit(0,&card->wandev.critical); + return err; +} + + + +/*=========================================================== + * disable_comm_shutdown + * + * Shutdown() disables the communications. We must + * have a sparate functions, because we must not + * call frmw_error() hander since the private + * area has already been replaced */ + +static int disable_comm_shutdown (sdla_t *card) +{ + wan_mbox_t* mb = &card->wan_mbox; + int err; + + mb->wan_pos_data_len = 0; + mb->wan_pos_port_num = card->wandev.comm_port;; + mb->wan_pos_command = DISABLE_POS; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + + card->comm_enabled = 0; + + return 0; +} + + +/*============================================================================ + * Firmware error handler. + * This routine is called whenever firmware command returns non-zero + * return code. + * + * Return zero if previous command has to be cancelled. + */ +static int frmw_error (sdla_t *card, int err, wan_mbox_t *mb) +{ + unsigned cmd = mb->wan_pos_command; + + switch (err) { + + case 0x33: + + switch(cmd){ + case SEND_ASYNC: + return -EBUSY; + } + + default: + DEBUG_EVENT( "%s: command 0x%02X returned 0x%02X!\n", + card->devname, cmd, err); + } + + return 0; +} + diff -Nur linux.org/drivers/net/wan/sdla_ppp.c linux-2.6.17/drivers/net/wan/sdla_ppp.c --- linux.org/drivers/net/wan/sdla_ppp.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/drivers/net/wan/sdla_ppp.c 2006-08-30 10:07:16.000000000 +0000 @@ -0,0 +1,4574 @@ +/***************************************************************************** +* sdla_ppp.c WANPIPE(tm) Multiprotocol WAN Link Driver. PPP module. +* +* Author: Nenad Corbic +* +* Copyright: (c) 1995-2002 Sangoma Technologies Inc. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version +* 2 of the License, or (at your option) any later version. +* ============================================================================ +* Jan 03, 2003 Nenad Corbic o Bug fix in Rx IPX packet. Possible memory leak +* if an invalid IPX packet was received +* Oct 18, 2002 Nenad Corbic 0 Added BRIDGE support +* Aug 30, 2002 Nenad Corbic o Added support for S5147 Dual TE1 card +* Jan 12, 2002 Nenad Corbic o Removed the 2.0.X support +* Added front end states +* Dec 03, 2001 Gideon Hack o Updated for S514-5 56K adapter. +* Sep 20, 2001 Nenad Corbic o The min() function has changed for 2.4.9 +* kernel. Thus using the wp_min() defined in +* wanpipe.h +* Sept 6, 2001 Alex Feldman o Add SNMP support. +* Aug 23, 2001 Nenad Corbic o Removed the if_header and set the hard_header +* length to zero. Caused problems with Checkpoint +* firewall. +* Jul 22, 2001 Nenad Corbic o Buf Fix make sure that in_dev ptr exists +* before trying to reference it. +* Jun 07, 2001 Nenad Corbic o Bug Fix in retrigger_comm(): +* On a noisy line, if the +* protocol toggles UP and DOWN fast +* enough it can lead to a race condition +* that will cause it to stop working. +* May 25, 2001 Alex Feldman o Added T1/E1 support +* Feb 28, 2001 Nenad Corbic o Updated if_tx_timeout() routine for +* 2.4.X kernels. +* Nov 29, 2000 Nenad Corbic o Added the 2.4.x kernel support: +* get_ip_address() function has moved +* into the ppp_poll() routine. It cannot +* be called from an interrupt. +* Nov 07, 2000 Nenad Corbic o Added security features for UDP debugging: +* Deny all and specify allowed requests. +* May 02, 2000 Nenad Corbic o Added the dynamic interface shutdown +* option. When the link goes down, the +* network interface IFF_UP flag is reset. +* Mar 06, 2000 Nenad Corbic o Bug Fix: corrupted mbox recovery. +* Feb 25, 2000 Nenad Corbic o Fixed the FT1 UDP debugger problem. +* Feb 09, 2000 Nenad Coribc o Shutdown bug fix. update() was called +* with NULL dev pointer: no check. +* Jan 24, 2000 Nenad Corbic o Disabled use of CMD complete inter. +* Dev 15, 1999 Nenad Corbic o Fixed up header files for 2.0.X kernels +* Oct 25, 1999 Nenad Corbic o Support for 2.0.X kernels +* Moved dynamic route processing into +* a polling routine. +* Oct 07, 1999 Nenad Corbic o Support for S514 PCI card. +* Gideon Hack o UPD and Updates executed using timer interrupt +* Sep 10, 1999 Nenad Corbic o Fixed up the /proc statistics +* Jul 20, 1999 Nenad Corbic o Remove the polling routines and use +* interrupts instead. +* Sep 17, 1998 Jaspreet Singh o Updates for 2.2.X Kernels. +* Aug 13, 1998 Jaspreet Singh o Improved Line Tracing. +* Jun 22, 1998 David Fong o Added remote IP address assignment +* Mar 15, 1998 Alan Cox o 2.1.8x basic port. +* Apr 16, 1998 Jaspreet Singh o using htons() for the IPX protocol. +* Dec 09, 1997 Jaspreet Singh o Added PAP and CHAP. +* o Implemented new routines like +* ppp_set_inbnd_auth(), ppp_set_outbnd_auth(), +* tokenize() and strstrip(). +* Nov 27, 1997 Jaspreet Singh o Added protection against enabling of irqs +* while they have been disabled. +* Nov 24, 1997 Jaspreet Singh o Fixed another RACE condition caused by +* disabling and enabling of irqs. +* o Added new counters for stats on disable/enable +* IRQs. +* Nov 10, 1997 Jaspreet Singh o Initialized 'skb->mac.raw' to 'skb->data' +* before every netif_rx(). +* o Free up the device structure in del_if(). +* Nov 07, 1997 Jaspreet Singh o Changed the delay to zero for Line tracing +* command. +* Oct 20, 1997 Jaspreet Singh o Added hooks in for Router UP time. +* Oct 16, 1997 Jaspreet Singh o The critical flag is used to maintain flow +* control by avoiding RACE conditions. The +* cli() and restore_flags() are taken out. +* A new structure, "ppp_private_area", is added +* to provide Driver Statistics. +* Jul 21, 1997 Jaspreet Singh o Protected calls to sdla_peek() by adding +* save_flags(), cli() and restore_flags(). +* Jul 07, 1997 Jaspreet Singh o Added configurable TTL for UDP packets +* o Added ability to discard mulitcast and +* broacast source addressed packets. +* Jun 27, 1997 Jaspreet Singh o Added FT1 monitor capabilities +* New case (0x25) statement in if_send routine. +* Added a global variable rCount to keep track +* of FT1 status enabled on the board. +* May 22, 1997 Jaspreet Singh o Added change in the PPP_SET_CONFIG command for +* 508 card to reflect changes in the new +* ppp508.sfm for supporting:continous transmission +* of Configure-Request packets without receiving a +* reply +* OR-ed 0x300 to conf_flags +* o Changed connect_tmout from 900 to 0 +* May 21, 1997 Jaspreet Singh o Fixed UDP Management for multiple boards +* Apr 25, 1997 Farhan Thawar o added UDP Management stuff +* Mar 11, 1997 Farhan Thawar Version 3.1.1 +* o fixed (+1) bug in rx_intr() +* o changed if_send() to return 0 if +* wandev.critical() is true +* o free socket buffer in if_send() if +* returning 0 +* Jan 15, 1997 Gene Kozin Version 3.1.0 +* o implemented exec() entry point +* Jan 06, 1997 Gene Kozin Initial version. +*****************************************************************************/ + +#include +#include +#include /* WAN router definitions */ +#include /* WANPIPE common user API definitions */ +#include +#include +#include /* PPP firmware API definitions */ +#include /* S514 Type Definition */ +#include +#include +#include /* Socket Driver common area */ + + + +/****** Defines & Macros ****************************************************/ + +#define PPP_DFLT_MTU 1500 /* default MTU */ +#define PPP_MAX_MTU 4000 /* maximum MTU */ +#define PPP_HDR_LEN 1 + +/* Private critical flags */ +enum { + POLL_CRIT = PRIV_CRIT +}; + +#define MAX_IP_ERRORS 100 + +#define CONNECT_TIMEOUT (90*HZ) /* link connection timeout */ +#define HOLD_DOWN_TIME (5*HZ) /* link hold down time : Changed from 30 to 5 */ + +/* For handle_IPXWAN() */ +#define CVHexToAscii(b) (((unsigned char)(b) > (unsigned char)9) ? ((unsigned char)'A' + ((unsigned char)(b) - (unsigned char)10)) : ((unsigned char)'0' + (unsigned char)(b))) + +/* Macro for enabling/disabling debugging comments */ +#undef NEX_DEBUG +#ifdef NEX_DEBUG +#define NEX_PRINTK(format, a...) printk(format, ## a) +#else +#define NEX_PRINTK(format, a...) +#endif /* NEX_DEBUG */ + +#define DCD(a) ( a & 0x08 ? "HIGH" : "LOW" ) +#define CTS(a) ( a & 0x20 ? "HIGH" : "LOW" ) +#define LCP(a) ( a == 0x09 ? "OPEN" : "CLOSED" ) +#define IP(a) ( a == 0x09 ? "ENABLED" : "DISABLED" ) + +#define TMR_INT_ENABLED_UPDATE 0x01 +#define TMR_INT_ENABLED_PPP_EVENT 0x02 +#define TMR_INT_ENABLED_UDP 0x04 +#define TMR_INT_ENABLED_CONFIG 0x20 +#define TMR_INT_ENABLED_TE 0x40 + +/* Set Configuraton Command Definitions */ +#define PERCENT_TX_BUFF 60 +#define TIME_BETWEEN_CONF_REQ 120 +#define TIME_BETWEEN_PAP_CHAP_REQ 120 +#define WAIT_PAP_CHAP_WITHOUT_REPLY 1200 +#define WAIT_AFTER_DCD_CTS_LOW 20 +#define TIME_DCD_CTS_LOW_AFTER_LNK_DOWN 40 +#define WAIT_DCD_HIGH_AFTER_ENABLE_COMM 3400 +#define MAX_CONF_REQ_WITHOUT_REPLY 40 +#define MAX_TERM_REQ_WITHOUT_REPLY 10 +#define NUM_CONF_NAK_WITHOUT_REPLY 20 +#define NUM_AUTH_REQ_WITHOUT_REPLY 40 + + +#define END_OFFSET 0x1F0 +#if LINUX_VERSION_CODE < 0x020125 +#define test_and_set_bit set_bit +#define net_ratelimit() 1 +#endif + +/* Number of times we'll retry to + * enable comunications. If it fails + * the link should be restarted */ +#define MAX_COMM_BUSY_RETRY 10 + +/******Data Structures*****************************************************/ + +/* This structure is placed in the private data area of the device structure. + * The card structure used to occupy the private area but now the following + * structure will incorporate the card structure along with PPP specific data + */ + +typedef struct ppp_private_area +{ + wanpipe_common_t common; + netdevice_t *slave; + sdla_t* card; + unsigned long router_start_time; /*router start time in sec */ + unsigned long tick_counter; /*used for 5 second counter*/ + unsigned mc; /*multicast support on or off*/ + unsigned char enable_IPX; + unsigned long network_number; + unsigned char pap; + unsigned char chap; + unsigned char sysname[31]; /* system name for in-bnd auth*/ + unsigned char userid[511]; /* list of user ids */ + unsigned char passwd[511]; /* list of passwords */ + unsigned protocol; /* SKB Protocol */ + u32 ip_local; /* Local IP Address */ + u32 ip_remote; /* remote IP Address */ + + u32 ip_local_tmp; + u32 ip_remote_tmp; + + unsigned int timer_int_enabled; /* Who enabled the timer inter*/ + unsigned long update_comms_stats; /* Used by update function */ + unsigned long curr_trace_addr; /* Trace information */ + unsigned long start_trace_addr; + unsigned long end_trace_addr; + + unsigned long interface_down; /* Brind down interface when channel + goes down */ + unsigned long config_wait_timeout; /* After if_open() if in dynamic if mode, + wait a few seconds before configuring */ + char udp_pkt_src; + + /* PPP specific statistics */ + + if_send_stat_t if_send_stat; + rx_intr_stat_t rx_intr_stat; + pipe_mgmt_stat_t pipe_mgmt_stat; + + unsigned long router_up_time; + + /* Polling task queue. Each interface + * has its own task queue, which is used + * to defer events from the interrupt */ + struct tq_struct poll_task; + struct timer_list poll_delay_timer; + + u8 gateway; + unsigned long config_ppp; + u8 ip_error; + + /* Entry in proc fs per each interface */ + struct proc_dir_entry* dent; + + unsigned char comm_busy_retry; + unsigned char ppp_state; + + unsigned char udp_pkt_data[sizeof(wan_udp_pkt_t)+10]; + atomic_t udp_pkt_len; + + char if_name[WAN_IFNAME_SZ+1]; + +}ppp_private_area_t; + +extern void disable_irq(unsigned int); +extern void enable_irq(unsigned int); + +/****** Function Prototypes *************************************************/ + +/* WAN link driver entry points. These are called by the WAN router module. */ +static int update(wan_device_t *wandev); +static int new_if(wan_device_t *wandev, netdevice_t *dev, wanif_conf_t *conf); +static int del_if(wan_device_t *wandev, netdevice_t *dev); + +/* Network device interface */ +static int if_init(netdevice_t *dev); +static int if_open(netdevice_t *dev); +static int if_close(netdevice_t *dev); +static int if_do_ioctl(netdevice_t *dev, struct ifreq *ifr, int cmd); + + +static void if_tx_timeout (netdevice_t *dev); + +static struct net_device_stats *if_stats(netdevice_t *dev); +static int if_send(struct sk_buff *skb, netdevice_t *dev); + + +/* PPP firmware interface functions */ +static int ppp_read_version(sdla_t *card, char *str); +static int ppp_set_outbnd_auth(sdla_t *card, ppp_private_area_t *ppp_priv_area); +static int ppp_set_inbnd_auth(sdla_t *card, ppp_private_area_t *ppp_priv_area); +static int ppp_configure(sdla_t *card, void *data); +static int ppp_set_intr_mode(sdla_t *card, unsigned char mode); +static int ppp_comm_enable(sdla_t *card); +static int ppp_comm_disable(sdla_t *card); +static int ppp_comm_disable_shutdown(sdla_t *card); +static int ppp_get_err_stats(sdla_t *card); +static int ppp_send(sdla_t *card, void *data, unsigned len, unsigned proto); +static int ppp_error(sdla_t *card, int err, wan_mbox_t *mb); + +static int set_adapter_config (sdla_t* card); + + +static void wpp_isr(sdla_t *card); +static void rx_intr(sdla_t *card); +static void event_intr(sdla_t *card); +static void timer_intr(sdla_t *card); + +/* Background polling routines */ +static void process_route(sdla_t *card); +static int retrigger_comm(sdla_t *card); + +/* Miscellaneous functions */ +static int read_info( sdla_t *card ); +static int read_connection_info (sdla_t *card); +static void remove_route( sdla_t *card ); +static int config508(netdevice_t *dev, sdla_t *card); +static void show_disc_cause(sdla_t * card, unsigned cause); +static int reply_udp( unsigned char *data, unsigned int mbox_len ); +static void process_udp_mgmt_pkt(sdla_t *card, netdevice_t *dev, + ppp_private_area_t *ppp_priv_area,int local_dev); +static void init_ppp_tx_rx_buff( sdla_t *card ); +static int intr_test( sdla_t *card ); +static int udp_pkt_type( struct sk_buff *skb , sdla_t *card); +static void init_ppp_priv_struct( ppp_private_area_t *ppp_priv_area); +static void init_global_statistics( sdla_t *card ); +static int tokenize(char *str, char **tokens); +static char* strstrip(char *str, char *s); +static int chk_bcast_mcast_addr(sdla_t* card, netdevice_t* dev, + struct sk_buff *skb); + +static int config_ppp (sdla_t *); +static void ppp_poll(void *); +static void trigger_ppp_poll(netdevice_t *); +static void ppp_poll_delay (unsigned long dev_ptr); + + +static unsigned long Read_connection_info; +static unsigned short available_buffer_space; + + +/* IPX functions */ +static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, + unsigned char incoming); +static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_PX, + unsigned long network_number, unsigned short proto); + +/* Lock Functions */ +static void s508_lock (sdla_t *card, unsigned long *smp_flags); +static void s508_unlock (sdla_t *card, unsigned long *smp_flags); + +static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, + struct sk_buff *skb, netdevice_t* dev, + ppp_private_area_t* ppp_priv_area ); +static unsigned short calc_checksum (char *data, int len); +static void disable_comm (sdla_t *card); +static int detect_and_fix_tx_bug (sdla_t *card); + +static int ppp_get_config_info(void* priv, struct seq_file* m, int*); +static int ppp_get_status_info(void* priv, struct seq_file* m, int*); +static int ppp_set_dev_config(struct file*, const char*, unsigned long, void *); +static int ppp_set_if_info(struct file*, const char*, unsigned long, void *); + +static WRITE_FRONT_END_REG_T write_front_end_reg; +static READ_FRONT_END_REG_T read_front_end_reg; +static void ppp_enable_timer(void* card_id); +static void ppp_handle_front_end_state(void* card_id); + +/* SNMP */ +static int ppp_snmp_data(sdla_t* card, netdevice_t *dev, void* data); + +static int ppp_debugging(sdla_t* card); +static unsigned long ppp_crc_frames(sdla_t* card); +static unsigned long ppp_abort_frames(sdla_t * card); +static unsigned long ppp_tx_underun_frames(sdla_t* card); +/****** Public Functions ****************************************************/ + +/*============================================================================ + * PPP protocol initialization routine. + * + * This routine is called by the main WANPIPE module during setup. At this + * point adapter is completely initialized and firmware is running. + * o read firmware version (to make sure it's alive) + * o configure adapter + * o initialize protocol-specific fields of the adapter data space. + * + * Return: 0 o.k. + * < 0 failure. + */ +int wpp_init(sdla_t *card, wandev_conf_t *conf) +{ + int err; + union + { + char str[80]; + } u; + + /* Verify configuration ID */ + if (conf->config_id != WANCONFIG_PPP) { + + printk(KERN_INFO "%s: invalid configuration ID %u!\n", + card->devname, conf->config_id); + return -EINVAL; + + } + + /* Initialize miscellaneous pointers to structures on the adapter */ + switch (card->type) { + + case SDLA_S508: /* Alex Apr 8 2004 Sangoma ISA card */ + case SDLA_S514: + card->mbox_off = PPP514_MB_OFFS; + card->flags_off = PPP514_FLG_OFFS; + break; + + default: + return -EINVAL; + + } + card->intr_type_off = + card->flags_off + + offsetof(ppp_flags_t, iflag); + card->intr_perm_off = + card->flags_off + + offsetof(ppp_flags_t, imask); + card->wandev.ignore_front_end_status = conf->ignore_front_end_status; + + //ALEX_TODAY err=check_conf_hw_mismatch(card,conf->te_cfg.media); + err = (card->hw_iface.check_mismatch) ? + card->hw_iface.check_mismatch(card->hw,conf->fe_cfg.media) : -EINVAL; + if (err){ + return err; + } + + /* TE1 Make special hardware initialization for T1/E1 board */ + if (IS_TE1_MEDIA(&conf->fe_cfg)){ + + memcpy(&card->fe.fe_cfg, &conf->fe_cfg, sizeof(sdla_fe_cfg_t)); + sdla_te_iface_init(&card->wandev.fe_iface); + card->fe.name = card->devname; + card->fe.card = card; + card->fe.write_fe_reg = write_front_end_reg; + card->fe.read_fe_reg = read_front_end_reg; + + card->wandev.fe_enable_timer = ppp_enable_timer; + card->wandev.te_link_state = ppp_handle_front_end_state; + conf->interface = + (IS_T1_CARD(card)) ? WANOPT_V35 : WANOPT_RS232; + conf->clocking = WANOPT_EXTERNAL; + + }else if (IS_56K_MEDIA(&conf->fe_cfg)){ + + memcpy(&card->fe.fe_cfg, &conf->fe_cfg, sizeof(sdla_fe_cfg_t)); + sdla_56k_iface_init(&card->wandev.fe_iface); + card->fe.name = card->devname; + card->fe.card = card; + card->fe.write_fe_reg = write_front_end_reg; + card->fe.read_fe_reg = read_front_end_reg; + + conf->clocking = WANOPT_EXTERNAL; + }else{ + card->fe.fe_status = FE_CONNECTED; + } + + if (card->wandev.ignore_front_end_status == WANOPT_NO){ + printk(KERN_INFO + "%s: Enabling front end link monitor\n", + card->devname); + }else{ + printk(KERN_INFO + "%s: Disabling front end link monitor\n", + card->devname); + } + + /* Read firmware version. Note that when adapter initializes, it + * clears the mailbox, so it may appear that the first command was + * executed successfully when in fact it was merely erased. To work + * around this, we execute the first command twice. + */ + if (ppp_read_version(card, NULL) || ppp_read_version(card, u.str)) + return -EIO; + + printk(KERN_INFO "%s: running PPP firmware v%s\n",card->devname, u.str); + + + if (set_adapter_config(card)) { + return -EIO; + } + + + /* Adjust configuration and set defaults */ + card->wandev.mtu = (conf->mtu) ? + wp_min(conf->mtu, PPP_MAX_MTU) : PPP_DFLT_MTU; + + card->wandev.bps = conf->bps; + card->wandev.interface = conf->interface; + card->wandev.clocking = conf->clocking; + card->isr = &wpp_isr; + card->poll = NULL; + card->exec = NULL; + card->wandev.update = &update; + card->wandev.new_if = &new_if; + card->wandev.del_if = &del_if; + card->wandev.udp_port = conf->udp_port; + card->wandev.ttl = conf->ttl; + card->wandev.state = WAN_DISCONNECTED; + card->disable_comm = &disable_comm; + card->irq_dis_if_send_count = 0; + card->irq_dis_poll_count = 0; + card->u.p.authenticator = conf->u.ppp.authenticator; + card->u.p.ip_mode = conf->u.ppp.ip_mode ? + conf->u.ppp.ip_mode : WANOPT_PPP_STATIC; + card->TracingEnabled = 0; + Read_connection_info = 1; + + // Proc fs functions + card->wandev.get_config_info = &ppp_get_config_info; + card->wandev.get_status_info = &ppp_get_status_info; + card->wandev.set_dev_config = &ppp_set_dev_config; + card->wandev.set_if_info = &ppp_set_if_info; + + /* Debugging */ + card->wan_debugging = &ppp_debugging; + card->get_crc_frames = &ppp_crc_frames; + card->get_abort_frames = &ppp_abort_frames; + card->get_tx_underun_frames = &ppp_tx_underun_frames; + + /* SNMP data */ + card->get_snmp_data = &ppp_snmp_data; + /* initialize global statistics */ + init_global_statistics( card ); + + + + if (!card->configured){ + int err; + + card->timer_int_enabled = 0; + err = intr_test(card); + + if(err || (card->timer_int_enabled < MAX_INTR_TEST_COUNTER)) { + printk("%s: Interrupt Test Failed, Counter: %i\n", + card->devname, card->timer_int_enabled); + printk( "%s: Please choose another interrupt\n",card->devname); + return -EIO; + } + + printk(KERN_INFO "%s: Interrupt Test Passed, Counter: %i\n", + card->devname, card->timer_int_enabled); + card->configured = 1; + } + + ppp_set_intr_mode(card, PPP_INTR_TIMER); + + /* Turn off the timer interrupt */ + card->hw_iface.clear_bit(card->hw, card->intr_perm_off, PPP_INTR_TIMER); + + printk(KERN_INFO "\n"); + + return 0; +} + +/******* WAN Device Driver Entry Points *************************************/ + +/*============================================================================ + * Update device status & statistics. + */ +static int update(wan_device_t *wandev) +{ + sdla_t* card = wandev->private; + netdevice_t *dev; + volatile ppp_private_area_t *ppp_priv_area; + unsigned long smp_flags; + + /* sanity checks */ + if ((wandev == NULL) || (wandev->private == NULL)) + return -EFAULT; + + if (wandev->state == WAN_UNCONFIGURED) + return -ENODEV; + + /* Shutdown bug fix. This function can be + * called with NULL dev pointer during + * shutdown + */ + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + if (dev == NULL) + return -ENODEV; + + if ((ppp_priv_area = wan_netif_priv(dev)) == NULL){ + return -ENODEV; + } + + /* TE1 Read T1/E1 alarms and PMON counters in one timer interrupt */ + if (test_and_set_bit(0,&ppp_priv_area->update_comms_stats)){ + return -EBUSY; + } + + spin_lock_irqsave(&card->wandev.lock, smp_flags); + + ppp_get_err_stats(card); + + if (IS_TE1_CARD(card)) { + card->wandev.fe_iface.read_alarm(&card->fe, 0); + /* TE1 Update T1/E1 perfomance counters */ + card->wandev.fe_iface.read_pmon(&card->fe, 0); + }else if (IS_56K_CARD(card)) { + /* 56K Update CSU/DSU alarms */ + card->wandev.fe_iface.read_alarm(&card->fe, 1); + } + + ppp_priv_area->update_comms_stats=0; + + spin_unlock_irqrestore(&card->wandev.lock, smp_flags); + + return 0; +} + +/*============================================================================ + * new_if - Create new logical channel. + * + * &wandev: Wanpipe device pointer + * &dev: Network device pointer + * &conf: User configuration options pointer + * + * This routine is called by the ROUTER_IFNEW ioctl, + * in wanmain.c. The ioctl passes us the user configuration + * options which we use to configure the driver and + * firmware. + * + * This functions main purpose is to allocate the + * private structure for CHDLC protocol and bind it + * to dev->priv pointer. + * + * Also the dev->init pointer should also be initialized + * to the if_init() function. + * + * Any allocation necessary for the private strucutre + * should be done here, as well as proc/ file initializetion + * for the network interface. + * + * o parse media- and hardware-specific configuration + * o make sure that a new channel can be created + * o allocate resources, if necessary + * o prepare network device structure for registaration. + * o add network interface to the /proc/net/wanrouter + * + * The opposite of this function is del_if() + * + * Return: 0 o.k. + * < 0 failure (channel will not be created) + */ +static int new_if(wan_device_t *wandev, netdevice_t *dev, wanif_conf_t *conf) +{ + sdla_t *card = wandev->private; + ppp_private_area_t *ppp_priv_area; + int err = 0; + + if (wandev->ndev) + return -EEXIST; + + + printk(KERN_INFO "%s: Configuring Interface: %s\n", + card->devname, conf->name); + + if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) { + + printk(KERN_INFO "%s: Invalid interface name!\n", + card->devname); + return -EINVAL; + + } + + /* allocate and initialize private data */ + ppp_priv_area = kmalloc(sizeof(ppp_private_area_t), GFP_KERNEL); + + if( ppp_priv_area == NULL ){ + WAN_MEM_ASSERT(card->devname); + return -ENOMEM; + } + + memset(ppp_priv_area, 0, sizeof(ppp_private_area_t)); + + ppp_priv_area->card = card; + + /* initialize data */ + strcpy(ppp_priv_area->if_name, conf->name); + + /* initialize data in ppp_private_area structure */ + + init_ppp_priv_struct( ppp_priv_area ); + + ppp_priv_area->mc = conf->mc; + ppp_priv_area->pap = conf->pap; + ppp_priv_area->chap = conf->chap; + + if(strcmp(conf->usedby, "WANPIPE") == 0) { + printk(KERN_INFO "%s: Running in WANPIPE IP mode!\n", + wandev->name); + ppp_priv_area->common.usedby = WANPIPE; + /* Option to bring down the interface when + * the link goes down */ + if (conf->if_down){ + set_bit(DYN_OPT_ON,&ppp_priv_area->interface_down); + printk("%s: Dynamic interface configuration enabled\n", + card->devname); + } + + }else if (strcmp(conf->usedby, "BRIDGE")==0){ + printk(KERN_INFO "%s:%s Running in WANPIPE BRIDGE mode!\n", + wandev->name,ppp_priv_area->if_name); + ppp_priv_area->common.usedby = BRIDGE; + + }else if (strcmp(conf->usedby, "BRIDGE_N") == 0){ + printk(KERN_INFO "%s:%s Running in WANPIPE BRIDGE NODE mode!\n", + wandev->name,ppp_priv_area->if_name); + ppp_priv_area->common.usedby = BRIDGE_NODE; + + }else{ + printk(KERN_INFO "%s:%s: Error: Invalid operation mode [WANPIPE|BRIDGE]\n", + card->devname,ppp_priv_area->if_name); + err=-EINVAL; + goto new_if_error; + } + + /* If no user ids are specified */ + if(!strlen(conf->userid) && (ppp_priv_area->pap||ppp_priv_area->chap)){ + err=-EINVAL; + goto new_if_error; + } + + /* If no passwords are specified */ + if(!strlen(conf->passwd) && (ppp_priv_area->pap||ppp_priv_area->chap)){ + err=-EINVAL; + goto new_if_error; + } + + if(strlen(conf->sysname) > 31){ + err=-EINVAL; + goto new_if_error; + } + + /* If no system name is specified */ + if(!strlen(conf->sysname) && (card->u.p.authenticator)){ + err=-EINVAL; + goto new_if_error; + } + + /* copy the data into the ppp private structure */ + memcpy(ppp_priv_area->userid, conf->userid, strlen(conf->userid)); + memcpy(ppp_priv_area->passwd, conf->passwd, strlen(conf->passwd)); + memcpy(ppp_priv_area->sysname, conf->sysname, strlen(conf->sysname)); + + + ppp_priv_area->enable_IPX = conf->enable_IPX; + if (conf->network_number){ + ppp_priv_area->network_number = conf->network_number; + }else{ + ppp_priv_area->network_number = 0xDEADBEEF; + } + + /* Tells us that if this interface is a + * gateway or not */ + if ((ppp_priv_area->gateway = conf->gateway) == WANOPT_YES){ + printk(KERN_INFO "%s: Interface %s is set as a gateway.\n", + card->devname,ppp_priv_area->if_name); + } + + /* Initialize the polling task routine */ + INIT_WORK((&ppp_priv_area->poll_task),ppp_poll,dev); + + /* Initialize the polling delay timer */ + init_timer(&ppp_priv_area->poll_delay_timer); + ppp_priv_area->poll_delay_timer.data = (unsigned long)dev; + ppp_priv_area->poll_delay_timer.function = ppp_poll_delay; + + /* + * Create interface file in proc fs. + * Once the proc file system is created, the new_if() function + * should exit successfuly. + * + * DO NOT place code under this function that can return + * anything else but 0. + */ + err = wanrouter_proc_add_interface(wandev, + &ppp_priv_area->dent, + ppp_priv_area->if_name, + dev); + if (err){ + printk(KERN_INFO + "%s: can't create /proc/net/router/ppp/%s entry!\n", + card->devname, ppp_priv_area->if_name); + goto new_if_error; + } + + dev->init = &if_init; + dev->priv = ppp_priv_area; + dev->mtu = wp_min(dev->mtu, card->wandev.mtu); + ppp_priv_area->ppp_state=WAN_DISCONNECTED; + + /* Since we start with dummy IP addresses we can say + * that route exists */ + printk(KERN_INFO "\n"); + + return 0; + +new_if_error: + + kfree(ppp_priv_area); + dev->priv=NULL; + + return err; +} + + +/*============================================================================ + * del_if - Delete logical channel. + * + * @wandev: Wanpipe private device pointer + * @dev: Netowrk interface pointer + * + * This function is called by ROUTER_DELIF ioctl call + * to deallocate the network interface. + * + * The network interface and the private structure are + * about to be deallocated by the upper layer. + * We have to clean and deallocate any allocated memory. + * + */ +static int del_if(wan_device_t *wandev, netdevice_t *dev) +{ + ppp_private_area_t* ppp_priv_area = dev->priv; + + /* Delete interface name from proc fs. */ + wanrouter_proc_delete_interface(wandev, ppp_priv_area->if_name); + return 0; +} + +/*============================================================= + * disable_comm - Main shutdown function + * + * @card: Wanpipe device pointer + * + * The command 'wanrouter stop' has been called + * and the whole wanpipe device is going down. + * This is the last function called to disable + * all comunications and deallocate any memory + * that is still allocated. + * + * o Disable communications, turn off interrupts + * o Deallocate memory used + * o Unconfigure TE1 card + */ + +static void disable_comm (sdla_t *card) +{ + unsigned long smp_flags; + + wan_spin_lock_irq(&card->wandev.lock,&smp_flags); + ppp_comm_disable_shutdown(card); + wan_spin_unlock_irq(&card->wandev.lock,&smp_flags); + + /* TE1 unconfiging */ + if (IS_TE1_CARD(card)) { + if (card->wandev.fe_iface.unconfig){ + card->wandev.fe_iface.unconfig(&card->fe); + } + } + return; +} + +/****** Network Device Interface ********************************************/ + +/*============================================================================ + * Initialize Linux network interface. + * + * This routine is called only once for each interface, during Linux network + * interface registration. Returning anything but zero will fail interface + * registration. + */ +static int if_init(netdevice_t *dev) +{ + ppp_private_area_t *ppp_priv_area = dev->priv; + sdla_t *card = ppp_priv_area->card; + wan_device_t *wandev = &card->wandev; + + /* Initialize device driver entry points */ + dev->open = &if_open; + dev->stop = &if_close; + dev->hard_header = NULL; + dev->rebuild_header = NULL; + dev->hard_start_xmit = &if_send; + dev->get_stats = &if_stats; +#if defined(LINUX_2_4)||defined(LINUX_2_6) + dev->tx_timeout = &if_tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; +#endif + + if (ppp_priv_area->common.usedby == BRIDGE || + ppp_priv_area->common.usedby == BRIDGE_NODE){ + + /* Setup the interface for Bridging */ + int hw_addr=0; + ether_setup(dev); + + /* Use a random number to generate the MAC address */ + memcpy(dev->dev_addr, "\x00\xFC\x00\x00\x00\x00", 6); + get_random_bytes(&hw_addr, sizeof(hw_addr)); + *(int *)(dev->dev_addr + 2) += hw_addr; + + }else{ + /* Initialize media-specific parameters */ + dev->type = ARPHRD_PPP; /* ARP h/w type */ + dev->flags |= IFF_POINTOPOINT; + dev->flags |= IFF_NOARP; + + /* Enable Mulitcasting if specified by user*/ + if (ppp_priv_area->mc == WANOPT_YES){ + dev->flags |= IFF_MULTICAST; + } + + dev->mtu = wandev->mtu; + dev->hard_header_len = 0; /* media header length */ + } + + /* Initialize hardware parameters (just for reference) */ + dev->irq = wandev->irq; + dev->dma = wandev->dma; + dev->base_addr = wandev->ioport; + card->hw_iface.getcfg(card->hw, SDLA_MEMBASE, &dev->mem_start); + card->hw_iface.getcfg(card->hw, SDLA_MEMEND, &dev->mem_end); + + /* Set transmit buffer queue length */ + dev->tx_queue_len = 100; + + /* SNMP */ + dev->do_ioctl = if_do_ioctl; + + return 0; +} + +/*============================================================================ + * Open network interface. + * o enable communications and interrupts. + * o prevent module from unloading by incrementing use count + * + * Return 0 if O.k. or errno. + */ +static int if_open (netdevice_t *dev) +{ + ppp_private_area_t *ppp_priv_area = dev->priv; + sdla_t *card = ppp_priv_area->card; + struct timeval tv; + + if (open_dev_check(dev)) + return -EBUSY; + + wanpipe_open(card); + + netif_start_queue(dev); + + do_gettimeofday( &tv ); + ppp_priv_area->router_start_time = tv.tv_sec; + + /* We cannot configure the card here because we don't + * have access to the interface IP addresses. + * Once the interface initilization is complete, we will be + * able to access the IP addresses. Therefore, + * configure the ppp link in the poll routine */ + set_bit(0,&ppp_priv_area->config_ppp); + ppp_priv_area->config_wait_timeout=jiffies; + + /* Start the PPP configuration after 1sec delay. + * This will give the interface initilization time + * to finish its configuration */ + del_timer(&ppp_priv_area->poll_delay_timer); + ppp_priv_area->poll_delay_timer.expires = jiffies+HZ; + add_timer(&ppp_priv_area->poll_delay_timer); + return 0; +} + +/*============================================================================ + * Close network interface. + * o if this is the last open, then disable communications and interrupts. + * o reset flags. + */ +static int if_close(netdevice_t *dev) +{ + ppp_private_area_t *ppp_priv_area = dev->priv; + sdla_t *card = ppp_priv_area->card; + + stop_net_queue(dev); +#if defined(LINUX_2_1) + dev->start=0; +#endif + wanpipe_close(card); + + del_timer (&ppp_priv_area->poll_delay_timer); + return 0; +} + +/*============================================================================ + * Handle transmit timeout event from netif watchdog + */ +static void if_tx_timeout (netdevice_t *dev) +{ + ppp_private_area_t* chan = dev->priv; + sdla_t *card = chan->card; + + /* If our device stays busy for at least 5 seconds then we will + * kick start the device by making dev->tbusy = 0. We expect + * that our device never stays busy more than 5 seconds. So this + * is only used as a last resort. + */ + + ++ chan->if_send_stat.if_send_tbusy; + ++card->wandev.stats.collisions; + + printk (KERN_INFO "%s: Transmit timed out on %s\n", card->devname,dev->name); + ++chan->if_send_stat.if_send_tbusy_timeout; + netif_wake_queue (dev); +} + + + +/*============================================================================ + * Send a packet on a network interface. + * o set tbusy flag (marks start of the transmission) to block a timer-based + * transmit from overlapping. + * o check link state. If link is not up, then drop the packet. + * o execute adapter send command. + * o free socket buffer + * + * Return: 0 complete (socket buffer must be freed) + * non-0 packet may be re-transmitted (tbusy must be set) + * + * Notes: + * 1. This routine is called either by the protocol stack or by the "net + * bottom half" (with interrupts enabled). + * 2. Setting tbusy flag will inhibit further transmit requests from the + * protocol stack and can be used for flow control with protocol layer. + */ +static int if_send (struct sk_buff *skb, netdevice_t *dev) +{ + ppp_private_area_t *ppp_priv_area = dev->priv; + sdla_t *card = ppp_priv_area->card; + unsigned char *sendpacket; + unsigned long smp_flags; + int udp_type; + int err=0; + + ++ppp_priv_area->if_send_stat.if_send_entry; + + netif_stop_queue(dev); + + if (skb == NULL) { + + /* If we get here, some higher layer thinks we've missed an + * tx-done interrupt. + */ + printk(KERN_INFO "%s: interface %s got kicked!\n", + card->devname, dev->name); + + ++ppp_priv_area->if_send_stat.if_send_skb_null; + + wake_net_dev(dev); + return 0; + } + +#if defined(LINUX_2_1) + if (dev->tbusy) { + ++ppp_priv_area->if_send_stat.if_send_tbusy; + ++card->wandev.stats.collisions; + + if ((jiffies - ppp_priv_area->tick_counter) < (5*HZ)) { + return 1; + } + + if_tx_timeout(dev); + } +#endif + + sendpacket = skb->data; + + udp_type = udp_pkt_type( skb, card ); + + + if (udp_type == UDP_PTPIPE_TYPE){ + + if(store_udp_mgmt_pkt(UDP_PKT_FRM_STACK, card, skb, dev, + ppp_priv_area)){ + card->hw_iface.set_bit(card->hw, card->intr_perm_off, PPP_INTR_TIMER); + } + ++ppp_priv_area->if_send_stat.if_send_PIPE_request; + start_net_queue(dev); + return 0; + } + + /* Check for broadcast and multicast addresses + * If found, drop (deallocate) a packet and return. + */ + if(chk_bcast_mcast_addr(card, dev, skb)){ + ++card->wandev.stats.tx_dropped; + wan_dev_kfree_skb(skb,FREE_WRITE); + start_net_queue(dev); + return 0; + } + + + if(card->type != SDLA_S514){ + s508_lock(card,&smp_flags); + } + + if (test_and_set_bit(SEND_CRIT, (void*)&card->wandev.critical)) { + + printk(KERN_INFO "%s: Critical in if_send: %lx\n", + card->wandev.name,card->wandev.critical); + + ++card->wandev.stats.tx_dropped; + ++ppp_priv_area->if_send_stat.if_send_critical_non_ISR; + start_net_queue(dev); + goto if_send_exit_crit; + } + + if (card->wandev.state != WAN_CONNECTED) { + + ++ppp_priv_area->if_send_stat.if_send_wan_disconnected; + ++card->wandev.stats.tx_dropped; + start_net_queue(dev); + + } else if (!skb->protocol) { + ++ppp_priv_area->if_send_stat.if_send_protocol_error; + ++card->wandev.stats.tx_errors; + start_net_queue(dev); + + } else { + + /*If it's IPX change the network numbers to 0 if they're ours.*/ + if( skb->protocol == htons(ETH_P_IPX) ) { + if(ppp_priv_area->enable_IPX) { + switch_net_numbers( skb->data, + ppp_priv_area->network_number, 0); + } else { + ++card->wandev.stats.tx_dropped; + start_net_queue(dev); + goto if_send_exit_crit; + } + } + + err=ppp_send(card, skb->data, skb->len, skb->protocol); + + if (err) { + err=-1; + stop_net_queue(dev); + ++ppp_priv_area->if_send_stat.if_send_adptr_bfrs_full; + ++ppp_priv_area->if_send_stat.if_send_tx_int_enabled; + }else{ + ++ppp_priv_area->if_send_stat.if_send_bfr_passed_to_adptr; + ++card->wandev.stats.tx_packets; + card->wandev.stats.tx_bytes += skb->len; + start_net_queue(dev); +#if defined(LINUX_2_4)||defined(LINUX_2_6) + dev->trans_start = jiffies; +#endif + } + } + +if_send_exit_crit: + + if (err==0){ + wan_dev_kfree_skb(skb, FREE_WRITE); + }else{ + ppp_priv_area->tick_counter = jiffies; + card->hw_iface.set_bit(card->hw, card->intr_perm_off, PPP_INTR_TXRDY); + } + + clear_bit(SEND_CRIT,&card->wandev.critical); + if(card->type != SDLA_S514){ + s508_unlock(card,&smp_flags); + } + + return err; +} + +/** + * if_do_ioctl - Ioctl handler for fr + * @dev: Device subject to ioctl + * @ifr: Interface request block from the user + * @cmd: Command that is being issued + * + * This function handles the ioctls that may be issued by the user + * to control the settings of a FR. It does both busy + * and security checks. This function is intended to be wrapped by + * callers who wish to add additional ioctl calls of their own. + */ +/* SNMP */ +static int if_do_ioctl(netdevice_t *dev, struct ifreq *ifr, int cmd) +{ + ppp_private_area_t* chan= (ppp_private_area_t*)dev->priv; + unsigned long smp_flags; + sdla_t *card; + wan_udp_pkt_t *wan_udp_pkt; + + if (!chan){ + return -ENODEV; + } + card=chan->card; + + NET_ADMIN_CHECK(); + + switch(cmd) + { + case SIOC_WANPIPE_SNMP: + case SIOC_WANPIPE_SNMP_IFSPEED: + return wan_snmp_data(card, dev, cmd, ifr); + + + case SIOC_WANPIPE_PIPEMON: + + if (atomic_read(&chan->udp_pkt_len) != 0){ + return -EBUSY; + } + + atomic_set(&chan->udp_pkt_len,MAX_LGTH_UDP_MGNT_PKT); + + /* For performance reasons test the critical + * here before spin lock */ + if (test_bit(0,&card->in_isr)){ + atomic_set(&chan->udp_pkt_len,0); + return -EBUSY; + } + + wan_udp_pkt=(wan_udp_pkt_t*)chan->udp_pkt_data; + if (copy_from_user(&wan_udp_pkt->wan_udp_hdr,ifr->ifr_data,MAX_LGTH_UDP_MGNT_PKT)){ + atomic_set(&chan->udp_pkt_len,0); + return -EFAULT; + } + + spin_lock_irqsave(&card->wandev.lock, smp_flags); + + /* We have to check here again because we don't know + * what happened during spin_lock */ + if (test_bit(0,&card->in_isr)){ + printk(KERN_INFO "%s:%s Pipemon failed, driver busy: try again.\n", + card->devname,dev->name); + atomic_set(&chan->udp_pkt_len,0); + spin_unlock_irqrestore(&card->wandev.lock, smp_flags); + return -EBUSY; + } + + process_udp_mgmt_pkt(card,dev,chan,1); + + spin_unlock_irqrestore(&card->wandev.lock, smp_flags); + + /* This area will still be critical to other + * PIPEMON commands due to udp_pkt_len + * thus we can release the irq */ + + if (atomic_read(&chan->udp_pkt_len) > MAX_LGTH_UDP_MGNT_PKT){ + printk(KERN_INFO "%s: Error, pipemon buf too big on the way up! %i\n", + card->devname,atomic_read(&chan->udp_pkt_len)); + atomic_set(&chan->udp_pkt_len,0); + return -EINVAL; + } + + if (copy_to_user(ifr->ifr_data,&wan_udp_pkt->wan_udp_hdr,sizeof(wan_udp_hdr_t))){ + atomic_set(&chan->udp_pkt_len,0); + return -EFAULT; + } + + atomic_set(&chan->udp_pkt_len,0); + return 0; + + + default: + return -EOPNOTSUPP; + } + return 0; +} + +/*============================================================================= + * Store a UDP management packet for later processing. + */ + +static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, + struct sk_buff *skb, netdevice_t* dev, + ppp_private_area_t* ppp_priv_area ) +{ + int udp_pkt_stored = 0; + + if(!atomic_read(&ppp_priv_area->udp_pkt_len) && (skb->len<=MAX_LGTH_UDP_MGNT_PKT)){ + atomic_set(&ppp_priv_area->udp_pkt_len,skb->len); + ppp_priv_area->udp_pkt_src = udp_pkt_src; + + memcpy(ppp_priv_area->udp_pkt_data, skb->data, skb->len); + ppp_priv_area->timer_int_enabled |= TMR_INT_ENABLED_UDP; + + ppp_priv_area->protocol = skb->protocol; + udp_pkt_stored = 1; + }else{ + if (skb->len > MAX_LGTH_UDP_MGNT_PKT){ + printk(KERN_INFO "%s: Pipemon UDP request too long : %i\n", + card->devname, skb->len); + }else{ + printk(KERN_INFO "%s: Pipemon UPD request already pending\n", + card->devname); + } + } + + if(udp_pkt_src == UDP_PKT_FRM_STACK){ + wan_dev_kfree_skb(skb, FREE_WRITE); + }else{ + wan_dev_kfree_skb(skb, FREE_READ); + } + + return(udp_pkt_stored); +} + + + +/*============================================================================ + * Reply to UDP Management system. + * Return length of reply. + */ +static int reply_udp( unsigned char *data, unsigned int mbox_len ) +{ + unsigned short len, udp_length, temp, ip_length; + unsigned long ip_temp; + int even_bound = 0; + wan_udp_pkt_t *p_udp_pkt = (wan_udp_pkt_t *)data; + + /* Set length of packet */ + len = sizeof(struct iphdr)+ + sizeof(struct udphdr)+ + sizeof(wan_mgmt_t)+ + sizeof(wan_cmd_t)+ + mbox_len; + + /* fill in UDP reply */ + p_udp_pkt->wan_udp_request_reply = UDPMGMT_REPLY; + + /* fill in UDP length */ + udp_length = sizeof(struct udphdr)+ + sizeof(wan_mgmt_t)+ + sizeof(wan_cmd_t)+ + mbox_len; + + + /* put it on an even boundary */ + if ( udp_length & 0x0001 ) { + udp_length += 1; + len += 1; + even_bound=1; + } + + temp = (udp_length<<8)|(udp_length>>8); + p_udp_pkt->wan_udp_len = temp; + + + /* swap UDP ports */ + temp = p_udp_pkt->wan_udp_sport; + p_udp_pkt->wan_udp_sport = + p_udp_pkt->wan_udp_dport; + p_udp_pkt->wan_udp_dport = temp; + + + /* add UDP pseudo header */ + temp = 0x1100; + *((unsigned short *)(p_udp_pkt->wan_udp_data+mbox_len+even_bound)) = temp; + temp = (udp_length<<8)|(udp_length>>8); + *((unsigned short *)(p_udp_pkt->wan_udp_data+mbox_len+even_bound+2)) = temp; + + /* calculate UDP checksum */ + p_udp_pkt->wan_udp_sum = 0; + p_udp_pkt->wan_udp_sum = + calc_checksum(&data[UDP_OFFSET],udp_length+UDP_OFFSET); + + /* fill in IP length */ + ip_length = udp_length + sizeof(struct iphdr); + temp = (ip_length<<8)|(ip_length>>8); + p_udp_pkt->wan_ip_len = temp; + + /* swap IP addresses */ + ip_temp = p_udp_pkt->wan_ip_src; + p_udp_pkt->wan_ip_src = p_udp_pkt->wan_ip_dst; + p_udp_pkt->wan_ip_dst = ip_temp; + + /* fill in IP checksum */ + p_udp_pkt->wan_ip_sum = 0; + p_udp_pkt->wan_ip_sum = calc_checksum(data,sizeof(struct iphdr)); + + return len; + +} /* reply_udp */ + +unsigned short calc_checksum (char *data, int len) +{ + unsigned short temp; + unsigned long sum=0; + int i; + + for( i = 0; i > 16 ) { + sum = (sum & 0xffffUL) + (sum >> 16); + } + + temp = (unsigned short)sum; + temp = ~temp; + + if( temp == 0 ) + temp = 0xffff; + + return temp; +} + +/* + If incoming is 0 (outgoing)- if the net numbers is ours make it 0 + if incoming is 1 - if the net number is 0 make it ours + +*/ +static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming) +{ + unsigned long pnetwork_number; + + pnetwork_number = (unsigned long)((sendpacket[6] << 24) + + (sendpacket[7] << 16) + (sendpacket[8] << 8) + + sendpacket[9]); + + if (!incoming) { + //If the destination network number is ours, make it 0 + if( pnetwork_number == network_number) { + sendpacket[6] = sendpacket[7] = sendpacket[8] = + sendpacket[9] = 0x00; + } + } else { + //If the incoming network is 0, make it ours + if( pnetwork_number == 0) { + sendpacket[6] = (unsigned char)(network_number >> 24); + sendpacket[7] = (unsigned char)((network_number & + 0x00FF0000) >> 16); + sendpacket[8] = (unsigned char)((network_number & + 0x0000FF00) >> 8); + sendpacket[9] = (unsigned char)(network_number & + 0x000000FF); + } + } + + + pnetwork_number = (unsigned long)((sendpacket[18] << 24) + + (sendpacket[19] << 16) + (sendpacket[20] << 8) + + sendpacket[21]); + + if( !incoming ) { + //If the source network is ours, make it 0 + if( pnetwork_number == network_number) { + sendpacket[18] = sendpacket[19] = sendpacket[20] = + sendpacket[21] = 0x00; + } + } else { + //If the source network is 0, make it ours + if( pnetwork_number == 0 ) { + sendpacket[18] = (unsigned char)(network_number >> 24); + sendpacket[19] = (unsigned char)((network_number & + 0x00FF0000) >> 16); + sendpacket[20] = (unsigned char)((network_number & + 0x0000FF00) >> 8); + sendpacket[21] = (unsigned char)(network_number & + 0x000000FF); + } + } +} /* switch_net_numbers */ + +/*============================================================================ + * Get ethernet-style interface statistics. + * Return a pointer to struct net_device_stats. + */ +static struct net_device_stats *if_stats(netdevice_t *dev) +{ + + ppp_private_area_t *ppp_priv_area = dev->priv; + sdla_t* card; + + if( ppp_priv_area == NULL ) + return NULL; + + card = ppp_priv_area->card; + return &card->wandev.stats; +} + + +/****** PPP Firmware Interface Functions ************************************/ + +/*============================================================================ + * Read TE1/56K Front end registers + */ +//static unsigned char read_front_end_reg (void* card1, unsigned short reg) +static unsigned char read_front_end_reg (void* card1, ...) +{ + va_list args; + sdla_t *card = (sdla_t*)card1; + wan_mbox_t *mb = &card->wan_mbox; + char *data = mb->wan_data; + u16 reg; + int err; + + va_start(args, card1); + reg = (u16)va_arg(args, int); + va_end(args); + + ((FRONT_END_REG_STRUCT *)data)->register_number = (unsigned short)reg; + mb->wan_data_len = sizeof(FRONT_END_REG_STRUCT); + mb->wan_command = READ_FRONT_END_REGISTER; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != CMD_OK) + ppp_error(card,err,mb); + + return(((FRONT_END_REG_STRUCT *)data)->register_value); +} + +/*============================================================================ + * Write to TE1/56K Front end registers + */ +//static unsigned char write_front_end_reg (void* card1, unsigned short reg, unsigned char value) +static int write_front_end_reg (void* card1, ...) +{ + va_list args; + sdla_t *card = (sdla_t*)card1; + wan_mbox_t *mb = &card->wan_mbox; + char *data = mb->wan_data; + u16 reg; + u8 value; + int err; + int retry=15; + + va_start(args, card1); + reg = (u16)va_arg(args, int); + value = (u8)va_arg(args, int); + va_end(args); + + do { + ((FRONT_END_REG_STRUCT *)data)->register_number = (unsigned short)reg; + ((FRONT_END_REG_STRUCT *)data)->register_value = value; + mb->wan_data_len = sizeof(FRONT_END_REG_STRUCT); + mb->wan_command = WRITE_FRONT_END_REGISTER; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != CMD_OK){ + ppp_error(card,err,mb); + } + }while(err && --retry); + + return err; +} + + +/*============================================================================ + * Enable timer interrupt + */ +static void ppp_enable_timer (void* card_id) +{ + netdevice_t *dev; + sdla_t* card = (sdla_t*)card_id; + ppp_private_area_t* ppp_priv_area; + + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + if (!dev || !wan_netif_priv(dev)) + return; + + ppp_priv_area = wan_netif_priv(dev); + ppp_priv_area->timer_int_enabled |= TMR_INT_ENABLED_TE; + card->hw_iface.set_bit(card->hw, card->intr_perm_off, PPP_INTR_TIMER); + return; +} + +/*============================================================================ + * Read firmware code version. + * Put code version as ASCII string in str. + */ +static int ppp_read_version(sdla_t *card, char *str) +{ + wan_mbox_t *mb = &card->wan_mbox; + int err; + + memset(&mb->wan_cmd, 0, sizeof(ppp_cmd_t)); + mb->wan_command = PPP_READ_CODE_VERSION; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + + if (err != CMD_OK) + + ppp_error(card, err, mb); + + else if (str) { + + int len = mb->wan_data_len; + + memcpy(str, mb->wan_data, len); + str[len] = '\0'; + + } + + return err; +} +/*=========================================================================== + * Set Out-Bound Authentication. +*/ +static int ppp_set_outbnd_auth (sdla_t *card, ppp_private_area_t *ppp_priv_area) +{ + wan_mbox_t *mb = &card->wan_mbox; + int err; + + memset(&mb->wan_cmd, 0, sizeof(ppp_cmd_t)); + memset(&mb->wan_data, 0, (strlen(ppp_priv_area->sysname) + strlen(ppp_priv_area->userid) + + strlen(ppp_priv_area->passwd) + 3)); + memcpy(mb->wan_data, ppp_priv_area->sysname, strlen(ppp_priv_area->sysname)); + memcpy((mb->wan_data + strlen(ppp_priv_area->sysname) + 1), + ppp_priv_area->userid, strlen(ppp_priv_area->userid)); + memcpy((mb->wan_data + strlen(ppp_priv_area->sysname) + strlen(ppp_priv_area->userid) + 2), + ppp_priv_area->passwd, strlen(ppp_priv_area->passwd)); + + mb->wan_data_len = strlen(ppp_priv_area->sysname) + strlen(ppp_priv_area->userid) + + strlen(ppp_priv_area->passwd) + 3 ; + + mb->wan_command = PPP_SET_OUTBOUND_AUTH; + + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + + if (err != CMD_OK) + ppp_error(card, err, mb); + + return err; +} + +/*=========================================================================== + * Set In-Bound Authentication. +*/ +static int ppp_set_inbnd_auth (sdla_t *card, ppp_private_area_t *ppp_priv_area) +{ + wan_mbox_t *mb = &card->wan_mbox; + int err, i; + char* user_tokens[32]; + char* pass_tokens[32]; + int userids, passwds; + int add_ptr; + + memset(&mb->wan_cmd, 0, sizeof(ppp_cmd_t)); + memset(&mb->wan_data, 0, 1008); + memcpy(mb->wan_data, ppp_priv_area->sysname, + strlen(ppp_priv_area->sysname)); + + /* Parse the userid string and the password string and build a string + to copy it to the data area of the command structure. The string + will look like "SYS_NAMEUSER1PASS1USER2PASS2 + .... " + */ + userids = tokenize(ppp_priv_area->userid, user_tokens); + passwds = tokenize(ppp_priv_area->passwd, pass_tokens); + + if (userids != passwds){ + printk(KERN_INFO "%s: Number of passwords does not equal the number of user ids\n", + card->devname); + return 1; + } + + add_ptr = strlen(ppp_priv_area->sysname) + 1; + for (i=0; iwan_data + add_ptr), user_tokens[i], + strlen(user_tokens[i])); + memcpy((mb->wan_data + add_ptr + strlen(user_tokens[i]) + 1), + pass_tokens[i], strlen(pass_tokens[i])); + add_ptr = add_ptr + strlen(user_tokens[i]) + 1 + + strlen(pass_tokens[i]) + 1; + } + + mb->wan_data_len = add_ptr + 1; + mb->wan_command = PPP_SET_INBOUND_AUTH; + + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + + if (err != CMD_OK) + ppp_error(card, err, mb); + + return err; +} + + +/*============================================================================ + * Tokenize string. + * Parse a string of the following syntax: + * ,,... + * and fill array of tokens with pointers to string elements. + * + */ +static int tokenize (char *str, char **tokens) +{ + int cnt = 0; + tokens[0] = strsep(&str, "/"); + while (tokens[cnt] && (cnt < 32 - 1)) + { + tokens[cnt] = strstrip(tokens[cnt], " \t"); + tokens[++cnt] = strsep(&str, "/"); + } + return cnt; +} + +/*============================================================================ + * Strip leading and trailing spaces off the string str. + */ +static char* strstrip (char *str, char* s) +{ + char *eos = str + strlen(str); /* -> end of string */ + + while (*str && strchr(s, *str)) + ++str /* strip leading spaces */ + ; + while ((eos > str) && strchr(s, *(eos - 1))) + --eos /* strip trailing spaces */ + ; + *eos = '\0'; + return str; +} +/*============================================================================ + * Configure PPP firmware. + */ +static int ppp_configure(sdla_t *card, void *data) +{ + wan_mbox_t *mb = &card->wan_mbox; + int data_len = sizeof(ppp508_conf_t); + int err; + + memset(&mb->wan_cmd, 0, sizeof(ppp_cmd_t)); + memcpy(mb->wan_data, data, data_len); + mb->wan_data_len = data_len; + mb->wan_command = PPP_SET_CONFIG; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + + if (err != CMD_OK) + ppp_error(card, err, mb); + + return err; +} + +/*============================================================================ + * Set interrupt mode. + */ +static int ppp_set_intr_mode(sdla_t *card, unsigned char mode) +{ + wan_mbox_t *mb = &card->wan_mbox; + ppp_intr_info_t *ppp_intr_data = (ppp_intr_info_t *) &mb->wan_data[0]; + int err; + + memset(&mb->wan_cmd, 0, sizeof(ppp_cmd_t)); + ppp_intr_data->i_enable = mode; + + ppp_intr_data->irq = card->wandev.irq; // ALEX_TODAY card->hw.irq; + mb->wan_data_len = 2; + + /* If timer has been enabled, set the timer delay to 1sec */ + if (mode & 0x80){ + ppp_intr_data->timer_len = 20; //5;//100; //250; + mb->wan_data_len = 4; + } + + mb->wan_command = PPP_SET_INTR_FLAGS; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + + if (err != CMD_OK) + ppp_error(card, err, mb); + + + return err; +} + +/*============================================================================ + * Enable communications. + */ +static int ppp_comm_enable(sdla_t *card) +{ + wan_mbox_t *mb = &card->wan_mbox; + int err; + + memset(&mb->wan_cmd, 0, sizeof(ppp_cmd_t)); + mb->wan_command = PPP_COMM_ENABLE; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + + if (err != CMD_OK) + ppp_error(card, err, mb); + else + card->u.p.comm_enabled = 1; + + return err; +} + +/*============================================================================ + * Disable communications. + */ +static int ppp_comm_disable(sdla_t *card) +{ + wan_mbox_t *mb = &card->wan_mbox; + int err; + + memset(&mb->wan_cmd, 0, sizeof(ppp_cmd_t)); + mb->wan_command = PPP_COMM_DISABLE; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != CMD_OK) + ppp_error(card, err, mb); + else + card->u.p.comm_enabled = 0; + + return err; +} + +static int ppp_comm_disable_shutdown(sdla_t *card) +{ + wan_mbox_t *mb = &card->wan_mbox; + ppp_intr_info_t *ppp_intr_data; + int err; + + if (!mb){ + return 1; + } + + ppp_intr_data = (ppp_intr_info_t *) &mb->wan_data[0]; + + /* Disable all interrupts */ + memset(&mb->wan_cmd, 0, sizeof(ppp_cmd_t)); + ppp_intr_data->i_enable = 0; + + ppp_intr_data->irq = card->wandev.irq; // ALEX_TODAY card->hw.irq; + mb->wan_data_len = 2; + + mb->wan_command = PPP_SET_INTR_FLAGS; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + + /* Disable communicatinons */ + memset(&mb->wan_cmd, 0, sizeof(ppp_cmd_t)); + mb->wan_command = PPP_COMM_DISABLE; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + + card->u.p.comm_enabled = 0; + + return 0; +} + + + +/*============================================================================ + * Get communications error statistics. + */ +static int ppp_get_err_stats(sdla_t *card) +{ + wan_mbox_t *mb = &card->wan_mbox; + int err; + + memset(&mb->wan_cmd, 0, sizeof(ppp_cmd_t)); + mb->wan_command = PPP_READ_ERROR_STATS; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + + if (err == CMD_OK) { + + ppp_err_stats_t* stats = (void*)mb->wan_data; + card->wandev.stats.rx_over_errors = stats->rx_overrun; + card->wandev.stats.rx_crc_errors = stats->rx_bad_crc; + card->wandev.stats.rx_missed_errors = stats->rx_abort; + card->wandev.stats.rx_length_errors = stats->rx_lost; + card->wandev.stats.tx_aborted_errors = stats->tx_abort; + + } else + ppp_error(card, err, mb); + + return err; +} + +/*============================================================================ + * Get communications error statistics. + */ +#if 0 +static int ppp_get_stats(sdla_t *card) +{ + wan_mbox_t *mb = card->mbox; + int err; + + memset(&mb->wan_cmd, 0, sizeof(ppp_cmd_t)); + mb->wan_command = PPP_READ_STATISTICS; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != WAN_CMD_OK){ + ppp_error(card, err, mb); + } + + return err; +} +#endif + +static int ppp_get_pkt_stats(sdla_t* card) +{ + wan_mbox_t *mb = &card->wan_mbox; + int err; + + memset(&mb->wan_cmd, 0, sizeof(ppp_cmd_t)); + mb->wan_command = PPP_READ_PACKET_STATS; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != WAN_CMD_OK){ + ppp_error(card, err, mb); + } + return err; +} + +static int ppp_get_lcp_stats(sdla_t* card) +{ + wan_mbox_t *mb = &card->wan_mbox; + int err; + + memset(&mb->wan_cmd, 0, sizeof(ppp_cmd_t)); + mb->wan_command = PPP_READ_LCP_STATS; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != WAN_CMD_OK){ + ppp_error(card, err, mb); + } + return err; +} + +/*============================================================================ + * Send packet. + * Return: 0 - o.k. + * 1 - no transmit buffers available + */ +static int ppp_send (sdla_t *card, void *data, unsigned len, unsigned proto) +{ + ppp_buf_ctl_t txbuf; + + card->hw_iface.peek(card->hw, card->u.p.txbuf_off, &txbuf, sizeof(txbuf)); + if (txbuf.flag) + return 1; + + card->hw_iface.poke(card->hw, txbuf.buf.ptr, data, len); + + txbuf.length = len; /* frame length */ + if (proto == htons(ETH_P_IPX)){ + txbuf.proto = 0x01; /* protocol ID */ + }else{ + txbuf.proto = 0x00; /* protocol ID */ + } + card->hw_iface.poke(card->hw, card->u.p.txbuf_off, &txbuf, sizeof(txbuf)); + + txbuf.flag = 1; /* start transmission */ + card->hw_iface.poke(card->hw, card->u.p.txbuf_off, &txbuf, sizeof(txbuf)); + + /* Update transmit buffer control fields */ + card->u.p.txbuf_off += sizeof(txbuf); + + if (card->u.p.txbuf_off > card->u.p.txbuf_last_off) + card->u.p.txbuf_off = card->u.p.txbuf_base_off; + return 0; +} + +/****** Firmware Error Handler **********************************************/ + +/*============================================================================ + * Firmware error handler. + * This routine is called whenever firmware command returns non-zero + * return code. + * + * Return zero if previous command has to be cancelled. + */ +static int ppp_error(sdla_t *card, int err, wan_mbox_t *mb) +{ + unsigned cmd = mb->wan_command; + + switch (err) { + + case CMD_TIMEOUT: + printk(KERN_INFO "%s: command 0x%02X timed out!\n", + card->devname, cmd); + break; + + default: + printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n" + , card->devname, cmd, err); + } + + return 0; +} + +/****** Interrupt Handlers **************************************************/ +/*============================================================================ + * PPP interrupt service routine. + */ +static void wpp_isr (sdla_t *card) +{ + ppp_flags_t flags; + netdevice_t *dev; + int i; + + if (!card->hw){ + return; + } + + set_bit(0,&card->in_isr); + ++card->statistics.isr_entry; + + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + + card->hw_iface.peek(card->hw, card->flags_off, &flags, sizeof(flags)); + if (!dev && flags.iflag != PPP_INTR_CMD){ + goto wpp_isr_done; + } + + if (test_bit(PERI_CRIT, (void*)&card->wandev.critical)) { + goto wpp_isr_done; + } + + + if(card->type != SDLA_S514){ + if (test_bit(SEND_CRIT, (void*)&card->wandev.critical)) { + ++card->statistics.isr_already_critical; + printk (KERN_INFO "%s: Critical while in ISR!\n", + card->devname); + goto wpp_isr_done; + } + } + + switch (flags.iflag) { + + case PPP_INTR_RXRDY: /* receive interrupt 0x01 (bit 0)*/ + ++card->statistics.isr_rx; + rx_intr(card); + break; + + case PPP_INTR_TXRDY: /* transmit interrupt 0x02 (bit 1)*/ + ++card->statistics.isr_tx; + card->hw_iface.clear_bit(card->hw, card->intr_perm_off, PPP_INTR_TXRDY); + wake_net_dev(dev); + break; + + case PPP_INTR_CMD: /* interface command completed */ + ++card->timer_int_enabled; + ++card->statistics.isr_intr_test; + break; + + case PPP_INTR_MODEM: /* modem status change (DCD, CTS) 0x04 (bit 2)*/ + case PPP_INTR_DISC: /* Data link disconnected 0x10 (bit 4)*/ + case PPP_INTR_OPEN: /* Data link open 0x20 (bit 5)*/ + case PPP_INTR_DROP_DTR: /* DTR drop timeout expired 0x40 bit 6 */ + event_intr(card); + break; + + case PPP_INTR_TIMER: + timer_intr(card); + break; + + default: /* unexpected interrupt */ + ++card->statistics.isr_spurious; + printk(KERN_INFO "%s: spurious interrupt 0x%02X!\n", + card->devname, flags.iflag); + printk(KERN_INFO "%s: ID Bytes = ",card->devname); + { + unsigned char str[8]; + card->hw_iface.peek(card->hw, card->intr_type_off + 0x28, str, 8); + for(i = 0; i < 8; i ++){ + printk("0x%02X ", str[i]); + } + } + printk("\n"); + } + +wpp_isr_done: + clear_bit(0,&card->in_isr); + card->hw_iface.poke_byte(card->hw, card->intr_type_off, 0x00); + return; +} + +/*============================================================================ + * Receive interrupt handler. + */ +static void rx_intr(sdla_t *card) +{ + netdevice_t *dev; + ppp_private_area_t *ppp_priv_area; + struct sk_buff *skb; + unsigned len; + void *buf; + int i; + ppp_buf_ctl_t rxbuf; + int udp_type; + + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + + card->hw_iface.peek(card->hw, card->rxmb_off, &rxbuf, sizeof(rxbuf)); + if (rxbuf.flag != 0x01) { + printk(KERN_INFO + "%s: corrupted Rx buffer @ 0x%lX, flag = 0x%02X!\n", + card->devname, card->rxmb_off, rxbuf.flag); + printk(KERN_INFO "%s: ID Bytes = ",card->devname); + { + unsigned char str[8]; + card->hw_iface.peek(card->hw, card->intr_type_off + 0x28, str, 8); + for(i = 0; i < 8; i ++){ + printk(KERN_INFO "0x%02X ", str[i]); + } + } + printk(KERN_INFO "\n"); + + ++card->statistics.rx_intr_corrupt_rx_bfr; + + + /* Bug Fix: Mar 6 2000 + * If we get a corrupted mailbox, it means that driver + * is out of sync with the firmware. There is no recovery. + * If we don't turn off all interrupts for this card + * the machine will crash. + */ + printk(KERN_INFO "%s: Critical router failure ...!!!\n", card->devname); + printk(KERN_INFO "Please contact Sangoma Technologies !\n"); + ppp_set_intr_mode(card,0); + return; + } + + if (dev && is_dev_running(dev) && dev->priv){ + len = rxbuf.length; + ppp_priv_area = dev->priv; + + /* Allocate socket buffer */ + skb = dev_alloc_skb(len+2); + + if (skb != NULL) { + /* Copy data to the socket buffer */ + unsigned addr = rxbuf.buf.ptr; + + if ((addr + len) > card->u.p.rx_top_off + 1) { + unsigned tmp = card->u.p.rx_top_off - addr + 1; + buf = skb_put(skb, tmp); + card->hw_iface.peek(card->hw, addr, buf, tmp); + addr = card->u.p.rx_base_off; + len -= tmp; + } + buf = skb_put(skb, len); + card->hw_iface.peek(card->hw, addr, buf, len); + + /* Decapsulate packet */ + switch (rxbuf.proto) { + case 0x00: + skb->protocol = htons(ETH_P_IP); + break; + + case 0x01: + skb->protocol = htons(ETH_P_IPX); + break; + + default: + skb->protocol = htons(ETH_P_IP); + break; + } + + udp_type = udp_pkt_type( skb, card ); + + if (udp_type == UDP_PTPIPE_TYPE){ + /* Handle a UDP Request in Timer Interrupt */ + if(store_udp_mgmt_pkt(UDP_PKT_FRM_NETWORK, card, skb, dev, + ppp_priv_area)){ + printk(KERN_INFO "Storing Network UDP!\n"); + card->hw_iface.set_bit(card->hw, card->intr_perm_off, PPP_INTR_TIMER); + } + ++ppp_priv_area->rx_intr_stat.rx_intr_PIPE_request; + + } else if (handle_IPXWAN(skb->data,card->devname, + ppp_priv_area->enable_IPX, + ppp_priv_area->network_number, + skb->protocol)) { + + /* Handle an IPXWAN packet */ + if( ppp_priv_area->enable_IPX) { + /* Make sure we are not already sending */ + if (!test_bit(SEND_CRIT, &card->wandev.critical)){ + int err=ppp_send(card, skb->data, skb->len, + htons(ETH_P_IPX)); + if (err != 0){ + ++card->wandev.stats.tx_dropped; + } + }else{ + ++card->wandev.stats.tx_dropped; + } + }else{ + ++card->wandev.stats.rx_dropped; + } + wan_dev_kfree_skb(skb,FREE_READ); + + }else if (ppp_priv_area->common.usedby == BRIDGE || + ppp_priv_area->common.usedby == BRIDGE_NODE){ + + /* Make sure it's an Ethernet frame, otherwise drop it */ + if (skb->len <= ETH_ALEN) { + wan_dev_kfree_skb(skb,FREE_READ); + ++card->wandev.stats.rx_errors; + goto rx_exit; + } + + ++card->wandev.stats.rx_packets; + card->wandev.stats.rx_bytes += skb->len; + ++ppp_priv_area->rx_intr_stat.rx_intr_bfr_passed_to_stack; + + skb->dev = dev; + skb->protocol=eth_type_trans(skb,dev); + netif_rx(skb); + + }else{ + /* Pass data up the protocol stack */ + skb->dev = dev; + skb->mac.raw = skb->data; + + ++card->wandev.stats.rx_packets; + card->wandev.stats.rx_bytes += skb->len; + ++ppp_priv_area->rx_intr_stat.rx_intr_bfr_passed_to_stack; + netif_rx(skb); + } + + } else { + + if (net_ratelimit()){ + printk(KERN_INFO "%s: no socket buffers available!\n", + card->devname); + } + ++card->wandev.stats.rx_dropped; + ++ppp_priv_area->rx_intr_stat.rx_intr_no_socket; + } + + } else { + ++card->statistics.rx_intr_dev_not_started; + } + +rx_exit: + /* Release buffer element and calculate a pointer to the next one */ + rxbuf.flag = 0x00; + card->hw_iface.poke(card->hw, card->rxmb_off, &rxbuf, sizeof(rxbuf)); + card->rxmb_off += sizeof(rxbuf); + if (card->rxmb_off > card->u.p.rxbuf_last_off) + card->rxmb_off = card->u.p.rxbuf_base_off; +} + + +void event_intr (sdla_t *card) +{ + netdevice_t *dev; + ppp_private_area_t *ppp_priv_area; + ppp_flags_t flags; + + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + if (!dev || !wan_netif_priv(dev)) + return; + ppp_priv_area = wan_netif_priv(dev); + + card->hw_iface.peek(card->hw, card->flags_off, &flags, sizeof(flags)); + switch (flags.iflag){ + + case PPP_INTR_MODEM: /* modem status change (DCD, CTS) 0x04 (bit 2)*/ + + if (IS_56K_CARD(card)) { + FRONT_END_STATUS_STRUCT FE_status; + unsigned long FE_status_off = 0xF020; + card->hw_iface.peek(card->hw, FE_status_off, &FE_status, sizeof(FE_status)); + card->fe.fe_param.k56_param.RR8_reg_56k = + FE_status.FE_U.stat_56k.RR8_56k; + card->fe.fe_param.k56_param.RRA_reg_56k = + FE_status.FE_U.stat_56k.RRA_56k; + card->fe.fe_param.k56_param.RRC_reg_56k = + FE_status.FE_U.stat_56k.RRC_56k; + card->wandev.fe_iface.read_alarm(&card->fe, 0); + + FE_status.opp_flag = 0x01; + card->hw_iface.poke(card->hw, FE_status_off, &FE_status, sizeof(FE_status)); + ppp_handle_front_end_state(card); + break; + } + + if (IS_TE1_CARD(card)) { + FRONT_END_STATUS_STRUCT FE_status; + unsigned long FE_status_off = 0xF020; + card->hw_iface.peek(card->hw, FE_status_off, &FE_status, sizeof(FE_status)); + + /* TE_INTR */ + card->wandev.fe_iface.isr(&card->fe); + FE_status.opp_flag = 0x01; + card->hw_iface.poke(card->hw, FE_status_off, &FE_status, sizeof(FE_status)); + ppp_handle_front_end_state(card); + break; + } + if (flags.mstatus == 0x28){ + card->fe.fe_status = FE_CONNECTED; + }else{ + card->fe.fe_status = FE_DISCONNECTED; + } + + if (net_ratelimit()){ + printk (KERN_INFO "\n"); + printk (KERN_INFO "%s: Modem status: DCD=%s CTS=%s\n", + card->devname, DCD(flags.mstatus), CTS(flags.mstatus)); + } + + ppp_handle_front_end_state(card); + break; + + case PPP_INTR_DISC: /* Data link disconnected 0x10 (bit 4)*/ + + printk (KERN_INFO "\n"); + printk (KERN_INFO "%s: Data link disconnected intr\n", + card->devname); + show_disc_cause(card, flags.disc_cause); + + if (flags.disc_cause & + (PPP_LOCAL_TERMINATION | + PPP_REMOTE_TERMINATION)) { + if (card->u.p.ip_mode == WANOPT_PPP_PEER) { + set_bit(0,&Read_connection_info); + } + ppp_priv_area->ppp_state = WAN_DISCONNECTED; + wanpipe_set_state(card, WAN_DISCONNECTED); + + ppp_priv_area->timer_int_enabled |= TMR_INT_ENABLED_PPP_EVENT; + card->hw_iface.set_bit(card->hw, card->intr_perm_off, PPP_INTR_TIMER); + trigger_ppp_poll(dev); + + /* Start debugging */ + WAN_DEBUG_START(card); + } + break; + + case PPP_INTR_OPEN: /* Data link open 0x20 (bit 5)*/ + + NEX_PRINTK (KERN_INFO "%s: PPP Link Open, LCP=%s IP=%s\n", + card->devname,LCP(flags.lcp_state), + IP(flags.ip_state)); + + if (flags.lcp_state == 0x09 && + (flags.ip_state == 0x09 || flags.ipx_state == 0x09)){ + /* Initialize the polling timer and set the state + * to WAN_CONNNECTED */ + + + /* BUG FIX: When the protocol restarts, during heavy + * traffic, board tx buffers and driver tx buffers + * can go out of sync. This checks the condition + * and if the tx buffers are out of sync, the + * protocols are restarted. + * I don't know why the board tx buffer is out + * of sync. It could be that a packets is tx + * while the link is down, but that is not + * possible. The other possiblility is that the + * firmware doesn't reinitialize properly. + * FIXME: A better fix should be found. + */ + if (detect_and_fix_tx_bug(card)){ + + ppp_comm_disable(card); + + ppp_priv_area->ppp_state = WAN_DISCONNECTED; + wanpipe_set_state(card, WAN_DISCONNECTED); + + ppp_priv_area->timer_int_enabled |= + TMR_INT_ENABLED_PPP_EVENT; + card->hw_iface.set_bit(card->hw, card->intr_perm_off, PPP_INTR_TIMER); + /* Start debugging */ + WAN_DEBUG_START(card); + break; + } + + card->state_tick = jiffies; + ppp_priv_area->ppp_state = WAN_CONNECTED; + + if (card->wandev.ignore_front_end_status == WANOPT_YES || + card->fe.fe_status == FE_CONNECTED){ + u32 tmp; + + wanpipe_set_state(card, WAN_CONNECTED); + + card->hw_iface.peek(card->hw, card->u.p.txbuf_next_off, &tmp, 4); + NEX_PRINTK(KERN_INFO "CON: L Tx: %lx B Tx: %lx || L Rx %lx B Rx %lx\n", + card->u.p.txbuf_off, tmp, + card->rxmb_off, card->u.p.rxbuf_next_off); + + /* Tell timer interrupt that PPP event occured */ + ppp_priv_area->timer_int_enabled |= TMR_INT_ENABLED_PPP_EVENT; + card->hw_iface.set_bit(card->hw, card->intr_perm_off, PPP_INTR_TIMER); + + /* If we are in PEER mode, we must first obtain the + * IP information and then go into the poll routine */ + if (card->u.p.ip_mode != WANOPT_PPP_PEER){ + trigger_ppp_poll(dev); + } + } + } + break; + + case PPP_INTR_DROP_DTR: /* DTR drop timeout expired 0x40 bit 6 */ + + printk (KERN_INFO "\n"); + printk(KERN_INFO "%s: DTR Drop Timeout Interrupt \n",card->devname); + + if (card->u.p.ip_mode == WANOPT_PPP_PEER) { + set_bit(0,&Read_connection_info); + } + + ppp_priv_area->ppp_state = WAN_DISCONNECTED; + wanpipe_set_state(card, WAN_DISCONNECTED); + + ppp_priv_area->timer_int_enabled |= TMR_INT_ENABLED_PPP_EVENT; + show_disc_cause(card, flags.disc_cause); + card->hw_iface.set_bit(card->hw, card->intr_perm_off, PPP_INTR_TIMER); + trigger_ppp_poll(dev); + + /* Start debugging */ + WAN_DEBUG_START(card); + break; + + default: + printk(KERN_INFO "%s: Error, Invalid PPP Event\n",card->devname); + } +} + + + +/* TIMER INTERRUPT */ + +void timer_intr (sdla_t *card) +{ + netdevice_t *dev; + ppp_private_area_t *ppp_priv_area; + + + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + if (!dev || !wan_netif_priv(dev)){ + DEBUG_EVENT("%s: Error: No dev\n",__FUNCTION__); + return; + } + + ppp_priv_area = wan_netif_priv(dev); + + if (ppp_priv_area->timer_int_enabled & TMR_INT_ENABLED_CONFIG){ + config_ppp(card); + ppp_priv_area->timer_int_enabled &= + ~TMR_INT_ENABLED_CONFIG; + } + + /* Update statistics */ + if (ppp_priv_area->timer_int_enabled & TMR_INT_ENABLED_UPDATE){ + + ppp_get_err_stats(card); + + if (IS_TE1_CARD(card)) { + card->wandev.fe_iface.read_alarm(&card->fe, 0); + /* TE1 Update T1/E1 perfomance counters */ + card->wandev.fe_iface.read_pmon(&card->fe, 0); + }else if (IS_56K_CARD(card)) { + /* 56K Update CSU/DSU alarms */ + card->wandev.fe_iface.read_alarm(&card->fe, 1); + } + + if(!(--ppp_priv_area->update_comms_stats)){ + ppp_priv_area->timer_int_enabled &= + ~TMR_INT_ENABLED_UPDATE; + } + } + + /* TE timer interrupt */ + if (ppp_priv_area->timer_int_enabled & TMR_INT_ENABLED_TE){ + card->wandev.fe_iface.polling(&card->fe); + ppp_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_TE; + } + + /* PPIPEMON UDP request */ + if (ppp_priv_area->timer_int_enabled & TMR_INT_ENABLED_UDP){ + process_udp_mgmt_pkt(card,dev, ppp_priv_area,0); + ppp_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_UDP; + } + + /* PPP Event */ + if (ppp_priv_area->timer_int_enabled & TMR_INT_ENABLED_PPP_EVENT){ + + if (ppp_priv_area->ppp_state == WAN_DISCONNECTED){ + int err; + if ((err=retrigger_comm(card)) < 0){ + /* DTR has been dropped. The card will + * NOT give us an interrupt, thus do not turn off + * interrupt, let it retry the command again */ + if (err != -EBUSY){ + ppp_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_PPP_EVENT; + } + } + } + + /* If the state is CONNECTING, it means that communicatins were + * enabled. When the remote side enables its comminication we + * should get an interrupt PPP_INTR_OPEN, thus turn off polling + */ + + else if (ppp_priv_area->ppp_state == WAN_CONNECTING){ + /* Turn off the timer interrupt */ + ppp_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_PPP_EVENT; + } + + /* If state is connected and we are in PEER mode + * poll for an IP address which will be provided by remote end. + * + * We must wait for the main state to become connected, + * because the front end might be disconnected still, + * and the interface might be down. + */ + else if ((card->wandev.state == WAN_CONNECTED && + card->u.p.ip_mode == WANOPT_PPP_PEER) && + test_bit(0,&Read_connection_info)){ + + card->state_tick = jiffies; + if (read_connection_info (card)){ + printk(KERN_INFO "%s: Failed to read PEER IP Addresses\n", + card->devname); + }else{ + clear_bit(0,&Read_connection_info); + set_bit(1,&Read_connection_info); + trigger_ppp_poll(dev); + } + }else{ + //FIXME Put the comment back int + ppp_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_PPP_EVENT; + } + + }/* End of PPP_EVENT */ + + + /* Only disable the timer interrupt if there are no udp, statistic */ + /* updates or events pending */ + if(!ppp_priv_area->timer_int_enabled) { + card->hw_iface.clear_bit(card->hw, card->intr_perm_off, PPP_INTR_TIMER); + } +} + + +static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number, unsigned short proto) +{ + int i; + + if( proto == htons(ETH_P_IPX) ) { + //It's an IPX packet + if(!enable_IPX) { + //Return 1 so we don't pass it up the stack. + return 1; + } + } else { + //It's not IPX so pass it up the stack. + return 0; + } + + if( sendpacket[16] == 0x90 && + sendpacket[17] == 0x04) + { + //It's IPXWAN + + if( sendpacket[2] == 0x02 && + sendpacket[34] == 0x00) + { + //It's a timer request packet + printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n",devname); + + //Go through the routing options and answer no to every + //option except Unnumbered RIP/SAP + for(i = 41; sendpacket[i] == 0x00; i += 5) + { + //0x02 is the option for Unnumbered RIP/SAP + if( sendpacket[i + 4] != 0x02) + { + sendpacket[i + 1] = 0; + } + } + + //Skip over the extended Node ID option + if( sendpacket[i] == 0x04 ) + { + i += 8; + } + + //We also want to turn off all header compression opt. + for(; sendpacket[i] == 0x80 ;) + { + sendpacket[i + 1] = 0; + i += (sendpacket[i + 2] << 8) + (sendpacket[i + 3]) + 4; + } + + //Set the packet type to timer response + sendpacket[34] = 0x01; + + printk(KERN_INFO "%s: Sending IPXWAN Timer Response\n",devname); + } + else if( sendpacket[34] == 0x02 ) + { + //This is an information request packet + printk(KERN_INFO "%s: Received IPXWAN Information Request packet\n",devname); + + //Set the packet type to information response + sendpacket[34] = 0x03; + + //Set the router name + sendpacket[51] = 'P'; + sendpacket[52] = 'T'; + sendpacket[53] = 'P'; + sendpacket[54] = 'I'; + sendpacket[55] = 'P'; + sendpacket[56] = 'E'; + sendpacket[57] = '-'; + sendpacket[58] = CVHexToAscii(network_number >> 28); + sendpacket[59] = CVHexToAscii((network_number & 0x0F000000)>> 24); + sendpacket[60] = CVHexToAscii((network_number & 0x00F00000)>> 20); + sendpacket[61] = CVHexToAscii((network_number & 0x000F0000)>> 16); + sendpacket[62] = CVHexToAscii((network_number & 0x0000F000)>> 12); + sendpacket[63] = CVHexToAscii((network_number & 0x00000F00)>> 8); + sendpacket[64] = CVHexToAscii((network_number & 0x000000F0)>> 4); + sendpacket[65] = CVHexToAscii(network_number & 0x0000000F); + for(i = 65; i < 99; i+= 1) + { + sendpacket[i] = 0; + } + + printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n",devname); + } + else + { + printk(KERN_INFO "%s: Unknown IPXWAN packet!\n",devname); + return 0; + } + + //Set the WNodeID to our network address + sendpacket[35] = (unsigned char)(network_number >> 24); + sendpacket[36] = (unsigned char)((network_number & 0x00FF0000) >> 16); + sendpacket[37] = (unsigned char)((network_number & 0x0000FF00) >> 8); + sendpacket[38] = (unsigned char)(network_number & 0x000000FF); + + return 1; + } else { + //If we get here's its an IPX-data packet, so it'll get passed up the stack. + + //switch the network numbers + switch_net_numbers(sendpacket, network_number, 1); + return 0; + } +} + +/****** Background Polling Routines ****************************************/ + +/* All polling functions are invoked by the TIMER interrupt in the wpp_isr + * routine. + */ + +/*============================================================================ + * Monitor active link phase. + */ +static void process_route (sdla_t *card) +{ + ppp_flags_t flags; + netdevice_t *dev; + ppp_private_area_t *ppp_priv_area; + + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + if (!dev || !wan_netif_priv(dev)) + return; + ppp_priv_area = wan_netif_priv(dev); + + card->hw_iface.peek(card->hw, card->flags_off, &flags, sizeof(flags)); + if ((card->u.p.ip_mode == WANOPT_PPP_PEER) && + (flags.ip_state == 0x09)){ + + /* We get ip_local from the firmware in PEER mode. + * Therefore, if ip_local is 0, we failed to obtain + * the remote IP address. */ + if (ppp_priv_area->ip_local == 0) + return; + + printk(KERN_INFO "%s: IPCP State Opened.\n", card->devname); + if (read_info( card )) { + printk(KERN_INFO + "%s: An error occurred in IP assignment.\n", + card->devname); + } else { + struct in_device *in_dev = dev->ip_ptr; + if (in_dev != NULL ) { + struct in_ifaddr *ifa = in_dev->ifa_list; + if (ifa){ + printk(KERN_INFO "%s: Assigned Lcl. Addr: %u.%u.%u.%u\n", + card->devname, NIPQUAD(ifa->ifa_local)); + printk(KERN_INFO "%s: Assigned Rmt. Addr: %u.%u.%u.%u\n", + card->devname, NIPQUAD(ifa->ifa_address)); + } + }else{ + printk(KERN_INFO + "%s: Error: Failed to add a route for PPP interface %s\n", + card->devname,dev->name); + } + } + } +} + +/*============================================================================ + * Monitor physical link disconnected phase. + * o if interface is up and the hold-down timeout has expired, then retry + * connection. + */ +static int retrigger_comm(sdla_t *card) +{ + netdevice_t *dev; + ppp_private_area_t *ppp_priv_area; + int err=0; + + dev= WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + if (!dev || !wan_netif_priv(dev)) + return 0; + + ppp_priv_area = wan_netif_priv(dev); + if ((jiffies - card->state_tick) > HOLD_DOWN_TIME){ + + /*Bug Fix: May 24 2001 + * Only set state if the communicatins are + * enabled */ + err = ppp_comm_enable(card); + + switch (err){ + + case 0x00: + /* Communications are back up, change + * state to connecting and reinitialize + * buffers */ + ppp_priv_area->ppp_state = WAN_CONNECTING; + wanpipe_set_state(card, WAN_CONNECTING); + init_ppp_tx_rx_buff( card ); + ppp_priv_area->comm_busy_retry=0; + break; + + case 0x0A: + printk(KERN_INFO "%s: Comm enable busy, retrying in %i sec.\n", + card->devname,HOLD_DOWN_TIME); + ppp_comm_disable(card); + card->state_tick=jiffies; + + /* We are in process of handing up, retry + * again later by leaving the wanpipe + * device in DISCONNECTED state */ + + return -EBUSY; + + /* NB: + * By setting wanpipe state to connecting, the + * communicatins will stay in disabled state, and the + * retries will fail */ + + case 0x01: + printk(KERN_INFO "%s: ERROR PPP Com-Enable failed: protocol not configured!\n", + card->devname); + return -EFAULT; + + case 0x09: + printk(KERN_INFO "%s: ERROR PPP Com-Enable failed: already enabled!\n", + card->devname); + ppp_priv_area->ppp_state = WAN_CONNECTING; + wanpipe_set_state(card, WAN_CONNECTING); + break; + + default: + printk(KERN_INFO "%s: ERROR PPP Com-Enable failed: unknown rc=0x%X!\n", + card->devname,err); + return -EINVAL; + } + } + return 0; +} + +/****** Miscellaneous Functions *********************************************/ + +/*============================================================================ + * Configure S508 adapter. + */ +static int config508(netdevice_t *dev, sdla_t *card) +{ + ppp508_conf_t cfg; + ppp_private_area_t *ppp_priv_area = dev->priv; + + /* Prepare PPP configuration structure */ + memset(&cfg, 0, sizeof(ppp508_conf_t)); + + if (card->wandev.clocking) + cfg.line_speed = card->wandev.bps; + + if (card->wandev.interface == WANOPT_RS232) + cfg.conf_flags |= INTERFACE_LEVEL_RS232; + + + cfg.conf_flags |= DONT_TERMINATE_LNK_MAX_CONFIG; /*send Configure-Request packets forever*/ + cfg.txbuf_percent = PERCENT_TX_BUFF; /* % of Tx bufs */ + cfg.mtu_local = card->wandev.mtu; + cfg.mtu_remote = card->wandev.mtu; /* Default */ + cfg.restart_tmr = TIME_BETWEEN_CONF_REQ; /* 30 = 3sec */ + cfg.auth_rsrt_tmr = TIME_BETWEEN_PAP_CHAP_REQ; /* 30 = 3sec */ + cfg.auth_wait_tmr = WAIT_PAP_CHAP_WITHOUT_REPLY; /* 300 = 30s */ + cfg.mdm_fail_tmr = WAIT_AFTER_DCD_CTS_LOW; /* 5 = 0.5s */ + cfg.dtr_drop_tmr = TIME_DCD_CTS_LOW_AFTER_LNK_DOWN; /* 10 = 1s */ + cfg.connect_tmout = WAIT_DCD_HIGH_AFTER_ENABLE_COMM; /* 900 = 90s */ + cfg.conf_retry = MAX_CONF_REQ_WITHOUT_REPLY; /* 10 = 1s */ + cfg.term_retry = MAX_TERM_REQ_WITHOUT_REPLY; /* 2 times */ + cfg.fail_retry = NUM_CONF_NAK_WITHOUT_REPLY; /* 5 times */ + cfg.auth_retry = NUM_AUTH_REQ_WITHOUT_REPLY; /* 10 times */ + + + if( !card->u.p.authenticator ) { + printk(KERN_INFO "%s: Device is not configured as an authenticator\n", + card->devname); + cfg.auth_options = NO_AUTHENTICATION; + }else{ + printk(KERN_INFO "%s: Device is configured as an authenticator\n", + card->devname); + cfg.auth_options = INBOUND_AUTH; + } + + if( ppp_priv_area->pap == WANOPT_YES){ + cfg.auth_options |=PAP_AUTH; + printk(KERN_INFO "%s: Pap enabled\n", card->devname); + } + if( ppp_priv_area->chap == WANOPT_YES){ + cfg.auth_options |= CHAP_AUTH; + printk(KERN_INFO "%s: Chap enabled\n", card->devname); + } + + + if (ppp_priv_area->enable_IPX == WANOPT_YES){ + printk(KERN_INFO "%s: Enabling IPX Protocol\n",card->devname); + cfg.ipx_options = ENABLE_IPX | ROUTING_PROT_DEFAULT; + }else{ + cfg.ipx_options = DISABLE_IPX; + } + + switch (card->u.p.ip_mode) { + + case WANOPT_PPP_STATIC: + + printk(KERN_INFO "%s: PPP IP Mode: STATIC\n",card->devname); + cfg.ip_options = L_AND_R_IP_NO_ASSIG | + ENABLE_IP; + cfg.ip_local = ppp_priv_area->ip_local; + cfg.ip_remote = ppp_priv_area->ip_remote; + break; + + case WANOPT_PPP_HOST: + + printk(KERN_INFO "%s: PPP IP Mode: HOST\n",card->devname); + cfg.ip_options = L_IP_LOCAL_ASSIG | + R_IP_LOCAL_ASSIG | + ENABLE_IP; + + cfg.ip_local = ppp_priv_area->ip_local; + cfg.ip_remote = ppp_priv_area->ip_remote; + break; + + case WANOPT_PPP_PEER: + + printk(KERN_INFO "%s: PPP IP Mode: PEER\n",card->devname); + cfg.ip_options = L_IP_REMOTE_ASSIG | + R_IP_REMOTE_ASSIG | + ENABLE_IP; + cfg.ip_local = 0x00; + cfg.ip_remote = 0x00; + break; + + default: + printk(KERN_INFO "%s: ERROR: Unsuported PPP Mode Selected\n", + card->devname); + printk(KERN_INFO "%s: PPP IP Modes: STATIC, PEER or HOST\n", + card->devname); + return 1; + } + + return ppp_configure(card, &cfg); +} + +/*============================================================================ + * Show disconnection cause. + */ +static void show_disc_cause(sdla_t *card, unsigned cause) +{ + if (cause & 0x0802) + + printk(KERN_INFO "%s: link terminated by peer\n", + card->devname); + + else if (cause & 0x0004) + + printk(KERN_INFO "%s: link terminated by user\n", + card->devname); + + else if (cause & 0x0008) + + printk(KERN_INFO "%s: authentication failed\n", card->devname); + + else if (cause & 0x0010) + + printk(KERN_INFO + "%s: authentication protocol negotiation failed\n", + card->devname); + + else if (cause & 0x0020) + + printk(KERN_INFO + "%s: peer's request for authentication rejected\n", + card->devname); + + else if (cause & 0x0040) + + printk(KERN_INFO "%s: MRU option rejected by peer\n", + card->devname); + + else if (cause & 0x0080) + + printk(KERN_INFO "%s: peer's MRU was too small\n", + card->devname); + + else if (cause & 0x0100) + + printk(KERN_INFO "%s: failed to negotiate peer's LCP options\n", + card->devname); + + else if (cause & 0x0200) + + printk(KERN_INFO "%s: failed to negotiate peer's IPCP options\n" + , card->devname); + + else if (cause & 0x0400) + + printk(KERN_INFO + "%s: failed to negotiate peer's IPXCP options\n", + card->devname); +} + +/*============================================================================= + * Process UDP call of type PTPIPEAB. + */ +static void process_udp_mgmt_pkt(sdla_t *card, netdevice_t *dev, + ppp_private_area_t *ppp_priv_area, int local_dev) +{ + unsigned char buf2[5]; + unsigned char *buf; + unsigned int frames, len; + struct sk_buff *new_skb; + unsigned short data_length, buffer_length, real_len; + unsigned long data_ptr; + int udp_mgmt_req_valid = 1; + wan_mbox_t *mb = &card->wan_mbox; + struct timeval tv; + int err; + wan_udp_pkt_t *wan_udp_pkt; + + memcpy(&buf2, &card->wandev.udp_port, 2 ); + wan_udp_pkt= (wan_udp_pkt_t*)&ppp_priv_area->udp_pkt_data; + + if (!local_dev){ + + if(ppp_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK) { + + switch(wan_udp_pkt->wan_udp_command) { + + case PPIPE_GET_IBA_DATA: + case PPP_READ_CONFIG: + case PPP_GET_CONNECTION_INFO: + case PPIPE_ROUTER_UP_TIME: + case PPP_READ_STATISTICS: + case PPP_READ_ERROR_STATS: + case PPP_READ_PACKET_STATS: + case PPP_READ_LCP_STATS: + case PPP_READ_IPCP_STATS: + case PPP_READ_IPXCP_STATS: + case PPP_READ_PAP_STATS: + case PPP_READ_CHAP_STATS: + case PPP_READ_CODE_VERSION: + case WAN_GET_MEDIA_TYPE: + case WAN_FE_GET_CFG: + case WAN_FE_GET_STAT: + case WAN_GET_PROTOCOL: + case WAN_GET_PLATFORM: + udp_mgmt_req_valid = 1; + break; + + default: + udp_mgmt_req_valid = 0; + break; + } + } + } + + wan_udp_pkt->wan_udp_opp_flag = 0x00; + if(!udp_mgmt_req_valid) { + /* set length to 0 */ + wan_udp_pkt->wan_udp_data_len = 0x00; + + /* set return code */ + wan_udp_pkt->wan_udp_return_code = 0xCD; + ++ppp_priv_area->pipe_mgmt_stat.UDP_PIPE_mgmt_direction_err; + + if (net_ratelimit()){ + printk(KERN_INFO + "%s: Warning, Illegal UDP command attempted from network: %x\n", + card->devname,wan_udp_pkt->wan_udp_command); + } + } else { + /* Initialize the trace element */ + trace_element_t trace_element; + + switch (wan_udp_pkt->wan_udp_command){ + + /* PPIPE_ENABLE_TRACING */ + case PPIPE_ENABLE_TRACING: + if (!card->TracingEnabled) { + + /* OPERATE_DATALINE_MONITOR */ + mb->wan_command = PPP_DATALINE_MONITOR; + mb->wan_data_len = 0x01; + mb->wan_data[0] = wan_udp_pkt->wan_udp_data[0]; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + + if (err != CMD_OK) { + + ppp_error(card, err, mb); + card->TracingEnabled = 0; + + /* set the return code */ + + wan_udp_pkt->wan_udp_return_code = mb->wan_return_code; + wan_udp_pkt->wan_udp_data_len=0; + break; + } + + card->hw_iface.peek(card->hw, 0xC000, &buf2, 2); + + ppp_priv_area->curr_trace_addr = 0; + memcpy(&ppp_priv_area->curr_trace_addr, &buf2, 2); + ppp_priv_area->start_trace_addr = + ppp_priv_area->curr_trace_addr; + ppp_priv_area->end_trace_addr = + ppp_priv_area->start_trace_addr + END_OFFSET; + + /* MAX_SEND_BUFFER_SIZE - 28 (IP header) + - 32 (ppipemon CBLOCK) */ + available_buffer_space = MAX_LGTH_UDP_MGNT_PKT - + sizeof(struct iphdr)- + sizeof(struct udphdr)- + sizeof(wan_mgmt_t)- + sizeof(wan_cmd_t); + } + wan_udp_pkt->wan_udp_return_code = 0; + wan_udp_pkt->wan_udp_data_len=0; + card->TracingEnabled = 1; + break; + + /* PPIPE_DISABLE_TRACING */ + case PPIPE_DISABLE_TRACING: + + if(card->TracingEnabled) { + + /* OPERATE_DATALINE_MONITOR */ + mb->wan_command = 0x33; + mb->wan_data_len = 1; + mb->wan_data[0] = 0x00; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + } + + /*set return code*/ + wan_udp_pkt->wan_udp_return_code = 0; + wan_udp_pkt->wan_udp_data_len=0; + card->TracingEnabled = 0; + break; + + /* PPIPE_GET_TRACE_INFO */ + case PPIPE_GET_TRACE_INFO: + + if(!card->TracingEnabled) { + /* set return code */ + wan_udp_pkt->wan_udp_return_code = 1; + wan_udp_pkt->wan_udp_data_len=0; + printk(KERN_INFO "%s: PPP Tracing not enabled!\n", + card->devname); + break; + } + + buffer_length = 0; + + /* frames < 62, where 62 is the number of trace + information elements. There is in total 496 + bytes of space and each trace information + element is 8 bytes. + */ + for ( frames=0; frames<62; frames++) { + + trace_pkt_t *trace_pkt = (trace_pkt_t *) + &wan_udp_pkt->wan_udp_data[buffer_length]; + + /* Read the whole trace packet */ + card->hw_iface.peek(card->hw, ppp_priv_area->curr_trace_addr, + &trace_element, sizeof(trace_element_t)); + + /* no data on board so exit */ + if( trace_element.opp_flag == 0x00 ) + break; + + data_ptr = trace_element.trace_data_ptr; + + /* See if there is actual data on the trace buffer */ + if (data_ptr){ + data_length = trace_element.trace_length; + }else{ + data_length = 0; + wan_udp_pkt->wan_udp_data[0] |= 0x02; + } + + //FIXME: Do we need this check + if ((available_buffer_space - buffer_length) + < (sizeof(trace_pkt_t)+1)){ + + /*indicate we have more frames + * on board and exit + */ + wan_udp_pkt->wan_udp_data[0] |= 0x02; + break; + } + + trace_pkt->status = trace_element.trace_type; + trace_pkt->time_stamp = trace_element.trace_time_stamp; + trace_pkt->real_length = trace_element.trace_length; + + real_len = trace_element.trace_length; + + if(data_ptr == 0){ + trace_pkt->data_avail = 0x00; + }else{ + /* we can take it next time */ + if ((available_buffer_space - buffer_length)< + (real_len + sizeof(trace_pkt_t))){ + + wan_udp_pkt->wan_udp_data[0] |= 0x02; + break; + } + trace_pkt->data_avail = 0x01; + + /* get the data */ + card->hw_iface.peek(card->hw, data_ptr, + &trace_pkt->data, + real_len); + } + /* zero the opp flag to + show we got the frame */ + buf2[0] = 0x00; + card->hw_iface.poke_byte(card->hw, ppp_priv_area->curr_trace_addr, 0x00); + + /* now move onto the next + frame */ + ppp_priv_area->curr_trace_addr += sizeof(trace_element_t); + + /* check if we passed the last address */ + if ( ppp_priv_area->curr_trace_addr >= + ppp_priv_area->end_trace_addr){ + + ppp_priv_area->curr_trace_addr = + ppp_priv_area->start_trace_addr; + } + + /* update buffer length and make sure its even */ + + if ( trace_pkt->data_avail == 0x01 ) { + buffer_length += real_len - 1; + } + + /* for the header */ + buffer_length += sizeof(trace_pkt_t); + + if( buffer_length & 0x0001 ) + buffer_length += 1; + } + + /* ok now set the total number of frames passed + in the high 5 bits */ + wan_udp_pkt->wan_udp_data[0] |= (frames << 2); + + /* set the data length */ + wan_udp_pkt->wan_udp_data_len = buffer_length; + + /* set return code */ + wan_udp_pkt->wan_udp_return_code = 0; + break; + + /* PPIPE_GET_IBA_DATA */ + case PPIPE_GET_IBA_DATA: + + card->hw_iface.peek(card->hw, 0xF003, &wan_udp_pkt->wan_udp_data, + 0x09); + + /* set the length of the data */ + wan_udp_pkt->wan_udp_data_len = 0x09; + + /* set return code */ + wan_udp_pkt->wan_udp_return_code = 0x00; + wan_udp_pkt->wan_udp_return_code = 0; + break; + + /* PPIPE_FT1_READ_STATUS */ + case PPIPE_FT1_READ_STATUS: + card->hw_iface.peek(card->hw, 0xF020, &wan_udp_pkt->wan_udp_data[0], 2); + wan_udp_pkt->wan_udp_data_len = 2; + wan_udp_pkt->wan_udp_return_code = 0; + break; + + case PPIPE_FLUSH_DRIVER_STATS: + init_ppp_priv_struct( ppp_priv_area ); + init_global_statistics( card ); + wan_udp_pkt->wan_udp_return_code = 0; + wan_udp_pkt->wan_udp_data_len=0; + break; + + + case PPIPE_ROUTER_UP_TIME: + + do_gettimeofday( &tv ); + ppp_priv_area->router_up_time = tv.tv_sec - + ppp_priv_area->router_start_time; + *(unsigned long *)&wan_udp_pkt->wan_udp_data = ppp_priv_area->router_up_time; + wan_udp_pkt->wan_udp_data_len=4; + wan_udp_pkt->wan_udp_return_code = 0; + break; + + /* PPIPE_DRIVER_STATISTICS */ + case PPIPE_DRIVER_STAT_IFSEND: + memcpy(&wan_udp_pkt->wan_udp_data, &ppp_priv_area->if_send_stat, + sizeof(if_send_stat_t)); + + wan_udp_pkt->wan_udp_return_code = 0; + wan_udp_pkt->wan_udp_data_len = sizeof(if_send_stat_t); + break; + + case PPIPE_DRIVER_STAT_INTR: + memcpy(&wan_udp_pkt->wan_udp_data, &card->statistics, + sizeof(global_stats_t)); + + memcpy(&wan_udp_pkt->wan_udp_data+sizeof(global_stats_t), + &ppp_priv_area->rx_intr_stat, + sizeof(rx_intr_stat_t)); + + wan_udp_pkt->wan_udp_return_code = 0; + wan_udp_pkt->wan_udp_data_len = sizeof(global_stats_t)+ + sizeof(rx_intr_stat_t); + break; + + case PPIPE_DRIVER_STAT_GEN: + memcpy( &wan_udp_pkt->wan_udp_data, + &ppp_priv_area->pipe_mgmt_stat, + sizeof(pipe_mgmt_stat_t)); + + memcpy(&wan_udp_pkt->wan_udp_data+sizeof(pipe_mgmt_stat_t), + &card->statistics, sizeof(global_stats_t)); + + wan_udp_pkt->wan_udp_return_code = 0; + wan_udp_pkt->wan_udp_data_len = sizeof(global_stats_t)+ + sizeof(rx_intr_stat_t); + break; + + + /* FT1 MONITOR STATUS */ + case FT1_MONITOR_STATUS_CTRL: + + wan_udp_pkt->wan_udp_return_code = 0; + + /* Enable FT1 MONITOR STATUS */ + if( wan_udp_pkt->wan_udp_data[0] == 1) { + + if(card->rCount++ != 0 ) { + wan_udp_pkt->wan_udp_return_code = 0; + wan_udp_pkt->wan_udp_data_len=1; + break; + } + } + + /* Disable FT1 MONITOR STATUS */ + if( wan_udp_pkt->wan_udp_data[0] == 0) { + + if(--card->rCount != 0) { + wan_udp_pkt->wan_udp_return_code = 0; + wan_udp_pkt->wan_udp_data_len=1; + break; + } + } + goto udp_dflt_cmd; + + case WAN_GET_MEDIA_TYPE: + case WAN_FE_GET_STAT: + case WAN_FE_SET_LB_MODE: + case WAN_FE_FLUSH_PMON: + case WAN_FE_GET_CFG: + + if (IS_TE1_CARD(card)){ + card->wandev.fe_iface.process_udp( + &card->fe, + &wan_udp_pkt->wan_udp_cmd, + &wan_udp_pkt->wan_udp_data[0]); + }else if (IS_56K_CARD(card)){ + card->wandev.fe_iface.process_udp( + &card->fe, + &wan_udp_pkt->wan_udp_cmd, + &wan_udp_pkt->wan_udp_data[0]); + }else{ + if (wan_udp_pkt->wan_udp_command == WAN_GET_MEDIA_TYPE){ + wan_udp_pkt->wan_udp_data_len = sizeof(unsigned char); + wan_udp_pkt->wan_udp_return_code = CMD_OK; + }else{ + wan_udp_pkt->wan_udp_return_code = WAN_UDP_INVALID_CMD; + } + } + break; + + case WAN_GET_PROTOCOL: + wan_udp_pkt->wan_udp_data[0] = card->wandev.config_id; + wan_udp_pkt->wan_udp_return_code = CMD_OK; + wan_udp_pkt->wan_udp_data_len = 1; + break; + + case WAN_GET_PLATFORM: + wan_udp_pkt->wan_udp_data[0] = WAN_LINUX_PLATFORM; + wan_udp_pkt->wan_udp_return_code = CMD_OK; + wan_udp_pkt->wan_udp_data_len = 1; + break; + + default: +udp_dflt_cmd: + /* it's a board command */ + mb->wan_command = wan_udp_pkt->wan_udp_command; + mb->wan_data_len = wan_udp_pkt->wan_udp_data_len; + + if(mb->wan_data_len) { + memcpy(&mb->wan_data,(unsigned char *)wan_udp_pkt->wan_udp_data, + mb->wan_data_len); + } + + /* run the command on the board */ + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + + if (err != CMD_OK) { + + wan_udp_pkt->wan_udp_return_code = mb->wan_return_code; + ppp_error(card, err, mb); + ++ppp_priv_area->pipe_mgmt_stat. + UDP_PIPE_mgmt_adptr_cmnd_timeout; + break; + } + + ++ppp_priv_area->pipe_mgmt_stat.UDP_PIPE_mgmt_adptr_cmnd_OK; + + /* copy the result back to our buffer */ + memcpy(&wan_udp_pkt->wan_udp_hdr.wan_cmd, mb, sizeof(wan_cmd_t)); + + if(mb->wan_data_len) { + memcpy(&wan_udp_pkt->wan_udp_data,&mb->wan_data,mb->wan_data_len); + } + + wan_udp_pkt->wan_udp_data_len = mb->wan_data_len; + + } /* end of switch */ + } /* end of else */ + + /* Fill UDP TTL */ + wan_udp_pkt->wan_ip_ttl = card->wandev.ttl; + + if (local_dev){ + wan_udp_pkt->wan_udp_request_reply = UDPMGMT_REPLY; + return; + } + + len = reply_udp(ppp_priv_area->udp_pkt_data, wan_udp_pkt->wan_udp_data_len); + + if (ppp_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK) { + + /* Make sure we are not already sending */ + if (!test_bit(SEND_CRIT,&card->wandev.critical)){ + ++ppp_priv_area->pipe_mgmt_stat.UDP_PIPE_mgmt_passed_to_adptr; + ppp_send(card,ppp_priv_area->udp_pkt_data,len,ppp_priv_area->protocol); + } + + } else { + + /* Pass it up the stack + Allocate socket buffer */ + if ((new_skb = dev_alloc_skb(len)) != NULL) { + + /* copy data into new_skb */ + + buf = skb_put(new_skb, len); + memcpy(buf,ppp_priv_area->udp_pkt_data, len); + + ++ppp_priv_area->pipe_mgmt_stat.UDP_PIPE_mgmt_passed_to_stack; + + /* Decapsulate packet and pass it up the protocol + stack */ + new_skb->protocol = ppp_priv_area->protocol; + new_skb->dev = dev; + new_skb->mac.raw = new_skb->data; + + netif_rx(new_skb); + + } else { + + ++ppp_priv_area->pipe_mgmt_stat.UDP_PIPE_mgmt_no_socket; + printk(KERN_INFO "no socket buffers available!\n"); + } + } + + atomic_set(&ppp_priv_area->udp_pkt_len,0); + return; +} + +/*============================================================================= + * Initial the ppp_private_area structure. + */ +static void init_ppp_priv_struct( ppp_private_area_t *ppp_priv_area ) +{ + + memset(&ppp_priv_area->if_send_stat, 0, sizeof(if_send_stat_t)); + memset(&ppp_priv_area->rx_intr_stat, 0, sizeof(rx_intr_stat_t)); + memset(&ppp_priv_area->pipe_mgmt_stat, 0, sizeof(pipe_mgmt_stat_t)); +} + +/*============================================================================ + * Initialize Global Statistics + */ +static void init_global_statistics( sdla_t *card ) +{ + memset(&card->statistics, 0, sizeof(global_stats_t)); +} + +/*============================================================================ + * Initialize Receive and Transmit Buffers. + */ +static void init_ppp_tx_rx_buff( sdla_t *card ) +{ + ppp508_buf_info_t info; + unsigned long info_off; + + /* Alex Apr 8 2004 Sangoma ISA card */ + info_off = PPP514_BUF_OFFS; + card->hw_iface.peek(card->hw, info_off, &info, sizeof(info)); + + card->u.p.txbuf_base_off = info.txb_ptr; + + card->u.p.txbuf_last_off = + card->u.p.txbuf_base_off + + (info.txb_num - 1) * sizeof(ppp_buf_ctl_t); + card->u.p.rxbuf_base_off = info.rxb_ptr; + card->u.p.rxbuf_last_off = + card->u.p.rxbuf_base_off + + (info.rxb_num - 1) * sizeof(ppp_buf_ctl_t); + + card->u.p.txbuf_next_off = info.txb_nxt; + card->u.p.rxbuf_next_off = info.rxb1_ptr; + + card->u.p.rx_base_off = info.rxb_base; + card->u.p.rx_top_off = info.rxb_end; + + card->u.p.txbuf_off = card->u.p.txbuf_base_off; + card->rxmb_off = card->u.p.rxbuf_base_off; + +} +/*============================================================================= + * Read Connection Information (ie for Remote IP address assginment). + * Called when ppp interface connected. + */ +static int read_info( sdla_t *card ) +{ + netdevice_t *dev; + ppp_private_area_t *ppp_priv_area; + int err; + struct ifreq if_info; + struct sockaddr_in *if_data1, *if_data2; + mm_segment_t fs; + + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + if (!dev || !wan_netif_priv(dev)) + return 0; + ppp_priv_area = wan_netif_priv(dev); + + + /* Set Local and remote addresses */ + memset(&if_info, 0, sizeof(if_info)); + strcpy(if_info.ifr_name, dev->name); + + + fs = get_fs(); + set_fs(get_ds()); /* get user space block */ + + /* Change the local and remote ip address of the interface. + * This will also add in the destination route. + */ + if_data1 = (struct sockaddr_in *)&if_info.ifr_addr; + if_data1->sin_addr.s_addr = ppp_priv_area->ip_local; + if_data1->sin_family = AF_INET; + err = wp_devinet_ioctl( SIOCSIFADDR, &if_info ); + if_data2 = (struct sockaddr_in *)&if_info.ifr_dstaddr; + if_data2->sin_addr.s_addr = ppp_priv_area->ip_remote; + if_data2->sin_family = AF_INET; + err = wp_devinet_ioctl( SIOCSIFDSTADDR, &if_info ); + + set_fs(fs); /* restore old block */ + + if (err) { + printk (KERN_INFO "%s: Adding of route failed: %i\n", + card->devname,err); + printk (KERN_INFO "%s: Local : %u.%u.%u.%u\n", + card->devname,NIPQUAD(ppp_priv_area->ip_local)); + printk (KERN_INFO "%s: Remote: %u.%u.%u.%u\n", + card->devname,NIPQUAD(ppp_priv_area->ip_remote)); + } + return err; +} + +/*============================================================================= + * Remove Dynamic Route. + * Called when ppp interface disconnected. + */ + +static void remove_route( sdla_t *card ) +{ + netdevice_t *dev; + long ip_addr; + int err; + mm_segment_t fs; + struct ifreq if_info; + struct sockaddr_in *if_data1; + struct in_device *in_dev; + struct in_ifaddr *ifa; + + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + if (!dev) + return; + in_dev = dev->ip_ptr; + if (!in_dev) + return; + + if (!(ifa = in_dev->ifa_list)) + return; + + ip_addr = ifa->ifa_local; + + /* Set Local and remote addresses */ + memset(&if_info, 0, sizeof(if_info)); + strcpy(if_info.ifr_name, dev->name); + + fs = get_fs(); + set_fs(get_ds()); /* get user space block */ + + + /* Change the local ip address of the interface to 0. + * This will also delete the destination route. + */ + if_data1 = (struct sockaddr_in *)&if_info.ifr_addr; + if_data1->sin_addr.s_addr = 0; + if_data1->sin_family = AF_INET; + err = wp_devinet_ioctl( SIOCSIFADDR, &if_info ); + + set_fs(fs); /* restore old block */ + + + if (err) { + printk (KERN_INFO "%s: Deleting dynamic route failed %d!\n", + card->devname, err); + return; + }else{ + printk (KERN_INFO "%s: PPP Deleting dynamic route %u.%u.%u.%u successfuly\n", + card->devname, NIPQUAD(ip_addr)); + } + return; +} + +/*============================================================================= + * Perform the Interrupt Test by running the READ_CODE_VERSION command MAX_INTR + * _TEST_COUNTER times. + */ +static int intr_test( sdla_t *card ) +{ + wan_mbox_t *mb = &card->wan_mbox; + int err,i; + + err = ppp_set_intr_mode( card, 0x08 ); + + if (err == CMD_OK) { + + for (i = 0; i < MAX_INTR_TEST_COUNTER; i ++) { + /* Run command READ_CODE_VERSION */ + memset(&mb->wan_cmd, 0, sizeof(ppp_cmd_t)); + mb->wan_data_len = 0; + mb->wan_command = PPP_READ_CODE_VERSION; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != CMD_OK) + ppp_error(card, err, mb); + } + } + else return err; + + err = ppp_set_intr_mode( card, 0 ); + if (err != CMD_OK) + return err; + + return 0; +} + +/*============================================================================== + * Determine what type of UDP call it is. DRVSTATS or PTPIPEAB ? + */ + +static int udp_pkt_type(struct sk_buff *skb, sdla_t* card) +{ + wan_udp_pkt_t *wan_udp_pkt = (wan_udp_pkt_t *)skb->data; + + if (skb->len < sizeof(wan_udp_pkt_t)){ + return UDP_INVALID_TYPE; + } + +#ifdef _WAN_UDP_DEBUG + printk(KERN_INFO "SIG %s = %s\n\ + UPP %x = %x\n\ + PRT %x = %x\n\ + REQ %i = %i\n\ + 36 th = %x 37th = %x\n", + wan_udp_pkt->wan_udp_signature, + UDPMGMT_SIGNATURE, + wan_udp_pkt->wan_udp_dport, + ntohs(card->wandev.udp_port), + wan_udp_pkt->wan_ip_p, + UDPMGMT_UDP_PROTOCOL, + wan_udp_pkt->wan_udp_request_reply, + UDPMGMT_REQUEST, + skb->data[36], skb->data[37]); +#endif + + if ((wan_udp_pkt->wan_udp_dport == ntohs(card->wandev.udp_port)) && + (wan_udp_pkt->wan_ip_p == UDPMGMT_UDP_PROTOCOL) && + (wan_udp_pkt->wan_udp_request_reply == UDPMGMT_REQUEST)) { + + if (!strncmp(wan_udp_pkt->wan_udp_signature,UDPMGMT_SIGNATURE,8)){ + return UDP_PTPIPE_TYPE; + } + if (!strncmp(wan_udp_pkt->wan_udp_signature,GLOBAL_UDP_SIGNATURE,8)){ + return UDP_PTPIPE_TYPE; + } + + if (!strncmp(wan_udp_pkt->wan_udp_signature,UDPDRV_SIGNATURE,8)){ + return UDP_DRVSTATS_TYPE; + } + + } + + return UDP_INVALID_TYPE; +} + +/*============================================================================ + * Check to see if the packet to be transmitted contains a broadcast or + * multicast source IP address. + */ + +static int chk_bcast_mcast_addr(sdla_t *card, netdevice_t* dev, + struct sk_buff *skb) +{ + u32 src_ip_addr; + u32 broadcast_ip_addr = 0; + struct in_device *in_dev; + /* read the IP source address from the outgoing packet */ + src_ip_addr = *(u32 *)(skb->data + 12); + + /* read the IP broadcast address for the device */ + in_dev = dev->ip_ptr; + if(in_dev != NULL) { + struct in_ifaddr *ifa= in_dev->ifa_list; + if(ifa != NULL) + broadcast_ip_addr = ifa->ifa_broadcast; + else + return 0; + } + + /* check if the IP Source Address is a Broadcast address */ + if((dev->flags & IFF_BROADCAST) && (src_ip_addr == broadcast_ip_addr)) { + printk(KERN_INFO "%s: Broadcast Source Address silently discarded\n", + card->devname); + return 1; + } + + /* check if the IP Source Address is a Multicast address */ + if((ntohl(src_ip_addr) >= 0xE0000001) && + (ntohl(src_ip_addr) <= 0xFFFFFFFE)) { + printk(KERN_INFO "%s: Multicast Source Address silently discarded\n", + card->devname); + return 1; + } + + return 0; +} + +void s508_lock (sdla_t *card, unsigned long *smp_flags) +{ + spin_lock_irqsave(&card->wandev.lock, *smp_flags); +} + +void s508_unlock (sdla_t *card, unsigned long *smp_flags) +{ + spin_unlock_irqrestore(&card->wandev.lock, *smp_flags); +} + +static int read_connection_info (sdla_t *card) +{ + wan_mbox_t *mb = &card->wan_mbox; + netdevice_t *dev; + ppp_private_area_t *ppp_priv_area; + ppp508_connect_info_t *ppp508_connect_info; + int err; + + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + if (!dev || !wan_netif_priv(dev)) + return 0; + ppp_priv_area = wan_netif_priv(dev); + + memset(&mb->wan_cmd, 0, sizeof(ppp_cmd_t)); + mb->wan_data_len = 0; + mb->wan_command = PPP_GET_CONNECTION_INFO; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != CMD_OK) { + ppp_error(card, err, mb); + ppp_priv_area->ip_remote = 0; + ppp_priv_area->ip_local = 0; + } + else { + ppp508_connect_info = (ppp508_connect_info_t *)mb->wan_data; + ppp_priv_area->ip_remote = ppp508_connect_info->ip_remote; + ppp_priv_area->ip_local = ppp508_connect_info->ip_local; + + NEX_PRINTK(KERN_INFO "READ CONNECTION GOT IP ADDRESS %x, %x\n", + ppp_priv_area->ip_remote, + ppp_priv_area->ip_local); + } + + return err; +} + +/*=============================================================================== + * config_ppp + * + * Configure the ppp protocol and enable communications. + * + * The if_open function binds this function to the poll routine. + * Therefore, this function will run every time the ppp interface + * is brought up. + * + * If the communications are not enabled, proceed to configure + * the card and enable communications. + * + * If the communications are enabled, it means that the interface + * was shutdown by ether the user or driver. In this case, we + * have to check that the IP addresses have not changed. If + * the IP addresses changed, we have to reconfigure the firmware + * and update the changed IP addresses. Otherwise, just exit. + */ +static int config_ppp (sdla_t *card) +{ + netdevice_t *dev; + ppp_private_area_t *ppp_priv_area; + + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + if (!dev || !wan_netif_priv(dev)) + return 0; + ppp_priv_area = wan_netif_priv(dev); + + if (card->u.p.comm_enabled){ + + if (ppp_priv_area->ip_local_tmp != ppp_priv_area->ip_local || + ppp_priv_area->ip_remote_tmp != ppp_priv_area->ip_remote){ + + /* The IP addersses have changed, we must + * stop the communications and reconfigure + * the card. Reason: the firmware must know + * the local and remote IP addresses. */ + disable_comm(card); + ppp_priv_area->ppp_state = WAN_DISCONNECTED; + wanpipe_set_state(card, WAN_DISCONNECTED); + printk(KERN_INFO + "%s: IP addresses changed!\n", + card->devname); + printk(KERN_INFO "%s: Restarting communications ...\n", + card->devname); + }else{ + /* IP addresses are the same and the link is up, + * we dont have to do anything here. Therefore, exit */ + return 0; + } + } + + card->hw_iface.poke_byte(card->hw, card->intr_type_off, 0x00); + card->hw_iface.poke_byte(card->hw, card->intr_perm_off, 0x00); + + + if (IS_TE1_CARD(card)) { + int err = -EINVAL; + printk(KERN_INFO "%s: Configuring onboard %s CSU/DSU\n", + card->devname, + (IS_T1_CARD(card))?"T1":"E1"); + if (card->wandev.fe_iface.config){ + err = card->wandev.fe_iface.config(&card->fe); + } + if (err){ + printk(KERN_INFO "%s: Failed %s configuratoin!\n", + card->devname, + (IS_T1_CARD(card))?"T1":"E1"); + return 0; + } + + }else if (IS_56K_CARD(card)) { + int err = -EINVAL; + printk(KERN_INFO "%s: Configuring 56K onboard CSU/DSU\n", + card->devname); + + if (card->wandev.fe_iface.config){ + err = card->wandev.fe_iface.config(&card->fe); + } + if (err){ + printk (KERN_INFO "%s: Failed 56K configuration!\n", + card->devname); + return 0; + } + } + + + /* Record the new IP addreses */ + ppp_priv_area->ip_local = ppp_priv_area->ip_local_tmp; + ppp_priv_area->ip_remote = ppp_priv_area->ip_remote_tmp; + + if (config508(dev, card)){ + printk(KERN_INFO "%s: Failed to configure PPP device\n", + card->devname); + return 0; + } + + if (ppp_set_intr_mode(card, PPP_INTR_RXRDY| + PPP_INTR_TXRDY| + PPP_INTR_MODEM| + PPP_INTR_DISC | + PPP_INTR_OPEN | + PPP_INTR_DROP_DTR | + PPP_INTR_TIMER)) { + + printk(KERN_INFO "%s: Failed to configure board interrupts !\n", + card->devname); + return 0; + } + + /* Turn off the transmit and timer interrupt */ + card->hw_iface.clear_bit(card->hw, card->intr_perm_off, (PPP_INTR_RXRDY| + PPP_INTR_TXRDY| + PPP_INTR_MODEM| + PPP_INTR_DISC | + PPP_INTR_OPEN | + PPP_INTR_DROP_DTR | + PPP_INTR_TIMER)); + + /* If you are not the authenticator and any one of the protocol is + * enabled then we call the set_out_bound_authentication. + */ + if ( !card->u.p.authenticator && (ppp_priv_area->pap || ppp_priv_area->chap)) { + if ( ppp_set_outbnd_auth(card, ppp_priv_area) ){ + printk(KERN_INFO "%s: Outbound authentication failed !\n", + card->devname); + return 0; + } + } + + /* If you are the authenticator and any one of the protocol is enabled + * then we call the set_in_bound_authentication. + */ + if (card->u.p.authenticator && (ppp_priv_area->pap || ppp_priv_area->chap)){ + if (ppp_set_inbnd_auth(card, ppp_priv_area)){ + printk(KERN_INFO "%s: Inbound authentication failed !\n", + card->devname); + return 0; + } + } + + + /* Turn on all masked interrupts except for + * tx and timer interrupts */ + card->hw_iface.set_bit(card->hw, card->intr_perm_off, + (PPP_INTR_RXRDY| PPP_INTR_MODEM| + PPP_INTR_DISC | PPP_INTR_OPEN | PPP_INTR_DROP_DTR)); + + /* If we fail to enable communications here it's OK, + * since the DTR timer will cause a disconnected, which + * will retrigger communication in timer_intr() */ + if (ppp_comm_enable(card) == CMD_OK) { + ppp_priv_area->ppp_state = WAN_CONNECTING; + wanpipe_set_state(card, WAN_CONNECTING); + init_ppp_tx_rx_buff(card); + } + + /* Manually poll the 56K CSU/DSU to get the status */ + if (IS_56K_CARD(card)) { + /* 56K Update CSU/DSU alarms */ + card->wandev.fe_iface.read_alarm(&card->fe, 1); + } + + /* Run WANPIPE debugging */ + WAN_DEBUG_START(card); + return 0; +} + +/*============================================================ + * ppp_poll + * + * Rationale: + * We cannot manipulate the routing tables, or + * ip addresses withing the interrupt. Therefore + * we must perform such actons outside an interrupt + * at a later time. + * + * Description: + * PPP polling routine, responsible for + * shutting down interfaces upon disconnect + * and adding/removing routes. + * + * Usage: + * This function is executed for each ppp + * interface through a tq_schedule bottom half. + * + * trigger_ppp_poll() function is used to kick + * the ppp_poll routine. + */ +static void ppp_poll (void *dev_ptr) +{ + netdevice_t *dev=dev_ptr; + ppp_private_area_t *ppp_priv_area; + sdla_t *card; + u8 check_gateway=0; + + if (!dev || (ppp_priv_area = dev->priv) == NULL) + return; + + card = ppp_priv_area->card; + + /* Shutdown is in progress, stop what you are + * doing and get out */ + if (test_bit(PERI_CRIT,&card->wandev.critical)){ + clear_bit(POLL_CRIT,&card->wandev.critical); + return; + } + + /* if_open() function has triggered the polling routine + * to determine the configured IP addresses. Once the + * addresses are found, trigger the chdlc configuration */ + if (test_bit(0,&ppp_priv_area->config_ppp)){ + + ppp_priv_area->ip_local_tmp = get_ip_address(dev,WAN_LOCAL_IP); + ppp_priv_area->ip_remote_tmp = get_ip_address(dev,WAN_POINTOPOINT_IP); + + if (ppp_priv_area->ip_local_tmp == ppp_priv_area->ip_remote_tmp && + card->u.p.ip_mode == WANOPT_PPP_HOST){ + + if (++ppp_priv_area->ip_error > MAX_IP_ERRORS){ + printk(KERN_INFO "\n"); + printk(KERN_INFO "%s: --- WARNING ---\n", + card->devname); + printk(KERN_INFO "%s: The local IP address is the same as the\n", + card->devname); + printk(KERN_INFO "%s: Point-to-Point IP address.\n", + card->devname); + printk(KERN_INFO "%s: --- WARNING ---\n\n", + card->devname); + }else{ + clear_bit(POLL_CRIT,&card->wandev.critical); + ppp_priv_area->poll_delay_timer.expires = jiffies+HZ; + add_timer(&ppp_priv_area->poll_delay_timer); + return; + } + } + + ppp_priv_area->timer_int_enabled |= TMR_INT_ENABLED_CONFIG; + card->hw_iface.set_bit(card->hw, card->intr_perm_off, PPP_INTR_TIMER); + ppp_priv_area->ip_error=0; + + clear_bit(0,&ppp_priv_area->config_ppp); + clear_bit(POLL_CRIT,&card->wandev.critical); + return; + } + + /* Dynamic interface implementation, as well as dynamic + * routing. */ + + switch (card->wandev.state) { + + case WAN_DISCONNECTED: + + /* If the dynamic interface configuration is on, and interface + * is up, then bring down the netowrk interface */ + + if (test_bit(DYN_OPT_ON,&ppp_priv_area->interface_down) && + !test_bit(DEV_DOWN,&ppp_priv_area->interface_down) && + dev->flags & IFF_UP){ + + printk(KERN_INFO "%s: Interface %s down.\n", + card->devname, dev->name); + change_dev_flags(dev, (dev->flags&~IFF_UP)); + set_bit(DEV_DOWN,&ppp_priv_area->interface_down); + }else{ + /* We need to check if the local IP address is + * zero. If it is, we shouldn't try to remove it. + * For some reason the kernel crashes badly if + * we try to remove the route twice */ + + if (dev->flags & IFF_UP && + get_ip_address(dev,WAN_LOCAL_IP) && + card->u.p.ip_mode == WANOPT_PPP_PEER){ + + remove_route(card); + } + } + break; + + case WAN_CONNECTED: + + /* In SMP machine this code can execute before the interface + * comes up. In this case, we must make sure that we do not + * try to bring up the interface before dev_open() is finished */ + + /* DEV_DOWN will be set only when we bring down the interface + * for the very first time. This way we know that it was us + * that brought the interface down */ + + if (test_bit(DYN_OPT_ON,&ppp_priv_area->interface_down) && + test_bit(DEV_DOWN, &ppp_priv_area->interface_down) && + !(dev->flags & IFF_UP)){ + + printk(KERN_INFO "%s: Interface %s up.\n", + card->devname,dev->name); + + change_dev_flags(dev,(dev->flags|IFF_UP)); + clear_bit(DEV_DOWN,&ppp_priv_area->interface_down); + check_gateway=1; + } + + if ((card->u.p.ip_mode == WANOPT_PPP_PEER) && + test_bit(1,&Read_connection_info)) { + + process_route(card); + clear_bit(1,&Read_connection_info); + check_gateway=1; + } + + if (ppp_priv_area->gateway && check_gateway) + add_gateway(card,dev); + + break; + } + clear_bit(POLL_CRIT,&card->wandev.critical); + return; +} + +/*============================================================ + * trigger_ppp_poll + * + * Description: + * Add a ppp_poll() task into a tq_scheduler bh handler + * for a specific interface. This will kick + * the ppp_poll() routine at a later time. + * + * Usage: + * Interrupts use this to defer a taks to + * a polling routine. + * + */ + +static void trigger_ppp_poll (netdevice_t *dev) +{ + ppp_private_area_t *ppp_priv_area; + + if ((ppp_priv_area=dev->priv) != NULL){ + + sdla_t *card = ppp_priv_area->card; + + if (test_bit(PERI_CRIT,&card->wandev.critical)){ + return; + } + + if (test_and_set_bit(POLL_CRIT,&card->wandev.critical)){ + return; + } + + wan_schedule_task(&ppp_priv_area->poll_task); + } + return; +} + +static void ppp_poll_delay (unsigned long dev_ptr) +{ + netdevice_t *dev = (netdevice_t *)dev_ptr; + trigger_ppp_poll(dev); +} + +/*============================================================ + * detect_and_fix_tx_bug + * + * Description: + * On connect, if the board tx buffer ptr is not the same + * as the driver tx buffer ptr, we found a firmware bug. + * Report the bug to the above layer. To fix the + * error restart communications again. + * + * Usage: + * + */ + +static int detect_and_fix_tx_bug (sdla_t *card) +{ + if ((card->u.p.txbuf_base_off & 0xFFF) != (card->u.p.txbuf_next_off & 0xFFF)){ + NEX_PRINTK(KERN_INFO "Major Error, Fix the bug\n"); + return 1; + } + return 0; +} + + +static int set_adapter_config (sdla_t* card) +{ + wan_mbox_t * mb = &card->wan_mbox; + ADAPTER_CONFIGURATION_STRUCT* cfg = (ADAPTER_CONFIGURATION_STRUCT*)mb->wan_data; + int err; + + card->hw_iface.getcfg(card->hw, SDLA_ADAPTERTYPE, &cfg->adapter_type); + cfg->adapter_config = 0x00; + cfg->operating_frequency = 00; + mb->wan_data_len = sizeof(ADAPTER_CONFIGURATION_STRUCT); + mb->wan_command = SET_ADAPTER_CONFIGURATION; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + + if(err != 0) { + ppp_error(card,err,mb); + } + return (err); +} + + +/* + * ****************************************************************** + * Proc FS function + */ +#define PROC_CFG_FRM "%-15s| %-12s|\n" +#define PROC_STAT_FRM "%-15s| %-12s| %-14s|\n" +static char ppp_config_hdr[] = + "Interface name | Device name |\n"; +static char ppp_status_hdr[] = + "Interface name | Device name | Status |\n"; + +static int ppp_get_config_info(void* priv, struct seq_file* m, int* stop_cnt) +{ + ppp_private_area_t* ppp_priv_area = priv; + sdla_t* card = NULL; + + if (ppp_priv_area == NULL) + return m->count; + card = ppp_priv_area->card; + + if ((m->from == 0 && m->count == 0) || (m->from && m->from == *stop_cnt)){ + PROC_ADD_LINE(m, + "%s", ppp_config_hdr); + } + + PROC_ADD_LINE(m, + PROC_CFG_FRM, ppp_priv_area->if_name, card->devname); + return m->count; +} + +static int ppp_get_status_info(void* priv, struct seq_file* m, int* stop_cnt) +{ + ppp_private_area_t* ppp_priv_area = priv; + sdla_t* card = NULL; + + if (ppp_priv_area == NULL) + return m->count; + card = ppp_priv_area->card; + + if ((m->from == 0 && m->count == 0) || (m->from && m->from == *stop_cnt)){ + PROC_ADD_LINE(m, + "%s", ppp_status_hdr); + } + + PROC_ADD_LINE(m, + PROC_STAT_FRM, ppp_priv_area->if_name, card->devname, STATE_DECODE(card->wandev.state)); + return m->count; +} + + +#define PROC_DEV_PPP_S_FRM "%-20s| %-14s|\n" +#define PROC_DEV_PPP_D_FRM "%-20s| %-14d|\n" +#define PROC_DEV_SEPARATE "=====================================\n" + +static int ppp_set_dev_config(struct file *file, + const char *buffer, + unsigned long count, + void *data) +{ + int cnt = 0; + wan_device_t* wandev = (void*)data; + sdla_t* card = NULL; + + if (wandev == NULL) + return cnt; + + card = (sdla_t*)wandev->private; + + printk(KERN_INFO "%s: New device config (%s)\n", + wandev->name, buffer); + /* Parse string */ + + return count; +} + +/* + ****************************************************************************** + * ppp_snmp_data() + * + * Description: Save snmp request and parameters in private structure, enable + * TIMER interrupt, put current process in sleep. + * Arguments: + * Returns: + ****************************************************************************** + */ +#define PPPLINKSTATUSPHYSICALINDEX 3 +#define PPPLINKSTATUSBADADDRESSES 4 +#define PPPLINKSTATUSBADCONTROLS 5 +#define PPPLINKSTATUSPACKETTOOLONGS 6 +#define PPPLINKSTATUSBADFCSS 7 +#define PPPLINKSTATUSLOCALMRU 8 +#define PPPLINKSTATUSREMOTEMRU 9 +#define PPPLINKSTATUSLOCALTOPEERACCMAP 10 +#define PPPLINKSTATUSPEERTOLOCALACCMAP 11 +#define PPPLINKSTATUSLOCALTOREMOTEPROTOCOLCOMPRESSION 12 +#define PPPLINKSTATUSREMOTETOLOCALPROTOCOLCOMPRESSION 13 +#define PPPLINKSTATUSLOCALTOREMOTEACCOMPRESSION 14 +#define PPPLINKSTATUSREMOTETOLOCALACCOMPRESSION 15 +#define PPPLINKSTATUSTRANSMITFCSSIZE 16 +#define PPPLINKSTATUSRECEIVEFCSSIZE 17 +#define PPPLINKCONFIGINITIALMRU 20 +#define PPPLINKCONFIGRECEIVEACCMAP 21 +#define PPPLINKCONFIGTRANSMITACCMAP 22 +#define PPPLINKCONFIGMAGICNUMBER 23 +#define PPPLINKCONFIGFCSSIZE 24 +#define PPPLQRQUALITY 27 +#define PPPLQRINGOODOCTETS 28 +#define PPPLQRLOCALPERIOD 29 +#define PPPLQRREMOTEPERIOD 30 +#define PPPLQROUTLQRS 31 +#define PPPLQRINLQRS 32 +#define PPPLQRCONFIGPERIOD 35 +#define PPPLQRCONFIGSTATUS 36 +#define PPPLQREXTNSLASTRECEIVEDLQRPACKET 39 +#define PPPSECURITYCONFIGLINK 42 +#define PPPSECURITYCONFIGPREFERENCE 43 +#define PPPSECURITYCONFIGPROTOCOL 44 +#define PPPSECURITYCONFIGSTATUS 45 +#define PPPSECURITYSECRETSLINK 48 +#define PPPSECURITYSECRETSIDINDEX 49 +#define PPPSECURITYSECRETSDIRECTION 50 +#define PPPSECURITYSECRETSPROTOCOL 51 +#define PPPSECURITYSECRETSIDENTITY 52 +#define PPPSECURITYSECRETSSECRET 53 +#define PPPSECURITYSECRETSSTATUS 54 +#define PPPIPOPERSTATUS 57 +#define PPPIPLOCALTOREMOTECOMPRESSIONPROTOCOL 58 +#define PPPIPREMOTETOLOCALCOMPRESSIONPROTOCOL 59 +#define PPPIPREMOTEMAXSLOTID 60 +#define PPPIPLOCALMAXSLOTID 61 +#define PPPIPCONFIGADMINSTATUS 64 +#define PPPIPCONFIGCOMPRESSION 65 +#define PPPBRIDGEOPERSTATUS 68 +#define PPPBRIDGELOCALTOREMOTETINYGRAMCOMPRESSION 69 +#define PPPBRIDGEREMOTETOLOCALTINYGRAMCOMPRESSION 70 +#define PPPBRIDGELOCALTOREMOTELANID 71 +#define PPPBRIDGEREMOTETOLOCALLANID 72 +#define PPPBRIDGECONFIGADMINSTATUS 75 +#define PPPBRIDGECONFIGTINYGRAM 76 +#define PPPBRIDGECONFIGRINGID 77 +#define PPPBRIDGECONFIGLINEID 78 +#define PPPBRIDGECONFIGLANID 79 +#define PPPBRIDGEMEDIAMACTYPE 82 +#define PPPBRIDGEMEDIALOCALSTATUS 83 +#define PPPBRIDGEMEDIAREMOTESTATUS 84 +#define PPPBRIDGEMEDIACONFIGMACTYPE 87 + +//static int ppp_snmp_data(netdevice_t *dev, struct ifreq* ifr) +static int ppp_snmp_data(sdla_t* card, netdevice_t *dev, void* data) +{ + ppp_private_area_t* ppp_priv_area = NULL; + wanpipe_snmp_t* snmp; + + if (dev == NULL || dev->priv == NULL) + return -EFAULT; + ppp_priv_area = (ppp_private_area_t*)dev->priv; + if (card->wandev.update) { + int rslt = 0; + rslt = card->wandev.update(&card->wandev); + if(rslt) { + return (rslt) ? (-EBUSY) : (-EINVAL); + } + } + snmp = (wanpipe_snmp_t*)data; + + switch(snmp->snmp_magic){ + /* PPP Link Group */ + case PPPLINKSTATUSPHYSICALINDEX: + case PPPLINKSTATUSBADADDRESSES: + case PPPLINKSTATUSBADCONTROLS: + return -EINVAL; + + case PPPLINKSTATUSPACKETTOOLONGS: + snmp->snmp_val = card->wandev.stats.rx_length_errors; + break; + + case PPPLINKSTATUSBADFCSS: + case PPPLINKSTATUSLOCALMRU: + case PPPLINKSTATUSREMOTEMRU: + case PPPLINKSTATUSLOCALTOPEERACCMAP: + case PPPLINKSTATUSPEERTOLOCALACCMAP: + case PPPLINKSTATUSLOCALTOREMOTEPROTOCOLCOMPRESSION: + case PPPLINKSTATUSREMOTETOLOCALPROTOCOLCOMPRESSION: + case PPPLINKSTATUSLOCALTOREMOTEACCOMPRESSION: + case PPPLINKSTATUSREMOTETOLOCALACCOMPRESSION: + case PPPLINKSTATUSTRANSMITFCSSIZE: + case PPPLINKSTATUSRECEIVEFCSSIZE: + case PPPLINKCONFIGINITIALMRU: + case PPPLINKCONFIGRECEIVEACCMAP: + case PPPLINKCONFIGTRANSMITACCMAP: + case PPPLINKCONFIGMAGICNUMBER: + case PPPLINKCONFIGFCSSIZE: + case PPPLQRQUALITY: + case PPPLQRINGOODOCTETS: + case PPPLQRLOCALPERIOD: + case PPPLQRREMOTEPERIOD: + case PPPLQROUTLQRS: + case PPPLQRINLQRS: + case PPPLQRCONFIGPERIOD: + case PPPLQRCONFIGSTATUS: + case PPPLQREXTNSLASTRECEIVEDLQRPACKET: + case PPPSECURITYCONFIGLINK: + case PPPSECURITYCONFIGPREFERENCE: + case PPPSECURITYCONFIGPROTOCOL: + case PPPSECURITYCONFIGSTATUS: + case PPPSECURITYSECRETSLINK: + case PPPSECURITYSECRETSIDINDEX: + case PPPSECURITYSECRETSDIRECTION: + case PPPSECURITYSECRETSPROTOCOL: + case PPPSECURITYSECRETSIDENTITY: + case PPPSECURITYSECRETSSECRET: + case PPPSECURITYSECRETSSTATUS: + case PPPIPOPERSTATUS: + case PPPIPLOCALTOREMOTECOMPRESSIONPROTOCOL: + case PPPIPREMOTETOLOCALCOMPRESSIONPROTOCOL: + case PPPIPREMOTEMAXSLOTID: + case PPPIPLOCALMAXSLOTID: + case PPPIPCONFIGADMINSTATUS: + case PPPIPCONFIGCOMPRESSION: + case PPPBRIDGEOPERSTATUS: + case PPPBRIDGELOCALTOREMOTETINYGRAMCOMPRESSION: + case PPPBRIDGEREMOTETOLOCALTINYGRAMCOMPRESSION: + case PPPBRIDGELOCALTOREMOTELANID: + case PPPBRIDGEREMOTETOLOCALLANID: + case PPPBRIDGECONFIGADMINSTATUS: + case PPPBRIDGECONFIGTINYGRAM: + case PPPBRIDGECONFIGRINGID: + case PPPBRIDGECONFIGLINEID: + case PPPBRIDGECONFIGLANID: + case PPPBRIDGEMEDIAMACTYPE: + case PPPBRIDGEMEDIALOCALSTATUS: + case PPPBRIDGEMEDIAREMOTESTATUS: + case PPPBRIDGEMEDIACONFIGMACTYPE: + + default: + return -EINVAL; + } + + return 0; +} + + +#define PROC_IF_FR_S_FRM "%-30s\t%-14s\n" +#define PROC_IF_FR_D_FRM "%-30s\t%-14d\n" +#define PROC_IF_FR_L_FRM "%-30s\t%-14ld\n" +#define PROC_IF_SEPARATE "====================================================\n" + +static int ppp_set_if_info(struct file *file, + const char *buffer, + unsigned long count, + void *data) +{ + netdevice_t* dev = (void*)data; + ppp_private_area_t* ppp_priv_area = NULL; + + if (dev == NULL || dev->priv == NULL) + return count; + ppp_priv_area = (ppp_private_area_t*)dev->priv; + + printk(KERN_INFO "%s: New interface config (%s)\n", + ppp_priv_area->if_name, buffer); + /* Parse string */ + + return count; +} + +static void ppp_handle_front_end_state(void* card_id) +{ + sdla_t *card = (sdla_t*)card_id; + netdevice_t *dev; + ppp_private_area_t *ppp_priv_area; + + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + if (!dev || !wan_netif_priv(dev)) + return; + ppp_priv_area = wan_netif_priv(dev); + + if (card->wandev.ignore_front_end_status == WANOPT_YES){ + return; + } + + if (ppp_priv_area->ppp_state != WAN_CONNECTED){ + return; + } + + if (card->fe.fe_status == FE_CONNECTED){ + + if (ppp_priv_area->ppp_state == WAN_CONNECTED && + card->wandev.state != WAN_CONNECTED){ + + wanpipe_set_state(card, WAN_CONNECTED); + + ppp_priv_area->timer_int_enabled |= TMR_INT_ENABLED_PPP_EVENT; + card->hw_iface.set_bit(card->hw, card->intr_perm_off, PPP_INTR_TIMER); + trigger_ppp_poll(dev); + } + }else{ + wanpipe_set_state(card, WAN_DISCONNECTED); + + ppp_priv_area->timer_int_enabled |= TMR_INT_ENABLED_PPP_EVENT; + card->hw_iface.set_bit(card->hw, card->intr_perm_off, PPP_INTR_TIMER); + if (card->u.p.ip_mode == WANOPT_PPP_PEER) { + set_bit(0,&Read_connection_info); + } + trigger_ppp_poll(dev); + + /* Start debugging */ + WAN_DEBUG_START(card); + } +} + +/* +**************************************************************************** +** +** +** +*/ +static int ppp_debugging(sdla_t* card) +{ + ppp_pkt_stats_t* pkt_stat = NULL; + ppp_lcp_stats_t* lcp_stat = NULL; + wan_mbox_t* mb = &card->wan_mbox; + unsigned long smp_flags; + static unsigned long last_rx_lcp = 0, last_rx_conf_nak = 0; + unsigned long rx_lcp = 0, rx_conf_nak = 0; + int err = 0; + + wan_spin_lock_irq(&card->wandev.lock,&smp_flags); + if (!(err = ppp_get_pkt_stats(card))){ + pkt_stat = (ppp_pkt_stats_t*)mb->wan_data; + rx_lcp = pkt_stat->rx_lcp; + } + wan_spin_unlock_irq(&card->wandev.lock,&smp_flags); + if (err) + return 0; + wan_spin_lock_irq(&card->wandev.lock,&smp_flags); + if (!(err = ppp_get_lcp_stats(card))){ + lcp_stat = (ppp_lcp_stats_t*)mb->wan_data; + rx_conf_nak = lcp_stat->rx_conf_nak; + } + wan_spin_unlock_irq(&card->wandev.lock,&smp_flags); + if (err) + return 0; + if (card->wan_debugging_state == WAN_DEBUGGING_CONT){ + last_rx_lcp = rx_lcp; + last_rx_conf_nak= rx_conf_nak; + card->wan_debugging_state = WAN_DEBUGGING_PROTOCOL; + return 15; + } + + if (rx_lcp != last_rx_lcp){ + if (rx_conf_nak != last_rx_conf_nak){ + if (card->wan_debug_last_msg != WAN_DEBUG_PPP_LCP_MSG){ + DEBUG_EVENT("%s: PPP NAKs received!\n", + card->devname); + DEBUG_EVENT("%s: Check remote router IP configuration!\n", + card->devname); + DEBUG_EVENT("%s: If you cannot resolve this, call you dealer.\n", + card->devname); + } + card->wan_debug_last_msg = WAN_DEBUG_PPP_LCP_MSG; + }else{ + if (card->wan_debug_last_msg != WAN_DEBUG_PPP_NAK_MSG){ + DEBUG_EVENT("%s: PPP negotiation problem!\n", + card->devname); + DEBUG_EVENT("%s: Check remote router or ISP.\n", + card->devname); + } + card->wan_debug_last_msg = WAN_DEBUG_PPP_NAK_MSG; + } + }else{ + if (card->wan_debug_last_msg != WAN_DEBUG_PPP_NEG_MSG){ + DEBUG_EVENT("%s: No replies to LCP!\n", + card->devname); + DEBUG_EVENT("%s: Check configuration of remote router.\n", + card->devname); + } + card->wan_debug_last_msg = WAN_DEBUG_PPP_NEG_MSG; + } + + return 0; +} + +static unsigned long ppp_crc_frames(sdla_t* card) +{ + wan_mbox_t* mb = &card->wan_mbox; + unsigned long smp_flags; + unsigned long rx_bad_crc = 0; + + wan_spin_lock_irq(&card->wandev.lock,&smp_flags); + if (!ppp_get_err_stats(card)){ + ppp_err_stats_t* stats = (ppp_err_stats_t*)mb->wan_data; + rx_bad_crc = stats->rx_bad_crc; + } + wan_spin_unlock_irq(&card->wandev.lock,&smp_flags); + return rx_bad_crc; +} + +static unsigned long ppp_abort_frames(sdla_t * card) +{ + wan_mbox_t* mb = &card->wan_mbox; + unsigned long smp_flags; + unsigned long rx_abort = 0; + + wan_spin_lock_irq(&card->wandev.lock,&smp_flags); + if (!ppp_get_err_stats(card)){ + ppp_err_stats_t* stats = (ppp_err_stats_t*)mb->wan_data; + rx_abort = stats->rx_abort; + } + wan_spin_unlock_irq(&card->wandev.lock,&smp_flags); + return rx_abort; +} + +static unsigned long ppp_tx_underun_frames(sdla_t* card) +{ + wan_mbox_t* mb = &card->wan_mbox; + unsigned long smp_flags; + unsigned long tx_underrun = 0; + + wan_spin_lock_irq(&card->wandev.lock,&smp_flags); + if (!ppp_get_err_stats(card)){ + ppp_err_stats_t* stats = (ppp_err_stats_t*)mb->wan_data; + tx_underrun = stats->tx_missed_intr; + } + wan_spin_unlock_irq(&card->wandev.lock,&smp_flags); + return tx_underrun; +} + +/****** End *****************************************************************/ diff -Nur linux.org/drivers/net/wan/sdla_remora.c linux-2.6.17/drivers/net/wan/sdla_remora.c --- linux.org/drivers/net/wan/sdla_remora.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/drivers/net/wan/sdla_remora.c 2006-08-30 10:07:16.000000000 +0000 @@ -0,0 +1,2116 @@ +/*************************************************************************** + * sdla_remora.c WANPIPE(tm) Multiprotocol WAN Link Driver. + * AFT REMORA and FXO/FXS support module. + * + * Author: Alex Feldman + * + * Copyright: (c) 2005 Sangoma Technologies Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * ============================================================================ + * Oct 6, 2005 Alex Feldman Initial version. + ****************************************************************************** + */ + +/******************************************************************************* +** INCLUDE FILES +*******************************************************************************/ +#if defined(__FreeBSD__) || defined(__OpenBSD__) +# include +# include +# include +# include +# include +# include +# include +# include +#elif (defined __WINDOWS__) +# include +#else +# include +# include +# include +# include +# include +#endif + + +/******************************************************************************* +** DEFINES AND MACROS +*******************************************************************************/ +#undef SPI2STEP + +/* TE1 critical flag */ +#define WP_RM_TIMER_RUNNING 0x01 +#define WP_RM_TIMER_KILL 0x02 +#define WP_RM_CONFIGURED 0x03 + +#define WP_RM_POLL_TIMER 1000 +#define WP_RM_POLL_TONE_TIMER 5000 +#define WP_RM_POLL_RING_TIMER 10000 +enum { + WP_RM_POLL_TONE_DIAL = 1, + WP_RM_POLL_TONE_BUSY, + WP_RM_POLL_TONE_RING, + WP_RM_POLL_TONE_CONGESTION, + WP_RM_POLL_TONE_DONE, + WP_RM_POLL_RING, + WP_RM_POLL_RING_STOP, + WP_RM_POLL_TDMV, + WP_RM_POLL_EVENT, + WP_RM_POLL_INIT +}; + +/* tone_struct DialTone +** OSC1= 350 Hz OSC2= 440 Hz .0975 Volts -18 dBm */ +#define DIALTONE_IR13 0x7b30 +#define DIALTONE_IR14 0x0063 +#define DIALTONE_IR16 0x7870 +#define DIALTONE_IR17 0x007d +#define DIALTONE_DR32 6 +#define DIALTONE_DR33 6 +#define DIALTONE_DR36 0 +#define DIALTONE_DR37 0 +#define DIALTONE_DR38 0 +#define DIALTONE_DR39 0 +#define DIALTONE_DR40 0 +#define DIALTONE_DR41 0 +#define DIALTONE_DR42 0 +#define DIALTONE_DR43 0 + +/* tone_struct BusySignal +** OSC1= 480 OSC2 = 620 .0975 Voltz -18 dBm 8 */ +#define BUSYTONE_IR13 0x7700 +#define BUSYTONE_IR14 0x0089 +#define BUSYTONE_IR16 0x7120 +#define BUSYTONE_IR17 0x00B2 +#define BUSYTONE_DR32 0x1E +#define BUSYTONE_DR33 0x1E +#define BUSYTONE_DR36 0xa0 +#define BUSYTONE_DR37 0x0f +#define BUSYTONE_DR38 0xa0 +#define BUSYTONE_DR39 0x0f +#define BUSYTONE_DR40 0xa0 +#define BUSYTONE_DR41 0x0f +#define BUSYTONE_DR42 0xa0 +#define BUSYTONE_DR43 0x0f + +/* tone_struct RingbackNormal +** OSC1 = 440 Hz OSC2 = 480 .0975 Volts -18 dBm */ +#define RINGBACKTONE_IR13 0x7870 +#define RINGBACKTONE_IR14 0x007D +#define RINGBACKTONE_IR16 0x7700 +#define RINGBACKTONE_IR17 0x0089 +#define RINGBACKTONE_DR32 0x1E +#define RINGBACKTONE_DR33 0x1E +#define RINGBACKTONE_DR36 0x80 +#define RINGBACKTONE_DR37 0x3E +#define RINGBACKTONE_DR38 0x0 +#define RINGBACKTONE_DR39 0x7d +#define RINGBACKTONE_DR40 0x80 +#define RINGBACKTONE_DR41 0x3E +#define RINGBACKTONE_DR42 0x0 +#define RINGBACKTONE_DR43 0x7d + +/* tone_struct CongestionTone +** OSC1= 480 Hz OSC2 = 620 .0975 Volts -18 dBM */ +#define CONGESTIONTONE_IR13 0x7700 +#define CONGESTIONTONE_IR14 0x0089 +#define CONGESTIONTONE_IR16 0x7120 +#define CONGESTIONTONE_IR17 0x00B2 +#define CONGESTIONTONE_DR32 0x1E +#define CONGESTIONTONE_DR33 0x1E +#define CONGESTIONTONE_DR36 0x40 +#define CONGESTIONTONE_DR37 0x06 +#define CONGESTIONTONE_DR38 0x60 +#define CONGESTIONTONE_DR39 0x09 +#define CONGESTIONTONE_DR40 0x40 +#define CONGESTIONTONE_DR41 0x06 +#define CONGESTIONTONE_DR42 0x60 +#define CONGESTIONTONE_DR43 0x09 + +static alpha indirect_regs[] = +{ +{0,255,"DTMF_ROW_0_PEAK",0x55C2}, +{1,255,"DTMF_ROW_1_PEAK",0x51E6}, +{2,255,"DTMF_ROW2_PEAK",0x4B85}, +{3,255,"DTMF_ROW3_PEAK",0x4937}, +{4,255,"DTMF_COL1_PEAK",0x3333}, +{5,255,"DTMF_FWD_TWIST",0x0202}, +{6,255,"DTMF_RVS_TWIST",0x0202}, +{7,255,"DTMF_ROW_RATIO_TRES",0x0198}, +{8,255,"DTMF_COL_RATIO_TRES",0x0198}, +{9,255,"DTMF_ROW_2ND_ARM",0x0611}, +{10,255,"DTMF_COL_2ND_ARM",0x0202}, +{11,255,"DTMF_PWR_MIN_TRES",0x00E5}, +{12,255,"DTMF_OT_LIM_TRES",0x0A1C}, +{13,0,"OSC1_COEF",0x7B30}, +{14,1,"OSC1X",0x0063}, +{15,2,"OSC1Y",0x0000}, +{16,3,"OSC2_COEF",0x7870}, +{17,4,"OSC2X",0x007D}, +{18,5,"OSC2Y",0x0000}, +{19,6,"RING_V_OFF",0x0000}, +{20,7,"RING_OSC",0x7EF0}, +{21,8,"RING_X",0x0160}, +{22,9,"RING_Y",0x0000}, +{23,255,"PULSE_ENVEL",0x2000}, +{24,255,"PULSE_X",0x2000}, +{25,255,"PULSE_Y",0x0000}, +/*{26,13,"RECV_DIGITAL_GAIN",0x4000},*/ /* playback volume set lower */ +{26,13,"RECV_DIGITAL_GAIN",0x2000}, /* playback volume set lower */ +{27,14,"XMIT_DIGITAL_GAIN",0x4000}, +/*{27,14,"XMIT_DIGITAL_GAIN",0x2000}, */ +{28,15,"LOOP_CLOSE_TRES",0x1000}, +{29,16,"RING_TRIP_TRES",0x3600}, +{30,17,"COMMON_MIN_TRES",0x1000}, +{31,18,"COMMON_MAX_TRES",0x0200}, +{32,19,"PWR_ALARM_Q1Q2",0x07C0}, +{33,20,"PWR_ALARM_Q3Q4",0x2600}, +{34,21,"PWR_ALARM_Q5Q6",0x1B80}, +{35,22,"LOOP_CLOSURE_FILTER",0x8000}, +{36,23,"RING_TRIP_FILTER",0x0320}, +{37,24,"TERM_LP_POLE_Q1Q2",0x008C}, +{38,25,"TERM_LP_POLE_Q3Q4",0x0100}, +{39,26,"TERM_LP_POLE_Q5Q6",0x0010}, +{40,27,"CM_BIAS_RINGING",0x0C00}, +{41,64,"DCDC_MIN_V",0x0C00}, +{42,255,"DCDC_XTRA",0x1000}, +{43,66,"LOOP_CLOSE_TRES_LOW",0x1000}, +}; + +static struct fxo_mode { + char *name; + /* FXO */ + int ohs; + int ohs2; + int rz; + int rt; + int ilim; + int dcv; + int mini; + int acim; + int ring_osc; + int ring_x; +} fxo_modes[] = +{ + { "FCC", 0, 0, 0, 1, 0, 0x3, 0, 0, }, /* US, Canada */ + { "TBR21", 0, 0, 0, 0, 1, 0x3, 0, 0x2, 0x7e6c, 0x023a, }, + /* Austria, Belgium, Denmark, Finland, France, Germany, + Greece, Iceland, Ireland, Italy, Luxembourg, Netherlands, + Norway, Portugal, Spain, Sweden, Switzerland, and UK */ + { "ARGENTINA", 0, 0, 0, 0, 0, 0x3, 0, 0, }, + { "AUSTRALIA", 1, 0, 0, 0, 0, 0, 0x3, 0x3, }, + { "AUSTRIA", 0, 1, 0, 0, 1, 0x3, 0, 0x3, }, + { "BAHRAIN", 0, 0, 0, 0, 1, 0x3, 0, 0x2, }, + { "BELGIUM", 0, 1, 0, 0, 1, 0x3, 0, 0x2, }, + { "BRAZIL", 0, 0, 0, 0, 0, 0, 0x3, 0, }, + { "BULGARIA", 0, 0, 0, 0, 1, 0x3, 0x0, 0x3, }, + { "CANADA", 0, 0, 0, 0, 0, 0x3, 0, 0, }, + { "CHILE", 0, 0, 0, 0, 0, 0x3, 0, 0, }, + { "CHINA", 0, 0, 0, 0, 0, 0, 0x3, 0xf, }, + { "COLUMBIA", 0, 0, 0, 0, 0, 0x3, 0, 0, }, + { "CROATIA", 0, 0, 0, 0, 1, 0x3, 0, 0x2, }, + { "CYRPUS", 0, 0, 0, 0, 1, 0x3, 0, 0x2, }, + { "CZECH", 0, 0, 0, 0, 1, 0x3, 0, 0x2, }, + { "DENMARK", 0, 1, 0, 0, 1, 0x3, 0, 0x2, }, + { "ECUADOR", 0, 0, 0, 0, 0, 0x3, 0, 0, }, + { "EGYPT", 0, 0, 0, 0, 0, 0, 0x3, 0, }, + { "ELSALVADOR", 0, 0, 0, 0, 0, 0x3, 0, 0, }, + { "FINLAND", 0, 1, 0, 0, 1, 0x3, 0, 0x2, }, + { "FRANCE", 0, 1, 0, 0, 1, 0x3, 0, 0x2, }, + { "GERMANY", 0, 1, 0, 0, 1, 0x3, 0, 0x3, }, + { "GREECE", 0, 1, 0, 0, 1, 0x3, 0, 0x2, }, + { "GUAM", 0, 0, 0, 0, 0, 0x3, 0, 0, }, + { "HONGKONG", 0, 0, 0, 0, 0, 0x3, 0, 0, }, + { "HUNGARY", 0, 0, 0, 0, 0, 0x3, 0, 0, }, + { "ICELAND", 0, 1, 0, 0, 1, 0x3, 0, 0x2, }, + { "INDIA", 0, 0, 0, 0, 0, 0x3, 0, 0x4, }, + { "INDONESIA", 0, 0, 0, 0, 0, 0x3, 0, 0, }, + { "IRELAND", 0, 1, 0, 0, 1, 0x3, 0, 0x2, }, + { "ISRAEL", 0, 0, 0, 0, 1, 0x3, 0, 0x2, }, + { "ITALY", 0, 1, 0, 0, 1, 0x3, 0, 0x2, }, + { "JAPAN", 0, 0, 0, 0, 0, 0, 0x3, 0, }, + { "JORDAN", 0, 0, 0, 0, 0, 0, 0x3, 0, }, + { "KAZAKHSTAN", 0, 0, 0, 0, 0, 0x3, 0, }, + { "KUWAIT", 0, 0, 0, 0, 0, 0x3, 0, 0, }, + { "LATVIA", 0, 0, 0, 0, 1, 0x3, 0, 0x2, }, + { "LEBANON", 0, 0, 0, 0, 1, 0x3, 0, 0x2, }, + { "LUXEMBOURG", 0, 1, 0, 0, 1, 0x3, 0, 0x2, }, + { "MACAO", 0, 0, 0, 0, 0, 0x3, 0, 0, }, + { "MALAYSIA", 0, 0, 0, 0, 0, 0, 0x3, 0, }, /* Current loop >= 20ma */ + { "MALTA", 0, 0, 0, 0, 1, 0x3, 0, 0x2, }, + { "MEXICO", 0, 0, 0, 0, 0, 0x3, 0, 0, }, + { "MOROCCO", 0, 0, 0, 0, 1, 0x3, 0, 0x2, }, + { "NETHERLANDS", 0, 1, 0, 0, 1, 0x3, 0, 0x2, }, + { "NEWZEALAND", 0, 0, 0, 0, 0, 0x3, 0, 0x4, }, + { "NIGERIA", 0, 0, 0, 0, 0x1, 0x3, 0, 0x2, }, + { "NORWAY", 0, 1, 0, 0, 1, 0x3, 0, 0x2, }, + { "OMAN", 0, 0, 0, 0, 0, 0, 0x3, 0, }, + { "PAKISTAN", 0, 0, 0, 0, 0, 0, 0x3, 0, }, + { "PERU", 0, 0, 0, 0, 0, 0x3, 0, 0, }, + { "PHILIPPINES", 0, 0, 0, 0, 0, 0, 0x3, 0, }, + { "POLAND", 0, 0, 1, 1, 0, 0x3, 0, 0, }, + { "PORTUGAL", 0, 1, 0, 0, 1, 0x3, 0, 0x2, }, + { "ROMANIA", 0, 0, 0, 0, 0, 3, 0, 0, }, + { "RUSSIA", 0, 0, 0, 0, 0, 0, 0x3, 0, }, + { "SAUDIARABIA", 0, 0, 0, 0, 0, 0x3, 0, 0, }, + { "SINGAPORE", 0, 0, 0, 0, 0, 0x3, 0, 0, }, + { "SLOVAKIA", 0, 0, 0, 0, 0, 0x3, 0, 0x3, }, + { "SLOVENIA", 0, 0, 0, 0, 0, 0x3, 0, 0x2, }, + { "SOUTHAFRICA", 1, 0, 1, 0, 0, 0x3, 0, 0x3, }, + { "SOUTHKOREA", 0, 0, 0, 0, 0, 0x3, 0, 0, }, + { "SPAIN", 0, 1, 0, 0, 1, 0x3, 0, 0x2, }, + { "SWEDEN", 0, 1, 0, 0, 1, 0x3, 0, 0x2, }, + { "SWITZERLAND", 0, 1, 0, 0, 1, 0x3, 0, 0x2, }, + { "SYRIA", 0, 0, 0, 0, 0, 0, 0x3, 0, }, + { "TAIWAN", 0, 0, 0, 0, 0, 0, 0x3, 0, }, + { "THAILAND", 0, 0, 0, 0, 0, 0, 0x3, 0, }, + { "UAE", 0, 0, 0, 0, 0, 0x3, 0, 0, }, + { "UK", 0, 1, 0, 0, 1, 0x3, 0, 0x5, }, + { "USA", 0, 0, 0, 0, 0, 0x3, 0, 0, }, + { "YEMEN", 0, 0, 0, 0, 0, 0x3, 0, 0, }, +}; + +/******************************************************************************* +** STRUCTURES AND TYPEDEFS +*******************************************************************************/ + +/******************************************************************************* +** GLOBAL VARIABLES +*******************************************************************************/ +extern WAN_LIST_HEAD(, wan_tdmv_) wan_tdmv_head; + +/******************************************************************************* +** FUNCTION PROTOTYPES +*******************************************************************************/ +int wp_init_proslic(sdla_fe_t *fe, int mod_no, int fast, int sane); + +static int wp_remora_config(void *pfe); +static int wp_remora_unconfig(void *pfe); +static int wp_remora_intr(sdla_fe_t *); +static int wp_remora_check_intr(sdla_fe_t *); +static void wp_remora_enable_timer(sdla_fe_t*, unsigned char, unsigned long); +static int wp_remora_polling(sdla_fe_t*); +static int wp_remora_udp(sdla_fe_t*, void*, unsigned char*); +static unsigned int wp_remora_active_map(sdla_fe_t* fe); +static unsigned char wp_remora_fe_media(sdla_fe_t *fe); +static int wp_remora_set_dtmf(sdla_fe_t*, int, unsigned char); +static int wp_remora_intr_ctrl(sdla_fe_t*, int, int, int, unsigned int); +static int wp_remora_event_ctrl(sdla_fe_t*, wan_event_ctrl_t*); + +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) +static void wp_remora_timer(void*); +#elif defined(__WINDOWS__) +static void wp_remora_timer(IN PKDPC,void*,void*,void*); +#else +static void wp_remora_timer(unsigned long); +#endif + +static int wp_remora_dialtone(sdla_fe_t*); +static int wp_remora_busytone(sdla_fe_t*); +static int wp_remora_ringtone(sdla_fe_t*); +static int wp_remora_congestiontone(sdla_fe_t*); +static int wp_remora_disabletone(sdla_fe_t*); + +/******************************************************************************* +** FUNCTION DEFINITIONS +*******************************************************************************/ + +static void wait_just_a_bit(int foo) +{ + +#if defined(__FreeBSD__) || defined(__OpenBSD__) + WP_SCHEDULE(foo, "A200"); +#else + unsigned long start_ticks; + start_ticks = SYSTEM_TICKS + foo; + while(SYSTEM_TICKS < start_ticks){ + WP_DELAY(10); + WP_SCHEDULE(foo, "A200"); +#if 0 +#if defined(__LINUX__) + schedule(); +#endif +#endif + } +#endif +} + +static void wp_remora_reset_spi(sdla_fe_t *fe) +{ + sdla_t *card = (sdla_t*)fe->card; + + WAN_ASSERT1(card == NULL); + card->hw_iface.bus_write_4( card->hw, + SPI_INTERFACE_REG, + MOD_SPI_RESET); + WP_DELAY(1000); + card->hw_iface.bus_write_4( card->hw, + SPI_INTERFACE_REG, + 0x00000000); + WP_DELAY(1000); + return; +} + + +static int +wp_proslic_setreg_indirect(sdla_fe_t *fe, int mod_no, unsigned char address, unsigned short data) +{ + + WRITE_RM_REG(mod_no, IDA_LO,(unsigned char)(data & 0xFF)); + WRITE_RM_REG(mod_no, IDA_HI,(unsigned char)((data & 0xFF00)>>8)); + WRITE_RM_REG(mod_no, IAA,address); + return 0; +} + +static int +wp_proslic_getreg_indirect(sdla_fe_t *fe, int mod_no, unsigned char address) +{ + int res = -1; + unsigned char data1, data2; + + WRITE_RM_REG(mod_no, IAA, address); + data1 = READ_RM_REG(mod_no, IDA_LO); + data2 = READ_RM_REG(mod_no, IDA_HI); + res = data1 | (data2 << 8); + return res; +} + +static int wp_proslic_init_indirect_regs(sdla_fe_t *fe, int mod_no) +{ + unsigned char i; + + for (i=0; iname, mod_no, + i); + return -1; + } + initial= indirect_regs[i].initial; + + if ( j != initial && indirect_regs[i].altaddr != 255){ + DEBUG_EVENT( + "%s: Module %d: Internal Error: iReg=%s (%X) Value=%X (%X)\n", + fe->name, mod_no, + indirect_regs[i].name, + indirect_regs[i].address, + j, initial); + passed = 0; + } + } + + if (!passed) { + DEBUG_EVENT( + "%s: Module %d: Init Indirect Registers UNSUCCESSFULLY.\n", + fe->name, mod_no); + return -1; + } + return 0; +} + + +static int wp_remora_chain_enable(sdla_fe_t *fe) +{ + int mod_no; + unsigned char byte; + + for(mod_no = 0;mod_no < MAX_REMORA_MODULES; mod_no += 2){ + if (fe->rm_param.mod[mod_no].type == MOD_TYPE_NONE){ + byte = READ_RM_FXS_REG(mod_no, 0, 0); + byte &= 0x0F; + if (byte == 0x05){ + DEBUG_RM("%s: Module %d/%d FXS\n", + fe->name, mod_no,mod_no+1); + fe->rm_param.mod[mod_no].type = + MOD_TYPE_FXS; + fe->rm_param.mod[mod_no+1].type = + MOD_TYPE_FXS; + }else if (byte == 0x00){ + DEBUG_RM("%s: Module %d/%d TEST\n", + fe->name, mod_no,mod_no+1); + fe->rm_param.mod[mod_no].type = + MOD_TYPE_TEST; + fe->rm_param.mod[mod_no+1].type = + MOD_TYPE_TEST; + } + } + } + /* Reset SPI interface */ + wp_remora_reset_spi(fe); + for(mod_no = 0;mod_no < MAX_REMORA_MODULES; mod_no += 2){ + if (fe->rm_param.mod[mod_no].type == MOD_TYPE_NONE){ + byte = READ_RM_FXO_REG(mod_no,1,2); + if (byte == 0x03){ + DEBUG_RM("%s: Module %d/%d FXO\n", + fe->name, mod_no,mod_no+1); + fe->rm_param.mod[mod_no].type = + MOD_TYPE_FXO; + fe->rm_param.mod[mod_no+1].type = + MOD_TYPE_FXO; + } + } + } + + /* Reset SPI interface */ + wp_remora_reset_spi(fe); + + /* Now enable chain mode for only FXS modules (FXO by default chain) */ + for(mod_no = 0;mod_no < MAX_REMORA_MODULES; mod_no += 2){ + if (fe->rm_param.mod[mod_no].type == MOD_TYPE_FXS){ + WRITE_RM_FXS_REG(mod_no,0,0,0xC0); + byte = READ_RM_FXS_REG(mod_no, 1, 0); + if ((byte & 0x80) != 0x80){ + DEBUG_RM( + "%s: Module %d: Failed to enable chain (%02X)!\n", + fe->name, mod_no, byte); + return -EINVAL; + } + }else if (fe->rm_param.mod[mod_no].type == MOD_TYPE_FXO){ + byte = READ_RM_FXO_REG(mod_no,1,2); + if (byte != 0x03){ + /* Should never happened */ + fe->rm_param.mod[mod_no].type = MOD_TYPE_NONE; + fe->rm_param.mod[mod_no+1].type = MOD_TYPE_NONE; + continue; + } + }else if (fe->rm_param.mod[mod_no].type == MOD_TYPE_TEST){ + /* Test module or nothing */ + continue; + }else{ + DEBUG_RM( + "%s: Module %d: Failed to detect FXO/FXS module!\n", + fe->name, mod_no); + continue; + } + DEBUG_RM( + "%s: Module %d/%d %s (chain)\n", + fe->name, mod_no,mod_no+1, + WP_REMORA_DECODE_TYPE(fe->rm_param.mod[mod_no].type)); + fe->rm_param.mod[mod_no].chain = MOD_CHAIN_ENABLED; + fe->rm_param.mod[mod_no+1].chain= MOD_CHAIN_ENABLED; + } + return 0; +} + +static int wp_init_proslic_insane(sdla_fe_t *fe, int mod_no) +{ + unsigned char value; + + value = READ_RM_REG(mod_no, 0); + if ((value & 0x30) >> 4){ + DEBUG_RM("%s: Proslic on module %d is not a Si3210 (%02X)!\n", + fe->name, + mod_no, + value); + return -1; + } + if (((value & 0x0F) == 0) || ((value & 0x0F) == 0x0F)){ + DEBUG_RM("%s: Proslic is not loaded!\n", + fe->name); + return -1; + } + if ((value & 0x0F) < 2){ + DEBUG_EVENT("%s: Proslic 3210 version %d is too old!\n", + fe->name, + value & 0x0F); + return -1; + } + + value = READ_RM_REG(mod_no, 8); + if (value != 0x2) { + DEBUG_EVENT( + "%s: Proslic on module %d insane (1) %d should be 2!\n", + fe->name, mod_no, value); + return -1; + } + + value = READ_RM_REG(mod_no, 64); + if (value != 0x0) { + DEBUG_EVENT( + "%s: Proslic on modyle %d insane (2) %d should be 0!\n", + fe->name, mod_no, value); + return -1; + } + + value = READ_RM_REG(mod_no, 11); + if (value != 0x33) { + DEBUG_EVENT( + "%s: Proslic on module %d insane (3) %02X should be 0x33\n", + fe->name, mod_no, value); + return -1; + } + WRITE_RM_REG(mod_no, 30, 0); + return 0; +} + + +static int wp_powerup_proslic(sdla_fe_t *fe, int mod_no, int fast) +{ + wp_remora_fxs_t *fxs; + unsigned long start_ticks; + int loopcurrent = 20, lim; + unsigned char vbat; + + fxs = &fe->rm_param.mod[mod_no].u.fxs; + /* set the period of the DC-DC converter to 1/64 kHz START OUT SLOW*/ + WRITE_RM_REG(mod_no, 92, 0xf5); + + start_ticks = SYSTEM_TICKS; + WRITE_RM_REG(mod_no, 14, 0x0); /* DIFF DEMO 0x10 */ + + if (fast) return 0; + + /* powerup */ + WRITE_RM_REG(mod_no, 93, 0x1F); + while((vbat = READ_RM_REG(mod_no, 82)) < 0xC0){ + /* Wait no more than 500ms */ + if ((SYSTEM_TICKS - start_ticks) > HZ/2){ + break; + } + wait_just_a_bit(HZ/10); + } + + if (vbat < 0xc0){ + if (fxs->proslic_power == PROSLIC_POWER_UNKNOWN){ + DEBUG_EVENT( + "%s: Module %d: Failed to powerup within %d ms (%d mV only)!\n", + fe->name, + mod_no, + (int)(((SYSTEM_TICKS - start_ticks) * 1000 / HZ)), + vbat * 375); + DEBUG_EVENT( + "%s: Module %d: Did you remember to plug in the power cable?\n", + fe->name, + mod_no); + + } + fxs->proslic_power = PROSLIC_POWER_WARNED; + return -1; + } + fxs->proslic_power = PROSLIC_POWER_ON; + DEBUG_RM("%s: Module %d: Current Battery1 %dV, Battery2 %dV\n", + fe->name, mod_no, + READ_RM_REG(mod_no, 82)*375/1000, + READ_RM_REG(mod_no, 83)*375/1000); + + /* Proslic max allowed loop current, reg 71 LOOP_I_LIMIT */ + /* If out of range, just set it to the default value */ + lim = (loopcurrent - 20) / 3; + if ( loopcurrent > 41 ) { + lim = 0; + DEBUG_RM( + "%s: Module %d: Loop current out of range (default 20mA)!\n", + fe->name, mod_no); + }else{ + DEBUG_RM("%s: Loop current set to %dmA!\n", + fe->name, + (lim*3)+20); + } + WRITE_RM_REG(mod_no, 71,lim); + + WRITE_RM_REG(mod_no, 93, 0x99); /* DC-DC Calibration */ +#if 1 + /* Wait for DC-DC Calibration to complete */ + start_ticks = SYSTEM_TICKS; + while(0x80 & READ_RM_REG(mod_no, 93)){ + if ((SYSTEM_TICKS - start_ticks) > 2*HZ){ + DEBUG_EVENT( + "%s: Module %d: Timeout waiting for DC-DC calibration\n", + fe->name, + mod_no); + return -EINVAL; + } + wait_just_a_bit(HZ/10); + } +#endif + return 0; +} + +static int wp_proslic_powerleak_test(sdla_fe_t *fe, int mod_no) +{ + unsigned long start_ticks; + unsigned char vbat; + + /* powerleak */ + WRITE_RM_REG(mod_no, 64, 0); + WRITE_RM_REG(mod_no, 14, 0x10); + /* wait for 1 s */ + start_ticks = SYSTEM_TICKS; + while((vbat = READ_RM_REG(mod_no, 82)) >= 0x6){ + if ((SYSTEM_TICKS - start_ticks) > (HZ/2)){ + break; + } + wait_just_a_bit(HZ/10); + } + if (vbat < 0x6){ + DEBUG_EVENT( + "%s: Module %d: Excessive leakage detected: %d volts (%02x) after %d ms\n", + fe->name, mod_no, + 376 * vbat / 1000, + vbat, + (int)((SYSTEM_TICKS - start_ticks) * 1000 / HZ)); + return -1; + } + DEBUG_RM("%s: Module %d: Post-leakage voltage: %d volts\n", + fe->name, + mod_no, + 376 * vbat / 1000); + + return 0; +} + + +/* static */ +int wp_init_proslic(sdla_fe_t *fe, int mod_no, int fast, int sane) +{ + volatile unsigned long start_ticks; + unsigned short tmp[5]; + unsigned char value; + volatile int i, x; + + /* By default, don't send on hook */ + if (fe->fe_cfg.cfg.remora.reversepolarity){ + fe->rm_param.mod[mod_no].u.fxs.idletxhookstate = 5; + }else{ + fe->rm_param.mod[mod_no].u.fxs.idletxhookstate = 1; + } + + /* Step 8 */ + if (!sane && wp_init_proslic_insane(fe, mod_no)){ + return -2; + } + + if (sane){ + WRITE_RM_REG(mod_no, 14, 0x10); + } + + /* Step 9 */ + if (wp_proslic_init_indirect_regs(fe, mod_no)) { + DEBUG_EVENT( + "%s: Module %d: Indirect Registers failed to initialize!\n", + fe->name, + mod_no); + return -1; + } + wp_proslic_setreg_indirect(fe, mod_no, 97,0); + + /* Steo 10 */ + WRITE_RM_REG(mod_no, 8, 0); /*DIGIUM*/ + WRITE_RM_REG(mod_no, 108, 0xeb); /*DIGIUM*/ + WRITE_RM_REG(mod_no, 67, 0x17); + WRITE_RM_REG(mod_no, 66, 1); + + /* Flush ProSLIC digital filters by setting to clear, while + ** saving old values */ + for (x=0;x<5;x++) { + tmp[x] = wp_proslic_getreg_indirect(fe, mod_no, x + 35); + wp_proslic_setreg_indirect(fe, mod_no, x + 35, 0x8000); + } + + /* Power up the DC-DC converter */ + if (wp_powerup_proslic(fe, mod_no, fast)) { + DEBUG_EVENT( + "%s: Module %d: Unable to do INITIAL ProSLIC powerup!\n", + fe->name, + mod_no); + return -1; + } + + if (!fast){ + + if (wp_proslic_powerleak_test(fe, mod_no)){ + DEBUG_EVENT( + "%s: Module %d: Proslic failed leakge the short circuit\n", + fe->name, + mod_no); + } + + /* Step 12 */ + if (wp_powerup_proslic(fe, mod_no, fast)) { + DEBUG_EVENT( + "%s: Module %d: Unable to do INITIAL ProSLIC powerup!\n", + fe->name, + mod_no); + return -1; + } + + /* Step 13 */ + WRITE_RM_REG(mod_no, 64, 0); + + /* Step 14 */ + WRITE_RM_REG(mod_no, 97, 0x1E); + WRITE_RM_REG(mod_no, 96, 0x47); + + /* Step 15 */ + start_ticks = SYSTEM_TICKS; + while(READ_RM_REG(mod_no, 96) != 0){ + if ((SYSTEM_TICKS - start_ticks) > 400){ + DEBUG_EVENT( + "%s: Module %d: Timeout on SLIC calibration (15)!\n", + fe->name, mod_no); + return -1; + } + wait_just_a_bit(HZ/10); + } + + /* Step 16 */ + /* Insert manual calibration for sangoma Si3210 */ + WRITE_RM_REG(mod_no, 98, 0x10); + //WRITE_RM_REG(mod_no, 98, 0x1F/*0x10*/); + for (i = 0x1f; i > 0; i--){ + + WRITE_RM_REG(mod_no, 98, i); + wait_just_a_bit(4); + if ((READ_RM_REG(mod_no, 88)) == 0){ + break; + } + } + + WRITE_RM_REG(mod_no, 99, 0x10); + //WRITE_RM_REG(mod_no, 99, 0x1F/*0x10*/); + for (i = 0x1f; i > 0; i--){ + + WRITE_RM_REG(mod_no, 99, i); + wait_just_a_bit(4); + if ((READ_RM_REG(mod_no, 89)) == 0){ + break; + } + } + + /* Step 17 */ + value = READ_RM_REG(mod_no, 23); + WRITE_RM_REG(mod_no, 23, value | 0x04); + + /* Step 18 */ + /* DAC offset and without common mode calibration. */ + WRITE_RM_REG(mod_no, 97, 0x01/*0x18*/); /* Manual after */ + /* Calibrate common mode and differential DAC mode DAC + ILIM */ + WRITE_RM_REG(mod_no, 96, 0x40/*0x47*/); + + /* Step 19 */ + start_ticks = SYSTEM_TICKS; + while(READ_RM_REG(mod_no, 96) != 0){ + if ((SYSTEM_TICKS - start_ticks) > 2000/*400*/){ + DEBUG_EVENT( + "%s: Module %d: Timeout on SLIC calibration (19:%02X)!\n", + fe->name, + mod_no, + READ_RM_REG(mod_no, 96)); + return -1; + } + wait_just_a_bit(HZ/10); + } + DEBUG_RM("%s: SLIC calibration complete (%ld)\n", + fe->name, SYSTEM_TICKS-start_ticks); + /* Save calibration vectors */ + for (x=0;xrm_param.mod[mod_no].u.fxs.callregs.vals[x] = + READ_RM_REG(mod_no, 96 + x); + } + + }else{ + /* Restore calibration vectors */ + for (x=0;xrm_param.mod[mod_no].u.fxs.callregs.vals[x]); + } + } + + /* Step 20 */ + wp_proslic_setreg_indirect(fe, mod_no, 88, 0); + wp_proslic_setreg_indirect(fe, mod_no, 89, 0); + wp_proslic_setreg_indirect(fe, mod_no, 90, 0); + wp_proslic_setreg_indirect(fe, mod_no, 91, 0); + wp_proslic_setreg_indirect(fe, mod_no, 92, 0); + wp_proslic_setreg_indirect(fe, mod_no, 93, 0); + wp_proslic_setreg_indirect(fe, mod_no, 94, 0); + wp_proslic_setreg_indirect(fe, mod_no, 95, 0); + + if (!fast){ + /* Disable interrupt while full initialization */ + fe->rm_param.mod[mod_no].u.fxs.imask1 = 0x00; + WRITE_RM_REG(mod_no, 21, 0); + fe->rm_param.mod[mod_no].u.fxs.imask2 = 0x00; + WRITE_RM_REG(mod_no, 22, 0); + fe->rm_param.mod[mod_no].u.fxs.imask3 = 0x00; + WRITE_RM_REG(mod_no, 23, 0); + } + + WRITE_RM_REG(mod_no, 64, 0);/* (0) */ + + //Alex Apr 3 - WRITE_RM_REG(mod_no, 64, 0x1); + + value = READ_RM_REG(mod_no, 68); + /* + ** FIXME ???value = value & 0x03; + ** if (value & 4){ + ** printf("Module %d Timeout!\n", mod_no); + ** return -1; + ** } */ + +#if 1 + WRITE_RM_REG(mod_no, 64, 0x00); + + /* this is a singular calibration bit for longitudinal calibration */ + WRITE_RM_REG(mod_no, 97, 0x01); + WRITE_RM_REG(mod_no, 96, 0x40); + + value = READ_RM_REG(mod_no, 96); + + WRITE_RM_REG(mod_no, 18,0xff); + WRITE_RM_REG(mod_no, 19,0xff); + WRITE_RM_REG(mod_no, 20,0xff); + + /* WRITE_RM_REG(mod_no, 64,0x1); */ +#endif + + /* Perform DC-DC calibration */ + WRITE_RM_REG(mod_no, 93, 0x99); + /*wait_just_a_bit(10);*/ + value = READ_RM_REG(mod_no, 107); + if ((value < 0x2) || (value > 0xd)) { + DEBUG_EVENT( + "%s: Module %d: DC-DC calibration has a surprising direct 107 of 0x%02x!\n", + fe->name, + mod_no, + value); + WRITE_RM_REG(mod_no, 107, 0x8); + } + + for (x=0;x<5;x++) { + wp_proslic_setreg_indirect(fe, mod_no, x + 35, tmp[x]); + } + + if (wp_proslic_verify_indirect_regs(fe, mod_no)) { + DEBUG_EVENT( + "%s: Module %d: Indirect Registers failed verification.\n", + fe->name, + mod_no); + return -1; + } + + if (fe->fe_cfg.tdmv_law == WAN_TDMV_ALAW){ + WRITE_RM_REG(mod_no, 1, 0x20); + }else if (fe->fe_cfg.tdmv_law == WAN_TDMV_MULAW){ + WRITE_RM_REG(mod_no, 1, 0x28); + } + /* U-Law 8-bit interface */ + /* Tx Start count low byte 0 */ + WRITE_RM_REG(mod_no, 2, mod_no * 8 + 1); + /* Tx Start count high byte 0 */ + WRITE_RM_REG(mod_no, 3, 0); + /* Rx Start count low byte 0 */ + WRITE_RM_REG(mod_no, 4, mod_no * 8 + 1); + /* Rx Start count high byte 0 */ + WRITE_RM_REG(mod_no, 5, 0); + /* Clear all interrupt */ + WRITE_RM_REG(mod_no, 18, 0xff); + WRITE_RM_REG(mod_no, 19, 0xff); + WRITE_RM_REG(mod_no, 20, 0xff); + WRITE_RM_REG(mod_no, 73, 0x04); + +#if 0 + /* Enable loopback */ + WRITE_RM_REG(mod_no, 8, 0x2); + WRITE_RM_REG(mod_no, 14, 0x0); + WRITE_RM_REG(mod_no, 64, 0x0); + WRITE_RM_REG(mod_no, 1, 0x08); +#endif + + WRITE_RM_REG(mod_no, 64, 0x1); + + DEBUG_RM("%s: Module %d: Current Battery1 %dV, Battery2 %dV (%d)\n", + fe->name, mod_no, + READ_RM_REG(mod_no, 82)*375/1000, + READ_RM_REG(mod_no, 83)*375/1000, + __LINE__); + + /* verify TIP/RING voltage */ + wait_just_a_bit(HZ); + start_ticks = SYSTEM_TICKS; + while(READ_RM_REG(mod_no, 81) < 0x75){ + if ((SYSTEM_TICKS - start_ticks) > HZ*10){ + break; + } + wait_just_a_bit(HZ); + } + wait_just_a_bit(HZ); + if (READ_RM_REG(mod_no, 81) < 0x75){ + if (sane){ + DEBUG_EVENT( + "%s: Module %d: TIP/RING is too low on FXS %d!\n", + fe->name, + mod_no, + READ_RM_REG(mod_no, 81) * 375 / 1000); + } + return -1; + } + + DEBUG_RM("%s: Module %d: Current Battery1 %dV, Battery2 %dV (%d)\n", + fe->name, mod_no, + READ_RM_REG(mod_no, 82)*375/1000, + READ_RM_REG(mod_no, 83)*375/1000, + __LINE__); + + /* lowpower */ + //WRITE_RM_REG(mod_no, 72, 0x14); + //todayWRITE_RM_REG(mod_no, 64, 0x1); + return 0; +} + +static int wp_voicedaa_insane(sdla_fe_t *fe, int mod_no) +{ + unsigned char byte; + + byte = READ_RM_REG(mod_no, 2); + if (byte != 0x3) + return -2; + byte = READ_RM_REG(mod_no, 11); + DEBUG_TEST("%s: Module %d: VoiceDAA System: %02x\n", + fe->name, + mod_no, + byte & 0xf); + return 0; +} + + +static int wp_init_voicedaa(sdla_fe_t *fe, int mod_no, int sane) +{ + unsigned char reg16=0, reg26=0, reg30=0, reg31=0; + unsigned long start_ticks; + + if (!sane && wp_voicedaa_insane(fe, mod_no)){ + return -2; + } + + /* Software reset */ + WRITE_RM_REG(mod_no, 1, 0x80); + + /* Wait just a bit */ + wait_just_a_bit(HZ/10); + + /* Enable PCM, ulaw */ + if (fe->fe_cfg.tdmv_law == WAN_TDMV_ALAW){ + WRITE_RM_REG(mod_no, 33, 0x20); + }else if (fe->fe_cfg.tdmv_law == WAN_TDMV_MULAW){ + WRITE_RM_REG(mod_no, 33, 0x28); + } + + /* Set On-hook speed, Ringer impedence, and ringer threshold */ + reg16 |= (fxo_modes[fe->fe_cfg.cfg.remora.opermode].ohs << 6); + reg16 |= (fxo_modes[fe->fe_cfg.cfg.remora.opermode].rz << 1); + reg16 |= (fxo_modes[fe->fe_cfg.cfg.remora.opermode].rt); + WRITE_RM_REG(mod_no, 16, reg16); + + /* Set DC Termination: + ** Tip/Ring voltage adjust, + ** minimum operational current, + ** current limitation */ + reg26 |= (fxo_modes[fe->fe_cfg.cfg.remora.opermode].dcv << 6); + reg26 |= (fxo_modes[fe->fe_cfg.cfg.remora.opermode].mini << 4); + reg26 |= (fxo_modes[fe->fe_cfg.cfg.remora.opermode].ilim << 1); + WRITE_RM_REG(mod_no, 26, reg26); + + /* Set AC Impedence */ + reg30 = (fxo_modes[fe->fe_cfg.cfg.remora.opermode].acim); + WRITE_RM_REG(mod_no, 30, reg30); + + /* Misc. DAA parameters */ + reg31 = 0xa3; + reg31 |= (fxo_modes[fe->fe_cfg.cfg.remora.opermode].ohs2 << 3); + WRITE_RM_REG(mod_no, 31, reg31); + + /* Set Transmit/Receive timeslot */ + WRITE_RM_REG(mod_no, 34, mod_no * 8 + 1); + WRITE_RM_REG(mod_no, 35, 0x00); + WRITE_RM_REG(mod_no, 36, mod_no * 8 + 1); + WRITE_RM_REG(mod_no, 37, 0x00); + + /* Enable ISO-Cap */ + WRITE_RM_REG(mod_no, 6, 0x00); + + /* Wait 1000ms for ISO-cap to come up */ + start_ticks = SYSTEM_TICKS + 2*HZ; + while(!(READ_RM_REG(mod_no, 11) & 0xf0)){ + if (SYSTEM_TICKS > start_ticks){ + break; + } + wait_just_a_bit(HZ/10); + } + + if (!(READ_RM_REG(mod_no, 11) & 0xf0)) { + DEBUG_EVENT( + "%s: Module %d: VoiceDAA did not bring up ISO link properly!\n", + fe->name, + mod_no); + return -1; + } + DEBUG_TEST("%s: Module %d: ISO-Cap is now up, line side: %02x rev %02x\n", + fe->name, + mod_no, + READ_RM_REG(mod_no, 11) >> 4, + (READ_RM_REG(mod_no, 13) >> 2) & 0xf); + + /* Enable on-hook line monitor */ + WRITE_RM_REG(mod_no, 5, 0x08); + + /* NZ -- crank the tx gain up by 7 dB */ + if (!strcmp(fxo_modes[fe->fe_cfg.cfg.remora.opermode].name, "NEWZEALAND")) { + DEBUG_EVENT("%s: Module %d: Adjusting gain\n", + fe->name, + mod_no); + WRITE_RM_REG(mod_no, 38, 0x7); + } + + return 0; +} + + +/****************************************************************************** +** wp_remora_iface_init) - +** +** OK +*/ +int wp_remora_iface_init(void *pfe_iface) +{ + sdla_fe_iface_t *fe_iface = (sdla_fe_iface_t*)pfe_iface; + + fe_iface->config = &wp_remora_config; + fe_iface->unconfig = &wp_remora_unconfig; + fe_iface->active_map = &wp_remora_active_map; + fe_iface->isr = &wp_remora_intr; + fe_iface->check_isr = &wp_remora_check_intr; + fe_iface->polling = &wp_remora_polling; + fe_iface->process_udp = &wp_remora_udp; + fe_iface->get_fe_media = &wp_remora_fe_media; + fe_iface->set_dtmf = &wp_remora_set_dtmf; + fe_iface->intr_ctrl = &wp_remora_intr_ctrl; + fe_iface->event_ctrl = &wp_remora_event_ctrl; + return 0; +} + +/****************************************************************************** +** wp_remora_opermode() - +** +** OK +*/ +static int wp_remora_opermode(sdla_fe_t *fe) +{ + sdla_fe_cfg_t *fe_cfg = &fe->fe_cfg; + + if (!strlen(fe_cfg->cfg.remora.opermode_name)){ + memcpy(fe_cfg->cfg.remora.opermode_name, "FCC", 3); + fe_cfg->cfg.remora.opermode = 0; + }else{ + int x; + for (x=0;x<(sizeof(fxo_modes) / sizeof(fxo_modes[0])); x++) { + if (!strcmp(fxo_modes[x].name, fe_cfg->cfg.remora.opermode_name)) + break; + } + if (x < sizeof(fxo_modes) / sizeof(fxo_modes[0])) { + fe_cfg->cfg.remora.opermode = x; + } else { + DEBUG_EVENT( + "%s: Invalid/unknown operating mode '%s' specified\n", + fe->name, + fe_cfg->cfg.remora.opermode_name); + DEBUG_EVENT( + "%s: Please choose one of:\n", + fe->name); + for (x=0;xname, fxo_modes[x].name); + return -ENODEV; + } + } + + return 0; +} + +/****************************************************************************** +** wp_remora_config() - +** +** OK +*/ +static int wp_remora_config(void *pfe) +{ + sdla_fe_t *fe = (sdla_fe_t*)pfe; + int err=0, mod_no, mod_cnt = 0, err_cnt = 0, retry; + int sane=0; + + DEBUG_EVENT("%s: Configuring FXS/FXO Front End ...\n", + fe->name); + fe->rm_param.max_fe_channels = MAX_REMORA_MODULES; + fe->rm_param.module_map = 0; + fe->rm_param.intcount = 0; + + if (wp_remora_opermode(fe)){ + return -EINVAL; + } + + wait_just_a_bit(HZ); + /* Reset SPI interface */ + wp_remora_reset_spi(fe); + + /* Search for installed modules and enable chain for all modules */ + if (wp_remora_chain_enable(fe)){ + DEBUG_EVENT("%s: Failed enable chain mode for all modules!\n", + fe->name); + return -EINVAL; + } + + /* Auto detect FXS and FXO modules */ + for(mod_no = 0; mod_no < MAX_REMORA_MODULES; mod_no++){ + sane = 0; err = 0; retry = 0; +retry_cfg: + switch(fe->rm_param.mod[mod_no].type){ + case MOD_TYPE_FXS: + if (!(err = wp_init_proslic(fe, mod_no, 0, sane))){ + DEBUG_EVENT( + "%s: Module %d: Installed -- Auto FXS!\n", + fe->name, + mod_no); + wan_set_bit(mod_no, &fe->rm_param.module_map); + mod_cnt++; +#if 0 + }else{ + DEBUG_EVENT( + "%s: Module %d: FXS failed!\n", + fe->name, + mod_no); + err_cnt++; +#endif + } + break; + + case MOD_TYPE_FXO: + err = wp_init_voicedaa(fe, mod_no, sane); + if (!err){ + DEBUG_EVENT( + "%s: Module %d: Installed -- Auto FXO (%s mode)!\n", + fe->name, + mod_no, + fxo_modes[fe->fe_cfg.cfg.remora.opermode].name); + wan_set_bit(mod_no, &fe->rm_param.module_map); + mod_cnt++; +#if 0 + }else{ + DEBUG_EVENT( + "%s: Module %d: FXO failed!\n", + fe->name, + mod_no); + err_cnt++; +#endif + } + break; + + case MOD_TYPE_TEST: + DEBUG_EVENT( + "%s: Module %d: Installed -- FXS/FXO tester!\n", + fe->name, + mod_no); + wan_set_bit(mod_no, &fe->rm_param.module_map); + mod_cnt++; + break; + default: + DEBUG_TDMV("%s: Module %d: Not Installed!\n", + fe->name, + mod_no); + break; + } + if (err/* && !sane*/){ + sane = 1; + if (retry++ < 10) goto retry_cfg; + DEBUG_EVENT("%s: Module %d: %s failed!\n", + fe->name, + mod_no, + WP_REMORA_DECODE_TYPE(fe->rm_param.mod[mod_no].type)); + err_cnt++; + } + } + + if (err_cnt){ + DEBUG_EVENT("%s: %d FXO/FXS module(s) are failed to initialize!\n", + fe->name, err_cnt); + return -EINVAL; + } + + if (mod_cnt == 0){ + DEBUG_EVENT("%s: No FXO/FXS modules are found!\n", + fe->name); + // return -EINVAL; + } + /* Initialize and start T1/E1 timer */ + wan_set_bit(WP_RM_TIMER_KILL,(void*)&fe->rm_param.critical); + + wan_init_timer( + &fe->rm_param.timer, + wp_remora_timer, + (wan_timer_arg_t)fe); + + wan_clear_bit(WP_RM_TIMER_KILL,(void*)&fe->rm_param.critical); + wan_clear_bit(WP_RM_TIMER_RUNNING,(void*)&fe->rm_param.critical); + wan_set_bit(WP_RM_CONFIGURED,(void*)&fe->rm_param.critical); + +#if 0 + wp_remora_event_ctrl( + fe, 0, + WAN_RM_EVENT_DTMF|WAN_RM_EVENT_LC|WAN_RM_EVENT_RT, + WAN_RM_EVENT_ENABLE, 0x00); +#endif + + return 0; +} + +/****************************************************************************** +** wp_remora_unconfig() - +** +** OK +*/ +static int wp_remora_unconfig(void *pfe) +{ + sdla_fe_t *fe = (sdla_fe_t*)pfe; + int mod_no; + + DEBUG_EVENT("%s: Unconfiguring FXS/FXO Front End...\n", + fe->name); + + /* Clear and Kill TE timer poll command */ + wan_clear_bit(WP_RM_CONFIGURED,(void*)&fe->rm_param.critical); + wan_set_bit(WP_RM_TIMER_KILL,(void*)&fe->rm_param.critical); + + wan_del_timer(&fe->rm_param.timer); + + wan_clear_bit(WP_RM_TIMER_RUNNING,(void*)&fe->rm_param.critical); + fe->rm_param.timer_cmd = 0x00; + + for(mod_no = 0; mod_no < MAX_REMORA_MODULES; mod_no++){ + if (wan_test_bit(mod_no, &fe->rm_param.module_map)) { + wp_remora_intr_ctrl(fe, mod_no, WAN_RM_INTR_GLOBAL, WAN_FE_INTR_MASK, 0x00); + wan_clear_bit(mod_no, &fe->rm_param.module_map); + } + } + return 0; +} + +static unsigned int wp_remora_active_map(sdla_fe_t* fe) +{ + return fe->rm_param.module_map; +} + +/****************************************************************************** + * wp_remora_fe_status() + * + * Description: + * Arguments: + * Returns: + ****************************************************************************** + */ +static unsigned char wp_remora_fe_media(sdla_fe_t *fe) +{ + return fe->fe_cfg.media; +} + +/****************************************************************************** + * wp_remora_set_dtmf() + * + * Description: + * Arguments: + * Returns: + ****************************************************************************** + */ +static int wp_remora_set_dtmf(sdla_fe_t *fe, int mod_no, unsigned char val) +{ + + if (mod_no > MAX_REMORA_MODULES){ + DEBUG_EVENT("%s: Module %d: Module number out of range!\n", + fe->name, mod_no); + return -EINVAL; + } + if (!wan_test_bit(mod_no-1, &fe->rm_param.module_map)){ + DEBUG_EVENT("%s: Module %d: Not configures yet!\n", + fe->name, mod_no); + return -EINVAL; + } + + return -EINVAL; +} + +/* + ****************************************************************************** + * sdla_remora_timer() + * + * Description: + * Arguments: + * Returns: + ****************************************************************************** + */ +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) +static void wp_remora_timer(void* pfe) +#elif defined(__WINDOWS__) +static void wp_remora_timer(IN PKDPC Dpc, void* pfe, void* arg2, void* arg3) +#else +static void wp_remora_timer(unsigned long pfe) +#endif +{ + sdla_fe_t *fe = (sdla_fe_t*)pfe; + sdla_t *card = (sdla_t*)fe->card; + wan_device_t *wandev = &card->wandev; + + if (wan_test_bit(WP_RM_TIMER_KILL,(void*)&fe->rm_param.critical)){ + wan_clear_bit(WP_RM_TIMER_RUNNING,(void*)&fe->rm_param.critical); + return; + } + /*WAN_ASSERT1(wandev->fe_enable_timer == NULL); */ + DEBUG_TIMER("%s: RM timer!\n", fe->name); + /* Enable hardware interrupt for TE1 */ + + if (wandev->fe_enable_timer){ + wandev->fe_enable_timer(fe->card); + }else{ + wp_remora_polling(fe); + } + + return; +} + +/* + ****************************************************************************** + * wp_remora_enable_timer() + * + * Description: Enable software timer interrupt in delay ms. + * Arguments: + * Returns: + ****************************************************************************** + */ +static void +wp_remora_enable_timer(sdla_fe_t* fe, unsigned char cmd, unsigned long delay) +{ + sdla_t *card = (sdla_t*)fe->card; + + WAN_ASSERT1(card == NULL); + + DEBUG_TEST("%s: %s:%d Cmd=0x%X\n", + fe->name,__FUNCTION__,__LINE__,cmd); + +#if defined (__WINDOWS__) + if(KeGetCurrentIrql() > DISPATCH_LEVEL){ + /* May get here on AFT card because front end interrupt + is handled inside ISR not in DPC as on S514. + The KeSetTimer() function is illegal inside ISR, + so queue 'front_end_dpc_obj' DPC and this routine + will be called again from xilinx_front_end_dpc(). + */ + card->xilinx_fe_dpc.te_timer_delay = delay; + fe->rm_param.timer_cmd=(unsigned char)cmd; + + if(KeInsertQueueDpc(&card->front_end_dpc_obj, NULL, + (PVOID)ENABLE_TE_TIMER) == FALSE){ + + DEBUG_TE1("Failed to queue 'front_end_dpc_obj'!\n"); + }else{ + DEBUG_TEST("Successfully queued 'front_end_dpc_obj'.\n"); + } + return; + } +#endif + if (wan_test_bit(WP_RM_TIMER_KILL,(void*)&fe->rm_param.critical)){ + wan_clear_bit( + WP_RM_TIMER_RUNNING, + (void*)&fe->rm_param.critical); + return; + } + + if (wan_test_bit(WP_RM_TIMER_RUNNING,(void*)&fe->rm_param.critical)){ + if (fe->rm_param.timer_cmd == cmd){ + /* Just ignore current request */ + return; + } + DEBUG_TEST("%s: WP_RM_TIMER_RUNNING: new_cmd=%X curr_cmd=%X\n", + fe->name, + cmd, + fe->rm_param.timer_cmd); + return; + } + + wan_set_bit(WP_RM_TIMER_RUNNING,(void*)&fe->rm_param.critical); + + fe->rm_param.timer_cmd=cmd; + + wan_add_timer(&fe->rm_param.timer, delay * HZ / 1000); + return; +} + +static int wp_remora_polling(sdla_fe_t* fe) +{ + sdla_t *card = (sdla_t*)fe->card; + int mod_no = fe->rm_param.timer_mod_no; + int err = 0; + + WAN_ASSERT(fe->write_fe_reg == NULL); + WAN_ASSERT(fe->read_fe_reg == NULL); + + DEBUG_RM("%s: RM Polling State=%s Cmd=0x%X!\n", + fe->name, fe->fe_status==FE_CONNECTED?"Con":"Disconn", + fe->rm_param.timer_cmd); + + wan_clear_bit(WP_RM_TIMER_RUNNING,(void*)&fe->rm_param.critical); + + switch(fe->rm_param.timer_cmd){ + + case WP_RM_POLL_TONE_DIAL: + wp_remora_dialtone(fe); + wp_remora_enable_timer( fe, + WP_RM_POLL_TONE_BUSY, + WP_RM_POLL_TONE_TIMER); + break; + case WP_RM_POLL_TONE_BUSY: + wp_remora_busytone(fe); + wp_remora_enable_timer( fe, + WP_RM_POLL_TONE_RING, + WP_RM_POLL_TONE_TIMER); + break; + case WP_RM_POLL_TONE_RING: + wp_remora_ringtone(fe); + wp_remora_enable_timer( fe, + WP_RM_POLL_TONE_CONGESTION, + WP_RM_POLL_TONE_TIMER); + break; + case WP_RM_POLL_TONE_CONGESTION: + wp_remora_congestiontone(fe); + wp_remora_enable_timer( fe, + WP_RM_POLL_TONE_DONE, + WP_RM_POLL_TONE_TIMER); + break; + case WP_RM_POLL_TONE_DONE: + wp_remora_disabletone(fe); + break; + case WP_RM_POLL_RING: + DEBUG_EVENT("%s: Module %d: Start ringing...\n", + fe->name, fe->rm_param.timer_mod_no); + WRITE_RM_REG(fe->rm_param.timer_mod_no, 64, 0x04); + wp_remora_enable_timer( fe, + WP_RM_POLL_RING_STOP, + WP_RM_POLL_RING_TIMER); + break; + case WP_RM_POLL_RING_STOP: + DEBUG_EVENT("%s: Module %d: Stop ringing...\n", + fe->name, fe->rm_param.timer_mod_no); + WRITE_RM_REG(fe->rm_param.timer_mod_no, 64, 0x01); + break; + case WP_RM_POLL_EVENT: + if (fe->rm_param.mod[mod_no].type == MOD_TYPE_FXS){ + WRITE_RM_REG(mod_no, 21, fe->rm_param.mod[mod_no].u.fxs.imask1); + WRITE_RM_REG(mod_no, 22, fe->rm_param.mod[mod_no].u.fxs.imask2); + WRITE_RM_REG(mod_no, 23, fe->rm_param.mod[mod_no].u.fxs.imask3); + } + break; +#if defined(CONFIG_PRODUCT_WANPIPE_TDM_VOICE) + case WP_RM_POLL_TDMV: + WAN_TDMV_CALL(polling, (card), err); + break; +#endif + case WP_RM_POLL_INIT: + wp_init_proslic(fe, mod_no, 1, 1); + break; + } + return 0; +} + +static int wp_remora_dialtone(sdla_fe_t *fe) +{ + int mod_no = fe->rm_param.timer_mod_no; + + DEBUG_EVENT("%s: Module %d: Enable Dial tone\n", + fe->name, mod_no); + wp_proslic_setreg_indirect(fe, mod_no, 13,DIALTONE_IR13); + wp_proslic_setreg_indirect(fe, mod_no, 14,DIALTONE_IR14); + wp_proslic_setreg_indirect(fe, mod_no, 16,DIALTONE_IR16); + wp_proslic_setreg_indirect(fe, mod_no, 17,DIALTONE_IR17); + + WRITE_RM_REG(mod_no, 36, DIALTONE_DR36); + WRITE_RM_REG(mod_no, 37, DIALTONE_DR37); + WRITE_RM_REG(mod_no, 38, DIALTONE_DR38); + WRITE_RM_REG(mod_no, 39, DIALTONE_DR39); + WRITE_RM_REG(mod_no, 40, DIALTONE_DR40); + WRITE_RM_REG(mod_no, 41, DIALTONE_DR41); + WRITE_RM_REG(mod_no, 42, DIALTONE_DR42); + WRITE_RM_REG(mod_no, 43, DIALTONE_DR43); + + WRITE_RM_REG(mod_no, 32, DIALTONE_DR32); + WRITE_RM_REG(mod_no, 33, DIALTONE_DR33); + return 0; +} + +static int wp_remora_busytone(sdla_fe_t *fe) +{ + int mod_no = fe->rm_param.timer_mod_no; + + DEBUG_EVENT("%s: Module %d: Enable Busy tone\n", + fe->name, mod_no); + wp_proslic_setreg_indirect(fe, mod_no, 13,BUSYTONE_IR13); + wp_proslic_setreg_indirect(fe, mod_no, 14,BUSYTONE_IR14); + wp_proslic_setreg_indirect(fe, mod_no, 16,BUSYTONE_IR16); + wp_proslic_setreg_indirect(fe, mod_no, 17,BUSYTONE_IR17); + + WRITE_RM_REG(mod_no, 6, BUSYTONE_DR36); + WRITE_RM_REG(mod_no, 37, BUSYTONE_DR37); + WRITE_RM_REG(mod_no, 38, BUSYTONE_DR38); + WRITE_RM_REG(mod_no, 39, BUSYTONE_DR39); + WRITE_RM_REG(mod_no, 40, BUSYTONE_DR40); + WRITE_RM_REG(mod_no, 41, BUSYTONE_DR41); + WRITE_RM_REG(mod_no, 42, BUSYTONE_DR42); + WRITE_RM_REG(mod_no, 43, BUSYTONE_DR43); + + WRITE_RM_REG(mod_no, 32, BUSYTONE_DR32); + WRITE_RM_REG(mod_no, 33, BUSYTONE_DR33); + return 0; +} + +static int wp_remora_ringtone(sdla_fe_t *fe) +{ + int mod_no = fe->rm_param.timer_mod_no; + + DEBUG_EVENT("%s: Module %d: Enable Ring tone\n", + fe->name, mod_no); + wp_proslic_setreg_indirect(fe, mod_no, 13,RINGBACKTONE_IR13); + wp_proslic_setreg_indirect(fe, mod_no, 14,RINGBACKTONE_IR14); + wp_proslic_setreg_indirect(fe, mod_no, 16,RINGBACKTONE_IR16); + wp_proslic_setreg_indirect(fe, mod_no, 17,RINGBACKTONE_IR17); + + WRITE_RM_REG(mod_no, 36, RINGBACKTONE_DR36); + WRITE_RM_REG(mod_no, 37, RINGBACKTONE_DR37); + WRITE_RM_REG(mod_no, 38, RINGBACKTONE_DR38); + WRITE_RM_REG(mod_no, 39, RINGBACKTONE_DR39); + WRITE_RM_REG(mod_no, 40, RINGBACKTONE_DR40); + WRITE_RM_REG(mod_no, 41, RINGBACKTONE_DR41); + WRITE_RM_REG(mod_no, 42, RINGBACKTONE_DR42); + WRITE_RM_REG(mod_no, 43, RINGBACKTONE_DR43); + + WRITE_RM_REG(mod_no, 32, RINGBACKTONE_DR32); + WRITE_RM_REG(mod_no, 33, RINGBACKTONE_DR33); + return 0; +} + +static int wp_remora_congestiontone(sdla_fe_t *fe) +{ + int mod_no = fe->rm_param.timer_mod_no; + + DEBUG_EVENT("%s: Module %d: Enable Congestion tone\n", + fe->name, mod_no); + wp_proslic_setreg_indirect(fe, mod_no, 13,CONGESTIONTONE_IR13); + wp_proslic_setreg_indirect(fe, mod_no, 14,CONGESTIONTONE_IR14); + wp_proslic_setreg_indirect(fe, mod_no, 16,CONGESTIONTONE_IR16); + wp_proslic_setreg_indirect(fe, mod_no, 17,CONGESTIONTONE_IR17); + + WRITE_RM_REG(mod_no, 36, CONGESTIONTONE_DR36); + WRITE_RM_REG(mod_no, 37, CONGESTIONTONE_DR37); + WRITE_RM_REG(mod_no, 38, CONGESTIONTONE_DR38); + WRITE_RM_REG(mod_no, 39, CONGESTIONTONE_DR39); + WRITE_RM_REG(mod_no, 40, CONGESTIONTONE_DR40); + WRITE_RM_REG(mod_no, 41, CONGESTIONTONE_DR41); + WRITE_RM_REG(mod_no, 42, CONGESTIONTONE_DR42); + WRITE_RM_REG(mod_no, 43, CONGESTIONTONE_DR43); + + WRITE_RM_REG(mod_no, 32, CONGESTIONTONE_DR32); + WRITE_RM_REG(mod_no, 33, CONGESTIONTONE_DR33); + return 0; +} + +static int wp_remora_disabletone(sdla_fe_t* fe) +{ + int mod_no = fe->rm_param.timer_mod_no; + + WRITE_RM_REG(mod_no, 32, 0); + WRITE_RM_REG(mod_no, 33, 0); + WRITE_RM_REG(mod_no, 36, 0); + WRITE_RM_REG(mod_no, 37, 0); + WRITE_RM_REG(mod_no, 38, 0); + WRITE_RM_REG(mod_no, 39, 0); + WRITE_RM_REG(mod_no, 40, 0); + WRITE_RM_REG(mod_no, 41, 0); + WRITE_RM_REG(mod_no, 42, 0); + WRITE_RM_REG(mod_no, 43, 0); + + return 0; +} + + +static int wp_remora_regdump(sdla_fe_t* fe, unsigned char *data) +{ + wan_remora_udp_t *rm_udp = (wan_remora_udp_t*)data; + wan_remora_fxs_regs_t *regs_fxs = NULL; + wan_remora_fxo_regs_t *regs_fxo = NULL; + int mod_no = 0, reg = 0; + + mod_no = rm_udp->mod_no; + DEBUG_EVENT("%s: Module %d: Read regdump...\n", + fe->name, mod_no); + if (fe->rm_param.mod[mod_no].type == MOD_TYPE_FXS){ + + rm_udp->type = MOD_TYPE_FXS; + regs_fxs = &rm_udp->u.regs_fxs; + for(reg = 0; reg < WAN_FXS_NUM_REGS; reg++){ + regs_fxs->direct[reg] = READ_RM_REG(mod_no, reg); + } + + for (reg=0; reg < WAN_FXS_NUM_INDIRECT_REGS; reg++){ + regs_fxs->indirect[reg] = + wp_proslic_getreg_indirect(fe, mod_no, reg); + } + }else if (fe->rm_param.mod[mod_no].type == MOD_TYPE_FXO){ + + rm_udp->type = MOD_TYPE_FXO; + regs_fxo = &rm_udp->u.regs_fxo; + for(reg = 0; reg < WAN_FXO_NUM_REGS; reg++){ + regs_fxo->direct[reg] = READ_RM_REG(mod_no, reg); + } + }else{ + return 0; + } + return sizeof(wan_remora_udp_t); +} + +/* + ****************************************************************************** + * wp_remora_udp() + * + * Description: + * Arguments: + * Returns: + ****************************************************************************** + */ +static int wp_remora_udp(sdla_fe_t *fe, void* p_udp_cmd, unsigned char* data) +{ + wan_cmd_t *udp_cmd = (wan_cmd_t*)p_udp_cmd; + int err = -EINVAL; + + switch(udp_cmd->wan_cmd_command){ + case WAN_FE_TONES: + fe->rm_param.timer_mod_no = data[0]; + wp_remora_enable_timer(fe, WP_RM_POLL_TONE_DIAL, WP_RM_POLL_TIMER); + udp_cmd->wan_cmd_return_code = WAN_CMD_OK; + udp_cmd->wan_cmd_data_len = 0; + break; + + case WAN_FE_RING: + fe->rm_param.timer_mod_no = data[0]; + wp_remora_enable_timer(fe, WP_RM_POLL_RING, WP_RM_POLL_TIMER); + udp_cmd->wan_cmd_return_code = WAN_CMD_OK; + udp_cmd->wan_cmd_data_len = 0; + break; + + case WAN_FE_REGDUMP: + err = wp_remora_regdump(fe, data); + if (err){ + udp_cmd->wan_cmd_return_code = WAN_CMD_OK; + udp_cmd->wan_cmd_data_len = err; + } + break; + + default: + udp_cmd->wan_cmd_return_code = WAN_UDP_INVALID_CMD; + udp_cmd->wan_cmd_data_len = 0; + break; + } + return 0; +} + + +/****************************************************************************** +* wp_remora_event_ctrl() +* +* Description: Enable/Disable event types +* Arguments: mod_no - Module number (1,2,3,... MAX_REMORA_MODULES) +* Returns: +******************************************************************************/ +//wp_remora_event_ctrl(sdla_fe_t *fe, int mod_no, int etype, int mode, unsigned long ts_map) +static int +wp_remora_event_ctrl(sdla_fe_t *fe, wan_event_ctrl_t *event_ctrl) +{ + int mod_no = event_ctrl->mod_no, + err = 0; + + if (mod_no >= MAX_REMORA_MODULES){ + DEBUG_EVENT("%s: Module %d: Module number is out of range!\n", + fe->name, mod_no); + return -EINVAL; + } + if (!wan_test_bit(mod_no, &fe->rm_param.module_map)) { + DEBUG_EVENT("%s: Module %d: Unconfigured module!\n", + fe->name, mod_no); + return -EINVAL; + } + if (wan_test_bit(WP_RM_TIMER_RUNNING,(void*)&fe->rm_param.critical)){ +DEBUG_EVENT("ADBG> I'm still busy....\n"); + return -EBUSY; + } + if (fe->rm_param.mod[mod_no].type == MOD_TYPE_FXS){ + + fe->rm_param.mod[mod_no].u.fxs.imask1 = 0x00; + fe->rm_param.mod[mod_no].u.fxs.imask2 = 0x00; + fe->rm_param.mod[mod_no].u.fxs.imask3 = 0x00; + if (event_ctrl->type & WAN_EVENT_RM_POWER){ + + DEBUG_EVENT("%s: Module %d: %s Power Alarm events!\n", + fe->name, mod_no, + WAN_EVENT_MODE_DECODE(event_ctrl->type)); + if (event_ctrl->type & WAN_EVENT_ENABLE){ + fe->rm_param.mod[mod_no].u.fxs.imask2 |= 0xFC; + fe->rm_param.mod[mod_no].events |= WAN_EVENT_RM_POWER; + }else{ + fe->rm_param.mod[mod_no].u.fxs.imask2 &= ~0xFC; + fe->rm_param.mod[mod_no].events &= ~WAN_EVENT_RM_POWER; + } + } + if (event_ctrl->type & WAN_EVENT_RM_LC){ + + DEBUG_EVENT("%s: Module %d: %s Loop Closure event!\n", + fe->name, mod_no, + WAN_EVENT_MODE_DECODE(event_ctrl->type)); + if (event_ctrl->type & WAN_EVENT_ENABLE){ + fe->rm_param.mod[mod_no].u.fxs.imask2 |= 0x02; + fe->rm_param.mod[mod_no].events |= WAN_EVENT_RM_LC; + }else{ + fe->rm_param.mod[mod_no].u.fxs.imask2 &= ~0x02; + fe->rm_param.mod[mod_no].events &= ~WAN_EVENT_RM_LC; + } + } + if (event_ctrl->type & WAN_EVENT_RM_RT){ + + DEBUG_EVENT("%s: Module %d: %s Ring Trip event!\n", + fe->name, mod_no, + WAN_EVENT_MODE_DECODE(event_ctrl->type)); + if (event_ctrl->type & WAN_EVENT_ENABLE){ + fe->rm_param.mod[mod_no].u.fxs.imask2 |= 0x01; + fe->rm_param.mod[mod_no].events |= WAN_EVENT_RM_RT; + }else{ + fe->rm_param.mod[mod_no].u.fxs.imask2 &= ~0x01; + fe->rm_param.mod[mod_no].events &= ~WAN_EVENT_RM_RT; + } + } + if (event_ctrl->type & WAN_EVENT_RM_DTMF){ + + DEBUG_EVENT("%s: Module %d: %s DTMF event!\n", + fe->name, mod_no, + WAN_EVENT_MODE_DECODE(event_ctrl->type)); + if (event_ctrl->type & WAN_EVENT_ENABLE){ + fe->rm_param.mod[mod_no].u.fxs.imask3 |= 0x01; + fe->rm_param.mod[mod_no].events |= WAN_EVENT_RM_DTMF; + }else{ + fe->rm_param.mod[mod_no].u.fxs.imask3 &= ~0x01; + fe->rm_param.mod[mod_no].events &= ~WAN_EVENT_RM_DTMF; + } + } + fe->rm_param.timer_mod_no = mod_no; + wp_remora_enable_timer(fe, WP_RM_POLL_EVENT, WP_RM_POLL_TIMER); + + }else if (fe->rm_param.mod[mod_no].type == MOD_TYPE_FXO){ + + DEBUG_EVENT("%s: Module %d: Unsupported FXO interrupt type (%s:%s)!\n", + fe->name, mod_no, + WAN_EVENT_TYPE_DECODE(event_ctrl->type), + WAN_EVENT_MODE_DECODE(event_ctrl->type)); + err = -EINVAL; + } + return err; +} + +/****************************************************************************** +* wp_remora_intr_ctrl() +* +* Description: Enable/Disable extra interrupt types +* Arguments: mod_no - Module number (1,2,3,... MAX_REMORA_MODULES) +* Returns: +******************************************************************************/ +static int +wp_remora_intr_ctrl(sdla_fe_t *fe, int mod_no, int type, int mode, unsigned int ts_map) +{ + int err = 0; + + if (mod_no >= MAX_REMORA_MODULES){ + DEBUG_EVENT( + "%s: Module %d: Module number is out of range!\n", + fe->name, mod_no); + return -EINVAL; + } + if (!wan_test_bit(mod_no, &fe->rm_param.module_map)) { + DEBUG_EVENT("%s: Module %d: Unconfigured module!\n", + fe->name, mod_no); + return -EINVAL; + } + if (fe->rm_param.mod[mod_no].type == MOD_TYPE_FXS){ + + switch(type){ + case WAN_RM_INTR_GLOBAL: + if (mode == WAN_FE_INTR_ENABLE){ + WRITE_RM_REG(mod_no, 21, fe->rm_param.mod[mod_no].u.fxs.imask1); + WRITE_RM_REG(mod_no, 22, fe->rm_param.mod[mod_no].u.fxs.imask2); + WRITE_RM_REG(mod_no, 23, fe->rm_param.mod[mod_no].u.fxs.imask3); + }else{ + WRITE_RM_REG(mod_no, 21, 0x00); + WRITE_RM_REG(mod_no, 22, 0x00); + WRITE_RM_REG(mod_no, 23, 0x00); + } + break; + default: + DEBUG_EVENT( + "%s: Module %d: Unsupported FXS interrupt type (%X)!\n", + fe->name, mod_no, type); + err = -EINVAL; + break; + } + + }else if (fe->rm_param.mod[mod_no].type == MOD_TYPE_FXO){ + DEBUG_RM( + "%s: Module %d: Unsupported FXO interrupt type (%X)!\n", + fe->name, mod_no, type); + err = -EINVAL; + } + return err; + +} + +static int wp_remora_check_intr_fxs(sdla_fe_t *fe, int mod_no) +{ + unsigned char stat1 = 0x0, stat2 = 0x00, stat3 = 0x00; + + if (__READ_RM_REG(mod_no, 8)){ + DEBUG_EVENT( + "%s: Module %d: Oops, part reset, quickly restoring reality\n", + fe->name, mod_no); +#if 0 + wp_init_proslic(fe, mod_no, 1, 1); +#else + wp_remora_enable_timer(fe, WP_RM_POLL_INIT, WP_RM_POLL_TIMER); +#endif + return 0; + } + + stat1 = __READ_RM_REG(mod_no, 18); + stat2 = __READ_RM_REG(mod_no, 19); + stat3 = __READ_RM_REG(mod_no, 20); + + if (stat1 & fe->rm_param.mod[mod_no].u.fxs.imask1) return 1; + if (stat2 & fe->rm_param.mod[mod_no].u.fxs.imask2) return 1; + if (stat3 & fe->rm_param.mod[mod_no].u.fxs.imask3) return 1; + return 0; +} + +static int wp_remora_check_intr_fxo(sdla_fe_t *fe, int mod_no) +{ + return 0; +} + +static int wp_remora_check_intr(sdla_fe_t *fe) +{ + int mod_no = 0, pending = 0; + + fe->rm_param.intcount++; + mod_no = fe->rm_param.intcount % MAX_REMORA_MODULES; + + if (wan_test_bit(mod_no, &fe->rm_param.module_map)) { + if (fe->rm_param.mod[mod_no].type == MOD_TYPE_FXS){ + pending = wp_remora_check_intr_fxs(fe, mod_no); + }else if (fe->rm_param.mod[mod_no].type == MOD_TYPE_FXO){ + pending = wp_remora_check_intr_fxo(fe, mod_no); + } + if (pending){ + return pending; + } + } +#if 0 + if (card->wan_tdmv.sc && fe->rm_param.intcount % 100 == 0){ + wp_remora_enable_timer(fe, WP_RM_POLL_TDMV, WP_RM_POLL_TIMER); + } +#endif + return 0; +} + +static int wp_remora_read_dtmf(sdla_fe_t *fe, int mod_no) +{ + sdla_t *card; + unsigned char status; + + WAN_ASSERT(fe->card == NULL); + card = fe->card; + status = READ_RM_REG(mod_no, 24); + if (status & 0x10){ + unsigned char digit = 0xFF; + status &= 0xF; + switch(status){ + case 0x01: digit = '1'; break; + case 0x02: digit = '2'; break; + case 0x03: digit = '3'; break; + case 0x04: digit = '4'; break; + case 0x05: digit = '5'; break; + case 0x06: digit = '6'; break; + case 0x07: digit = '7'; break; + case 0x08: digit = '8'; break; + case 0x09: digit = '9'; break; + case 0x0A: digit = '0'; break; + case 0x0B: digit = '*'; break; + case 0x0C: digit = '#'; break; + case 0x0D: digit = 'A'; break; + case 0x0E: digit = 'B'; break; + case 0x0F: digit = 'C'; break; + case 0x00: digit = 'D'; break; + } + DEBUG_RM("%s: Module %d: TDMV digit %c!\n", + fe->name, + mod_no + 1, + digit); + WRITE_RM_REG(mod_no, 20, 0x1); + if (card->wandev.event_callback.dtmf){ + wan_event_t event; + event.type = WAN_EVENT_RM_DTMF; + event.digit = digit; + event.channel = mod_no+1; + event.dtmf_port = WAN_EC_CHANNEL_PORT_SOUT; + event.dtmf_type = WAN_EC_TONE_STOP; + card->wandev.event_callback.dtmf(card, &event); + } + } + return 0; +} + +static int wp_remora_intr_fxs(sdla_fe_t *fe, int mod_no) +{ + sdla_t *card = NULL; + wan_event_t event; + unsigned char stat1 = 0x0, stat2 = 0x00, stat3 = 0x00; + + WAN_ASSERT(fe->card == NULL); + card = fe->card; + + stat1 = READ_RM_REG(mod_no, 18); + if (stat1){ + /* Ack interrupts for now */ + WRITE_RM_REG(mod_no, 18, stat1); + } + + stat2 = READ_RM_REG(mod_no, 19); + if (stat2){ + unsigned char status = READ_RM_REG(mod_no, 68); + + if (stat2 & 0x02){ + DEBUG_RM( + "%s: Module %d: LCIP interrupt pending!\n", + fe->name, mod_no); +#if 0 + if (card->wandev.fe_notify_iface.hook_state){ + card->wandev.fe_notify_iface.hook_state( + fe, mod_no, status & 0x01); + } +#endif + event.type = WAN_EVENT_RM_LC; + event.channel = mod_no+1; + if (status & 0x01){ + DEBUG_RM( + "%s: Module %d: Off-hook status!\n", + fe->name, mod_no); + fe->rm_param.mod[mod_no].u.fxs.oldrxhook = 1; + event.rxhook = WAN_EVENT_RXHOOK_OFF; + }else if (fe->rm_param.mod[mod_no].u.fxs.oldrxhook){ + DEBUG_RM( + "%s: Module %d: On-hook status!\n", + fe->name, mod_no); + fe->rm_param.mod[mod_no].u.fxs.oldrxhook = 0; + event.rxhook = WAN_EVENT_RXHOOK_ON; + } + if (card->wandev.event_callback.hook){ + card->wandev.event_callback.hook(card, &event); + } + } + if (stat2 & 0x01){ + DEBUG_RM( + "%s: Module %d: Ring TRIP interrupt pending!\n", + fe->name, mod_no); +#if 0 + if (card->wandev.fe_notify_iface.hook_state){ + card->wandev.fe_notify_iface.hook_state( + fe, mod_no, status & 0x01); + } +#endif + event.type = WAN_EVENT_RM_RT; + event.channel = mod_no+1; + if (status & 0x02){ + DEBUG_RM( + "%s: Module %d: Ring Trip detect occured!\n", + fe->name, mod_no); + event.rxhook = WAN_EVENT_RING_PRESENT; + }else{ + DEBUG_RM( + "%s: Module %d: Ring Trip detect not occured!\n", + fe->name, mod_no); + event.rxhook = WAN_EVENT_RING_STOP; + } + if (card->wandev.event_callback.ringtrip){ + card->wandev.event_callback.ringtrip(card, &event); + } + } + DEBUG_RM( + "%s: Module %d: Reg[64]=%02X Reg[68]=%02X\n", + fe->name, mod_no, + READ_RM_REG(mod_no,64), + status); + WRITE_RM_REG(mod_no, 19, stat2); + } + + stat3 = READ_RM_REG(mod_no, 20); + if (stat3){ + if (stat3 & 0x1){ + wp_remora_read_dtmf(fe, mod_no); + } + WRITE_RM_REG(mod_no, 20, stat3); + } + return 0; +} + +static int wp_remora_intr_fxo(sdla_fe_t *fe, int mod_no) +{ + return 0; +} + +static int wp_remora_intr(sdla_fe_t *fe) +{ + int mod_no = 0; + + for(mod_no = 0; mod_no < MAX_REMORA_MODULES; mod_no++){ + if (!wan_test_bit(mod_no, &fe->rm_param.module_map)) { + continue; + } + if (fe->rm_param.mod[mod_no].type == MOD_TYPE_FXS){ + wp_remora_intr_fxs(fe, mod_no); + }else if (fe->rm_param.mod[mod_no].type == MOD_TYPE_FXO){ + wp_remora_intr_fxo(fe, mod_no); + } + } + + return 0; +} + diff -Nur linux.org/drivers/net/wan/sdla_remora_tdmv.c linux-2.6.17/drivers/net/wan/sdla_remora_tdmv.c --- linux.org/drivers/net/wan/sdla_remora_tdmv.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/drivers/net/wan/sdla_remora_tdmv.c 2006-08-30 10:07:16.000000000 +0000 @@ -0,0 +1,1496 @@ +/*************************************************************************** + * sdla_remora_tdmv.c WANPIPE(tm) Multiprotocol WAN Link Driver. + * AFT REMORA and FXO/FXS support module. + * + * Author: Alex Feldman + * + * Copyright: (c) 2005 Sangoma Technologies Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * ============================================================================ + * Oct 6, 2005 Alex Feldman Initial version. + ****************************************************************************** + */ + +/******************************************************************************* +** INCLUDE FILES +*******************************************************************************/ +#if defined(__FreeBSD__) || defined(__OpenBSD__) +# include +# include +# include +# include +# include +# include +# include +# include +#elif (defined __WINDOWS__) +# include +#else +# include +# include +# include +# include +# include +#endif + +/******************************************************************************* +** DEFINES AND MACROS +*******************************************************************************/ +#define REG_SHADOW +#define REG_WRITE_SHADOW +#undef PULSE_DIALING + +#if 0 +# define SPI2STEP +#endif +/* The constants below control the 'debounce' periods enforced by the +** check_hook routines; these routines are called once every 4 interrupts +** (the interrupt cycles around the four modules), so the periods are +** specified in _4 millisecond_ increments +*/ +#define RING_DEBOUNCE 16 /* Ringer Debounce (64 ms) */ +#define DEFAULT_BATT_DEBOUNCE 16 /* Battery debounce (64 ms) */ +#define POLARITY_DEBOUNCE 16 /* Polarity debounce (64 ms) */ +#define DEFAULT_BATT_THRESH 3 /* Anything under this is "no battery" */ + +#define OHT_TIMER 6000 /* How long after RING to retain OHT */ + +#define MAX_ALARMS 10 + +/* Interrupt flag enable */ +#if 0 +# define WAN_REMORA_FXS_LCIP +#endif +#if 0 +# define WAN_REMORA_FXS_DTMF +#endif + + +/* flags bits */ +#define WP_TDMV_REGISTER 1 /*0x01*/ +#define WP_TDMV_RUNNING 2 /*0x02*/ +#define WP_TDMV_UP 3 /*0x04*/ + +#define IS_TDMV_RUNNING(wr) wan_test_bit(WP_TDMV_RUNNING, &(wr)->flags) +#define IS_TDMV_UP(wr) wan_test_bit(WP_TDMV_UP, &(wr)->flags) +#define IS_TDMV_UP_RUNNING(wr) (IS_TDMV_UP(wr) && IS_TDMV_RUNNING(wr)) + +/******************************************************************************* +** STRUCTURES AND TYPEDEFS +*******************************************************************************/ +typedef struct { + int ready; + int offhook; + int lastpol; + int polarity; + int polaritydebounce; + int battery; + int battdebounce; + int ringdebounce; + int nobatttimer; + int wasringing; + + int echotune; /* echo tune */ + struct wan_rm_echo_coefs echoregs; /* echo tune */ +} tdmv_fxo_t; + +typedef struct { + int ready; + int lasttxhook; + int lasttxhook_update; + int lastrxhook; + int oldrxhook; + int debouncehook; + int debounce; + int palarms; + int ohttimer; +} tdmv_fxs_t; + +typedef struct wp_tdmv_remora_ { + void *card; + char *devname; + int num; + int flags; + wan_spinlock_t lock; + wan_spinlock_t tx_rx_lock; + union { + tdmv_fxo_t fxo; + tdmv_fxs_t fxs; + } mod[MAX_REMORA_MODULES]; + + int spanno; + struct zt_span span; + struct zt_chan chans[MAX_REMORA_MODULES]; + unsigned long reg_module_map; /* Registered modules */ + + unsigned char reg0shadow[MAX_REMORA_MODULES]; /* read> fxs: 68 fxo: 5 */ + unsigned char reg1shadow[MAX_REMORA_MODULES]; /* read> fxs: 64 fxo: 29 */ + unsigned char reg2shadow[MAX_REMORA_MODULES]; /* read> fxs: 64 fxo: 29 */ + + unsigned char reg0shadow_write[MAX_REMORA_MODULES]; /* write> fxs: 68 fxo: 5 */ + int reg0shadow_update[MAX_REMORA_MODULES]; + + /* Global configuration */ + + int intcount; + int pollcount; + unsigned char ec_chunk1[31][ZT_CHUNKSIZE]; + unsigned char ec_chunk2[31][ZT_CHUNKSIZE]; + int usecount; + int max_timeslots; /* up to MAX_REMORA_MODULES */ + int max_rxtx_len; + int channelized; + unsigned long echo_off_map; +} wp_tdmv_remora_t; + +/******************************************************************************* +** GLOBAL VARIABLES +*******************************************************************************/ +static int wp_remora_no = 0; +extern WAN_LIST_HEAD(, wan_tdmv_) wan_tdmv_head; +static int battdebounce = DEFAULT_BATT_DEBOUNCE; +static int battthresh = DEFAULT_BATT_THRESH; + +/******************************************************************************* +** FUNCTION PROTOTYPES +*******************************************************************************/ +static int wp_tdmv_remora_check_mtu(void* pcard, unsigned long timeslot_map, int *mtu); +static int wp_tdmv_remora_create(void* pcard, wan_xilinx_conf_t *conf); +static int wp_tdmv_remora_remove(void* pcard); +static int wp_tdmv_remora_reg(void* pcard, wanif_conf_t *conf, netdevice_t *dev); +static int wp_tdmv_remora_unreg(void* pcard, unsigned long ts_map); +static int wp_tdmv_remora_software_init(wan_tdmv_t *wan_tdmv); +static int wp_tdmv_remora_state(void* pcard, int state); +static int wp_tdmv_remora_running(void* pcard); +static int wp_tdmv_remora_is_rbsbits(wan_tdmv_t *wan_tdmv); +static int wp_tdmv_remora_rx_tx_span(void *pcard); +static int wp_tdmv_remora_rx_chan(wan_tdmv_t*, int,unsigned char*,unsigned char*); + +extern int wp_init_proslic(sdla_fe_t *fe, int mod_no, int fast, int sane); + +/******************************************************************************* +** FUNCTION DEFINITIONS +*******************************************************************************/ + +static int +#if defined(__FreeBSD__) || defined(__OpenBSD__) +wp_remora_zap_ioctl(struct zt_chan *chan, unsigned int cmd, caddr_t data) +#else +wp_remora_zap_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long data) +#endif +{ + wp_tdmv_remora_t *wr = chan->pvt; + sdla_t *card = NULL; + sdla_fe_t *fe = NULL; + int x, err; + + WAN_ASSERT(wr->card == NULL); + card = wr->card; + fe = &card->fe; + + switch (cmd) { + case ZT_ONHOOKTRANSFER: + if (fe->rm_param.mod[chan->chanpos - 1].type != MOD_TYPE_FXS) { + return -EINVAL; + } + err = WAN_COPY_FROM_USER(&x, (int*)data, sizeof(int)); + /*err = get_user(x, (int *)data);*/ + if (err) return -EFAULT; + wr->mod[chan->chanpos - 1].fxs.ohttimer = x << 3; + if (fe->fe_cfg.cfg.remora.reversepolarity){ + /* OHT mode when idle */ + fe->rm_param.mod[chan->chanpos - 1].u.fxs.idletxhookstate = 0x6; + }else{ + fe->rm_param.mod[chan->chanpos - 1].u.fxs.idletxhookstate = 0x2; + } + if (wr->mod[chan->chanpos - 1].fxs.lasttxhook == 0x1) { + /* Apply the change if appropriate */ + if (fe->fe_cfg.cfg.remora.reversepolarity){ + wr->mod[chan->chanpos - 1].fxs.lasttxhook = 0x6; + }else{ + wr->mod[chan->chanpos - 1].fxs.lasttxhook = 0x2; + } +#if defined(REG_WRITE_SHADOW) + wr->mod[chan->chanpos-1].fxs.lasttxhook_update = 1; +#else + WRITE_RM_REG(chan->chanpos - 1, 64, wr->mod[chan->chanpos - 1].fxs.lasttxhook); +#endif + } + break; + + case ZT_SETPOLARITY: + err = WAN_COPY_FROM_USER(&x, (int*)data, sizeof(int)); + /*err = get_user(x, (int *)data);*/ + if (err) return -EFAULT; + if (fe->rm_param.mod[chan->chanpos - 1].type != MOD_TYPE_FXS) { + return -EINVAL; + } + /* Can't change polarity while ringing or when open */ + if ((wr->mod[chan->chanpos - 1].fxs.lasttxhook == 0x04) || + (wr->mod[chan->chanpos - 1 ].fxs.lasttxhook == 0x00)){ + return -EINVAL; + } + + if ((x && !fe->fe_cfg.cfg.remora.reversepolarity) || (!x && fe->fe_cfg.cfg.remora.reversepolarity)){ + wr->mod[chan->chanpos - 1].fxs.lasttxhook |= 0x04; + }else{ + wr->mod[chan->chanpos - 1].fxs.lasttxhook &= ~0x04; + } +#if defined(REG_WRITE_SHADOW) + wr->mod[chan->chanpos-1].fxs.lasttxhook_update = 1; +#else + WRITE_RM_REG(chan->chanpos - 1, 64, wr->mod[chan->chanpos - 1].fxs.lasttxhook); +#endif + break; + + case WAN_RM_SET_ECHOTUNE: + if (fe->rm_param.mod[chan->chanpos - 1].type == MOD_TYPE_FXO) { + + err = WAN_COPY_FROM_USER( + &wr->mod[chan->chanpos-1].fxo.echoregs, + (struct wan_rm_echo_coefs*)data, + sizeof(struct wan_rm_echo_coefs)); + if (err) return -EFAULT; + +#if 1 + wr->mod[chan->chanpos-1].fxo.echotune = 1; +#else + DEBUG_EVENT("%s: Module %d: Setting echo registers: \n", + fe->name, chan->chanpos-1); + /* Set the ACIM register */ + WRITE_RM_REG(chan->chanpos - 1, 30, echoregs.acim); + + /* Set the digital echo canceller registers */ + WRITE_RM_REG(chan->chanpos - 1, 45, echoregs.coef1); + WRITE_RM_REG(chan->chanpos - 1, 46, echoregs.coef2); + WRITE_RM_REG(chan->chanpos - 1, 47, echoregs.coef3); + WRITE_RM_REG(chan->chanpos - 1, 48, echoregs.coef4); + WRITE_RM_REG(chan->chanpos - 1, 49, echoregs.coef5); + WRITE_RM_REG(chan->chanpos - 1, 50, echoregs.coef6); + WRITE_RM_REG(chan->chanpos - 1, 51, echoregs.coef7); + WRITE_RM_REG(chan->chanpos - 1, 52, echoregs.coef8); + + DEBUG_EVENT("%s: Module %d: Set echo registers successfully\n", + fe->name, chan->chanpos-1); +#endif + break; + } else { + return -EINVAL; + + } + break; + + default: + return -ENOTTY; + break; + } + return 0; +} + +static int wp_remora_zap_hooksig(struct zt_chan *chan, zt_txsig_t txsig) +{ + wp_tdmv_remora_t *wr = chan->pvt; + sdla_t *card = NULL; + sdla_fe_t *fe = NULL; + + WAN_ASSERT(wr->card == NULL); + card = wr->card; + fe = &card->fe; + + if (fe->rm_param.mod[chan->chanpos - 1].type == MOD_TYPE_FXO) { + /* XXX Enable hooksig for FXO XXX */ + switch(txsig) { + case ZT_TXSIG_START: + case ZT_TXSIG_OFFHOOK: + DEBUG_TDMV("%s: Module %d: goes off-hook (txsig %d)\n", + wr->devname, chan->chanpos, txsig); + wr->mod[chan->chanpos - 1].fxo.offhook = 1; +#if defined(REG_WRITE_SHADOW) + wr->reg0shadow[chan->chanpos-1] = 0x09; + wr->reg0shadow_update[chan->chanpos-1] = 1; +#else + WRITE_RM_REG(chan->chanpos - 1, 5, 0x9); +#endif + break; + case ZT_TXSIG_ONHOOK: + DEBUG_TDMV("%s: Module %d: goes on-hook (txsig %d)\n", + wr->devname, chan->chanpos, txsig); + wr->mod[chan->chanpos - 1].fxo.offhook = 0; +#if defined(REG_WRITE_SHADOW) + wr->reg0shadow[chan->chanpos-1] = 0x08; + wr->reg0shadow_update[chan->chanpos-1] = 1; +#else + WRITE_RM_REG(chan->chanpos - 1, 5, 0x8); +#endif + break; + default: + DEBUG_TDMV("%s: Can't set tx state to %d (chan %d)\n", + wr->devname, txsig, chan->chanpos); + } + }else if (fe->rm_param.mod[chan->chanpos - 1].type == MOD_TYPE_FXS) { + switch(txsig) { + case ZT_TXSIG_ONHOOK: + DEBUG_TDMV("%s: Module %d: goes on-hook (txsig %d).\n", + wr->devname, chan->chanpos, txsig); + switch(chan->sig) { + case ZT_SIG_EM: + case ZT_SIG_FXOKS: + case ZT_SIG_FXOLS: + wr->mod[chan->chanpos-1].fxs.lasttxhook = + fe->rm_param.mod[chan->chanpos-1].u.fxs.idletxhookstate; + break; + case ZT_SIG_FXOGS: + wr->mod[chan->chanpos-1].fxs.lasttxhook = 3; + break; + } + break; + case ZT_TXSIG_OFFHOOK: + DEBUG_TDMV("%s: Module %d: goes off-hook (txsig %d).\n", + wr->devname, chan->chanpos, txsig); + switch(chan->sig) { + case ZT_SIG_EM: + wr->mod[chan->chanpos-1].fxs.lasttxhook = 5; + break; + default: + wr->mod[chan->chanpos-1].fxs.lasttxhook = + fe->rm_param.mod[chan->chanpos-1].u.fxs.idletxhookstate; + break; + } + break; + case ZT_TXSIG_START: + DEBUG_TDMV("%s: Module %d: txsig START (txsig %d).\n", + wr->devname, chan->chanpos, txsig); + wr->mod[chan->chanpos-1].fxs.lasttxhook = 4; + break; + case ZT_TXSIG_KEWL: + wr->mod[chan->chanpos-1].fxs.lasttxhook = 0; + break; + default: + DEBUG_EVENT("%s: Can't set tx state to %d\n", + wr->devname, txsig); + return 0; + break; + } +#if defined(REG_WRITE_SHADOW) + wr->mod[chan->chanpos-1].fxs.lasttxhook_update = 1; +#else + WRITE_RM_REG(chan->chanpos - 1, 64, wr->mod[chan->chanpos-1].fxs.lasttxhook); +#endif + } + + return 0; +} + +static int wp_remora_zap_open(struct zt_chan *chan) +{ + wp_tdmv_remora_t *wr = NULL; + + WAN_ASSERT2(chan == NULL, -ENODEV); + WAN_ASSERT2(chan->pvt == NULL, -ENODEV); + wr = chan->pvt; + wr->usecount++; + wan_set_bit(WP_TDMV_RUNNING, &wr->flags); + DEBUG_EVENT("%s: Open (usecount=%d, channo=%d, chanpos=%d)...\n", + wr->devname, + wr->usecount, + chan->channo, + chan->chanpos); + return 0; +} + +static int wp_remora_zap_close(struct zt_chan *chan) +{ + sdla_t *card = NULL; + wp_tdmv_remora_t* wr = NULL; + sdla_fe_t *fe = NULL; + + WAN_ASSERT2(chan == NULL, -ENODEV); + WAN_ASSERT2(chan->pvt == NULL, -ENODEV); + wr = chan->pvt; + card = wr->card; + fe = &card->fe; + wr->usecount--; + wan_clear_bit(WP_TDMV_RUNNING, &wr->flags); + +#if 1 + if (fe->rm_param.mod[chan->chanpos - 1].type == MOD_TYPE_FXS) { + if (fe->fe_cfg.cfg.remora.reversepolarity) + fe->rm_param.mod[chan->chanpos - 1].u.fxs.idletxhookstate = 5; + else + fe->rm_param.mod[chan->chanpos - 1].u.fxs.idletxhookstate = 1; + } +#endif + return 0; +} + +static int wp_remora_zap_watchdog(struct zt_span *span, int event) +{ +#if 0 + printk("TDM: Restarting DMA\n"); + wctdm_restart_dma(span->pvt); +#endif + return 0; +} + +/****************************************************************************** +** wp_remora_zap_hwec() - +** +** OK +*/ +static int wp_remora_zap_hwec(struct zt_chan *chan, int enable) +{ + wp_tdmv_remora_t *wr = NULL; + sdla_t *card = NULL; + int channel = chan->chanpos; + int err = -ENODEV; + + WAN_ASSERT2(chan == NULL, -ENODEV); + WAN_ASSERT2(chan->pvt == NULL, -ENODEV); + wr = chan->pvt; + WAN_ASSERT2(wr->card == NULL, -ENODEV); + card = wr->card; + + if (card->wandev.ec_enable){ + DEBUG_TDMV("[TDMV_RM]: %s: %s HW echo canceller on channel %d\n", + wr->devname, + (enable) ? "Enable" : "Disable", + channel); + err = card->wandev.ec_enable(card, enable, channel-1); + } + return err; +} + +static void wp_tdmv_remora_proslic_recheck_sanity(wp_tdmv_remora_t *wr, int mod_no) +{ + sdla_t *card = NULL; + sdla_fe_t *fe = NULL; + int res; + + WAN_ASSERT1(wr->card == NULL); + card = wr->card; + fe = &card->fe; + + /* Check loopback */ +#if defined(REG_SHADOW) + res = wr->reg2shadow[mod_no]; +#else + res = READ_RM_REG(mod_no, 8); +#endif + if (res) { + DEBUG_EVENT( + "%s: Module %d: Ouch, part reset, quickly restoring reality (%02X) -- Comment out\n", + wr->devname, mod_no, res); +#if 0 + wp_init_proslic(fe, mod_no, 1, 1); +#endif + return; + } +#if defined(REG_SHADOW) + res = wr->reg1shadow[mod_no]; +#else + res = READ_RM_REG(mod_no, 64); +#endif + if (!res && (res != wr->mod[mod_no].fxs.lasttxhook)) { +#if defined(REG_SHADOW) + res = wr->reg2shadow[mod_no]; +#else + res = READ_RM_REG(mod_no, 8); +#endif + if (res) { + DEBUG_EVENT( + "%s: Module %d: Ouch, part reset, quickly restoring reality\n", + wr->devname, mod_no); + wp_init_proslic(fe, mod_no, 1, 1); + } else { + if (wr->mod[mod_no].fxs.palarms++ < MAX_ALARMS) { + DEBUG_EVENT( + "%s: Module %d: Power alarm, resetting!\n", + wr->devname, mod_no + 1); + if (wr->mod[mod_no].fxs.lasttxhook == 4) + wr->mod[mod_no].fxs.lasttxhook = 1; + WRITE_RM_REG(mod_no, 64, wr->mod[mod_no].fxs.lasttxhook); + } else { + if (wr->mod[mod_no].fxs.palarms == MAX_ALARMS) + DEBUG_EVENT( + "%s: Module %d: Too many power alarms, NOT resetting!\n", + wr->devname, mod_no + 1); + } + } + } + return; +} + +static void wp_tdmv_remora_voicedaa_check_hook(wp_tdmv_remora_t *wr, int mod_no) +{ + sdla_t *card = NULL; + sdla_fe_t *fe = NULL; +#ifndef AUDIO_RINGCHECK + unsigned char res; +#endif + signed char b; + int poopy = 0; + + WAN_ASSERT1(wr->card == NULL); + card = wr->card; + fe = &card->fe; + + /* Try to track issues that plague slot one FXO's */ +#if defined(REG_SHADOW) + b = wr->reg0shadow[mod_no]; +#else + b = READ_RM_REG(mod_no, 5); +#endif + if ((b & 0x2) || !(b & 0x8)) { + /* Not good -- don't look at anything else */ + DEBUG_TDMV("%s: Module %d: Poopy (%02x)!\n", + wr->devname, mod_no + 1, b); + poopy++; + } + b &= 0x9b; + if (wr->mod[mod_no].fxo.offhook) { + if (b != 0x9){ + WRITE_RM_REG(mod_no, 5, 0x9); + } + } else { + if (b != 0x8){ + WRITE_RM_REG(mod_no, 5, 0x8); + } + } + if (poopy) + return; +#ifndef AUDIO_RINGCHECK + if (!wr->mod[mod_no].fxo.offhook) { +#if defined(REG_SHADOW) + res = wr->reg0shadow[mod_no]; +#else + res = READ_RM_REG(mod_no, 5); +#endif + if ((res & 0x60) && wr->mod[mod_no].fxo.battery) { + wr->mod[mod_no].fxo.ringdebounce += (ZT_CHUNKSIZE * 16); + if (wr->mod[mod_no].fxo.ringdebounce >= ZT_CHUNKSIZE * 64) { + if (!wr->mod[mod_no].fxo.wasringing) { + wr->mod[mod_no].fxo.wasringing = 1; + zt_hooksig(&wr->chans[mod_no], ZT_RXSIG_RING); + DEBUG_TDMV("%s: Module %d: RING on span %d!\n", + wr->devname, + mod_no + 1, + wr->span.spanno); + } + wr->mod[mod_no].fxo.ringdebounce = ZT_CHUNKSIZE * 64; + } + } else { + wr->mod[mod_no].fxo.ringdebounce -= ZT_CHUNKSIZE * 4; + if (wr->mod[mod_no].fxo.ringdebounce <= 0) { + if (wr->mod[mod_no].fxo.wasringing) { + wr->mod[mod_no].fxo.wasringing = 0; + zt_hooksig(&wr->chans[mod_no], ZT_RXSIG_OFFHOOK); + DEBUG_TDMV("%s: Module %d: NO RING on span %d!\n", + wr->devname, + mod_no + 1, + wr->span.spanno); + } + wr->mod[mod_no].fxo.ringdebounce = 0; + } + } + } +#endif +#if defined(REG_SHADOW) + b = wr->reg1shadow[mod_no]; +#else + b = READ_RM_REG(mod_no, 29); +#endif +#if 0 + { + static int count = 0; + if (!(count++ % 100)) { + printk("mod_no %d: Voltage: %d Debounce %d\n", mod_no + 1, + b, wr->mod[mod_no].fxo.battdebounce); + } + } +#endif + if (abs(b) < battthresh) { + wr->mod[mod_no].fxo.nobatttimer++; +#if 0 + if (wr->mod[mod_no].fxo.battery) + printk("Battery loss: %d (%d debounce)\n", b, wr->mod[mod_no].fxo.battdebounce); +#endif + if (wr->mod[mod_no].fxo.battery && !wr->mod[mod_no].fxo.battdebounce) { + DEBUG_TDMV("%s: Module %d: NO BATTERY on span %d!\n", + wr->devname, + mod_no + 1, + wr->span.spanno); + wr->mod[mod_no].fxo.battery = 0; +#ifdef JAPAN + if ((!wr->ohdebounce) && wr->offhook) { + zt_hooksig(&wr->chans[mod_no], ZT_RXSIG_ONHOOK); + DEBUG_TDMV("%s: Module %d: Signalled On Hook span %d\n", + wr->devname, + mod_no + 1, + wr->span.spanno); +#ifdef ZERO_BATT_RING + wr->onhook++; +#endif + } +#else + zt_hooksig(&wr->chans[mod_no], ZT_RXSIG_ONHOOK); +#endif + wr->mod[mod_no].fxo.battdebounce = battdebounce; + } else if (!wr->mod[mod_no].fxo.battery) + wr->mod[mod_no].fxo.battdebounce = battdebounce; + } else if (abs(b) > battthresh) { + if (!wr->mod[mod_no].fxo.battery && !wr->mod[mod_no].fxo.battdebounce) { + DEBUG_TDMV("%s: Module %d: BATTERY on span %d (%s)!\n", + wr->devname, + mod_no + 1, + wr->span.spanno, + (b < 0) ? "-" : "+"); +#ifdef ZERO_BATT_RING + if (wr->onhook) { + wr->onhook = 0; + zt_hooksig(&wr->chans[mod_no], ZT_RXSIG_OFFHOOK); + DEBUG_TDMV("%s: Module %d: Signalled Off Hook span %d\n", + wr->devname, + mod_no + 1, + wr->span.spanno); + } +#else + zt_hooksig(&wr->chans[mod_no], ZT_RXSIG_OFFHOOK); +#endif + wr->mod[mod_no].fxo.battery = 1; + wr->mod[mod_no].fxo.nobatttimer = 0; + wr->mod[mod_no].fxo.battdebounce = battdebounce; + } else if (wr->mod[mod_no].fxo.battery) + wr->mod[mod_no].fxo.battdebounce = battdebounce; + + if (wr->mod[mod_no].fxo.lastpol >= 0) { + if (b < 0) { + wr->mod[mod_no].fxo.lastpol = -1; + wr->mod[mod_no].fxo.polaritydebounce = POLARITY_DEBOUNCE; + } + } + if (wr->mod[mod_no].fxo.lastpol <= 0) { + if (b > 0) { + wr->mod[mod_no].fxo.lastpol = 1; + wr->mod[mod_no].fxo.polaritydebounce = POLARITY_DEBOUNCE; + } + } + } else { + /* It's something else... */ + wr->mod[mod_no].fxo.battdebounce = battdebounce; + } + if (wr->mod[mod_no].fxo.battdebounce) + wr->mod[mod_no].fxo.battdebounce--; + if (wr->mod[mod_no].fxo.polaritydebounce) { + wr->mod[mod_no].fxo.polaritydebounce--; + if (wr->mod[mod_no].fxo.polaritydebounce < 1) { + if (wr->mod[mod_no].fxo.lastpol != wr->mod[mod_no].fxo.polarity) { + DEBUG_TDMV( + "%s: Module %d: %lu Polarity reversed (%d -> %d)\n", + wr->devname, + mod_no + 1, + SYSTEM_TICKS, + wr->mod[mod_no].fxo.polarity, + wr->mod[mod_no].fxo.lastpol); + if (wr->mod[mod_no].fxo.polarity){ + zt_qevent_lock(&wr->chans[mod_no], + ZT_EVENT_POLARITY); + } + wr->mod[mod_no].fxo.polarity = + wr->mod[mod_no].fxo.lastpol; + } + } + } + return; +} + +static void wp_tdmv_remora_proslic_check_hook(wp_tdmv_remora_t *wr, int mod_no) +{ + sdla_t *card = NULL; + sdla_fe_t *fe = NULL; + int hook; + char res; + + WAN_ASSERT1(wr->card == NULL); + card = wr->card; + fe = &card->fe; + /* For some reason we have to debounce the + hook detector. */ + +#if defined(REG_SHADOW) + res = wr->reg0shadow[mod_no]; +#else + res = READ_RM_REG(mod_no, 68); +#endif + hook = (res & 1); + if (hook != wr->mod[mod_no].fxs.lastrxhook) { + /* Reset the debounce (must be multiple of 4ms) */ + wr->mod[mod_no].fxs.debounce = 4 * (4 * 8); + DEBUG_TDMV( + "%s: Module %d: Resetting debounce hook %d, %d\n", + wr->devname, mod_no + 1, hook, + wr->mod[mod_no].fxs.debounce); + } else { + if (wr->mod[mod_no].fxs.debounce > 0) { + wr->mod[mod_no].fxs.debounce-= 16 * ZT_CHUNKSIZE; + DEBUG_TDMV( + "%s: Module %d: Sustaining hook %d, %d\n", + wr->devname, mod_no + 1, + hook, wr->mod[mod_no].fxs.debounce); + if (!wr->mod[mod_no].fxs.debounce) { + DEBUG_TDMV( + "%s: Module %d: Counted down debounce, newhook: %d\n", + wr->devname, + mod_no + 1, + hook); + wr->mod[mod_no].fxs.debouncehook = hook; + } + if (!wr->mod[mod_no].fxs.oldrxhook && wr->mod[mod_no].fxs.debouncehook) { + /* Off hook */ + DEBUG_TDMV( + "%s: Module %d: Going off hook\n", + wr->devname, mod_no + 1); + zt_hooksig(&wr->chans[mod_no], ZT_RXSIG_OFFHOOK); +#if 0 + if (robust) + wp_init_proslic(wc, card, 1, 0, 1); +#endif + wr->mod[mod_no].fxs.oldrxhook = 1; + + } else if (wr->mod[mod_no].fxs.oldrxhook && !wr->mod[mod_no].fxs.debouncehook) { + /* On hook */ + DEBUG_TDMV( + "%s: Module %d: Going on hook\n", + wr->devname, mod_no + 1); + zt_hooksig(&wr->chans[mod_no], ZT_RXSIG_ONHOOK); + wr->mod[mod_no].fxs.oldrxhook = 0; + } + } + } + wr->mod[mod_no].fxs.lastrxhook = hook; +} + +static int wp_tdmv_remora_check_hook(sdla_fe_t *fe, int mod_no) +{ + sdla_t *card = fe->card; + wan_tdmv_t *wan_tdmv = NULL; + wp_tdmv_remora_t *wr = NULL; + + wan_tdmv = &card->wan_tdmv; + WAN_ASSERT(wan_tdmv->sc == NULL); + wr = wan_tdmv->sc; + + if (fe->rm_param.mod[mod_no].type == MOD_TYPE_FXS) { + wp_tdmv_remora_proslic_check_hook(wr, mod_no); + } else if (fe->rm_param.mod[mod_no].type == MOD_TYPE_FXO) { + wp_tdmv_remora_voicedaa_check_hook(wr, mod_no); + } + return 0; +} + +static int wp_tdmv_remora_hook(sdla_fe_t *fe, int mod_no, int off_hook) +{ + sdla_t *card = fe->card; + wan_tdmv_t *wan_tdmv = NULL; + wp_tdmv_remora_t *wr = NULL; + + wan_tdmv = &card->wan_tdmv; + WAN_ASSERT(wan_tdmv->sc == NULL); + wr = wan_tdmv->sc; + + if (off_hook){ + zt_hooksig(&wr->chans[mod_no], ZT_RXSIG_OFFHOOK); + }else{ + zt_hooksig(&wr->chans[mod_no], ZT_RXSIG_ONHOOK); + } + wr->mod[mod_no].fxs.lastrxhook = off_hook; + return 0; +} + + +/****************************************************************************** +** wp_tdmv_remora_init() - +** +** OK +*/ +int wp_tdmv_remora_init(wan_tdmv_iface_t *iface) +{ + WAN_ASSERT(iface == NULL); + + memset(iface, 0, sizeof(wan_tdmv_iface_t)); + iface->check_mtu = wp_tdmv_remora_check_mtu; + iface->create = wp_tdmv_remora_create; + iface->remove = wp_tdmv_remora_remove; + iface->reg = wp_tdmv_remora_reg; + iface->unreg = wp_tdmv_remora_unreg; + iface->software_init = wp_tdmv_remora_software_init; + iface->state = wp_tdmv_remora_state; + iface->running = wp_tdmv_remora_running; + iface->is_rbsbits = wp_tdmv_remora_is_rbsbits; + iface->rx_tx_span = wp_tdmv_remora_rx_tx_span; + iface->rx_chan = wp_tdmv_remora_rx_chan; + + return 0; +} + +static int wp_tdmv_remora_software_init(wan_tdmv_t *wan_tdmv) +{ + sdla_t *card = NULL; + sdla_fe_t *fe = NULL; + wp_tdmv_remora_t *wr = wan_tdmv->sc; + int x = 0, num = 0; + + WAN_ASSERT(wr == NULL); + WAN_ASSERT(wr->card == NULL); + card = wr->card; + fe = &card->fe; + + if (wan_test_bit(WP_TDMV_REGISTER, &wr->flags)){ + DEBUG_EVENT( + "%s: Wanpipe device is already registered to Zaptel span # %d!\n", + wr->devname, wr->span.spanno); + return 0; + } + /* Zapata stuff */ + sprintf(wr->span.name, "WRTDM/%d", wr->num); + sprintf(wr->span.desc, "wrtdm Board %d", wr->num + 1); + switch(fe->fe_cfg.tdmv_law){ + case WAN_TDMV_ALAW: + DEBUG_EVENT( + "%s: ALAW override parameter detected. Device will be operating in ALAW\n", + wr->devname); + wr->span.deflaw = ZT_LAW_ALAW; + break; + case WAN_TDMV_MULAW: + wr->span.deflaw = ZT_LAW_MULAW; + break; + } + for (x = 0; x < MAX_REMORA_MODULES; x++) { + if (wan_test_bit(x, &fe->rm_param.module_map)){ + + sprintf(wr->chans[x].name, "WRTDM/%d/%d", wr->num, x); + DEBUG_TDMV("%s: Configure Module %d for voice (%s, type %s)!\n", + wr->devname, + x + 1, + wr->chans[x].name, + WP_REMORA_DECODE_TYPE(fe->rm_param.mod[x].type)); + if (fe->rm_param.mod[x].type == MOD_TYPE_FXO){ + wr->chans[x].sigcap = + ZT_SIG_FXSKS | ZT_SIG_FXSLS | + ZT_SIG_SF | ZT_SIG_CLEAR; + }else if (fe->rm_param.mod[x].type == MOD_TYPE_FXS){ + wr->chans[x].sigcap = + ZT_SIG_FXOKS | ZT_SIG_FXOLS | ZT_SIG_FXOGS | + ZT_SIG_SF | ZT_SIG_EM | ZT_SIG_CLEAR; + } + wr->chans[x].chanpos = x+1; + wr->chans[x].pvt = wr; + num++; + }else{ + + sprintf(wr->chans[x].name, "WRTDM/%d/%d", wr->num, x); + DEBUG_TEST("%s: Not used module %d!\n", + wr->devname, + x + 1); + wr->chans[x].sigcap = ZT_SIG_CLEAR; + wr->chans[x].chanpos = x+1; + wr->chans[x].pvt = wr; + num++; + } + } + wr->span.pvt = wr; + wr->span.chans = wr->chans; + wr->span.channels = num/*wr->max_timeslots*/; + wr->span.hooksig = wp_remora_zap_hooksig; + wr->span.open = wp_remora_zap_open; + wr->span.close = wp_remora_zap_close; + wr->span.flags = ZT_FLAG_RBS; + wr->span.ioctl = wp_remora_zap_ioctl; + wr->span.watchdog = wp_remora_zap_watchdog; + /* Set this pointer only if card has hw echo canceller module */ + if (card->wandev.ec_dev){ + wr->span.echocan = wp_remora_zap_hwec; + } +#if defined(__LINUX__) + init_waitqueue_head(&wr->span.maintq); +#endif + if (zt_register(&wr->span, 0)) { + DEBUG_EVENT("%s: Unable to register span with zaptel\n", + wr->devname); + return -EINVAL; + } + if (wr->span.spanno != wr->spanno +1){ + DEBUG_EVENT("\n"); + DEBUG_EVENT("WARNING: Span number %d is already used by another device!\n", + wr->spanno + 1); + DEBUG_EVENT(" Possible cause: Another TDM driver already loaded!\n"); + DEBUG_EVENT(" Solution: Unload wanpipe and check currently\n"); + DEBUG_EVENT(" used spans in /proc/zaptel directory.\n"); + DEBUG_EVENT(" Reconfiguring device %s to new span number # %d\n", + wr->devname,wr->span.spanno); + DEBUG_EVENT("\n"); + wr->spanno = wr->span.spanno-1; + }else{ + DEBUG_EVENT("%s: Wanpipe device is registered to Zaptel span # %d!\n", + wr->devname, wr->span.spanno); + } + wp_tdmv_remora_check_mtu(card, wr->reg_module_map, &wr->max_rxtx_len); + wan_set_bit(WP_TDMV_REGISTER, &wr->flags); + return 0; +} + +/****************************************************************************** +** wp_tdmv_release() - +** +** OK +*/ +static void wp_tdmv_release(wp_tdmv_remora_t *wr) +{ + WAN_ASSERT1(wr == NULL); + if (wan_test_bit(WP_TDMV_REGISTER, &wr->flags)){ + DEBUG_EVENT("%s: Unregister WAN FXS/FXO device from Zaptel!\n", + wr->devname); + wan_clear_bit(WP_TDMV_REGISTER, &wr->flags); + zt_unregister(&wr->span); + wan_clear_bit(WP_TDMV_REGISTER, &wr->flags); + } + wan_free(wr); + return; +} + + +static wp_tdmv_remora_t *wan_remora_search(sdla_t * card) +{ + return NULL; +} + +/****************************************************************************** +** wp_tdmv_remora_check_mtu() - +** +** OK +*/ +static int wp_tdmv_remora_check_mtu(void* pcard, unsigned long timeslot_map, int *mtu) +{ + sdla_t *card = (sdla_t*)pcard; + int x, num_of_channels = 0, max_channels; + + max_channels = WAN_FE_MAX_CHANNELS(&card->fe); + for (x = 0; x < max_channels; x++) { + if (wan_test_bit(x,×lot_map)){ + num_of_channels++; + } + } + *mtu = ZT_CHUNKSIZE * num_of_channels; + return 0; +} + +/****************************************************************************** +** wp_tdmv_remora_create() - +*tdmv_* +** OK +*/ +static int wp_tdmv_remora_create(void* pcard, wan_xilinx_conf_t *conf) +{ + sdla_t *card = (sdla_t*)pcard; + wp_tdmv_remora_t *wr = NULL; + wan_tdmv_t *tmp = NULL; + + WAN_ASSERT(card == NULL); + WAN_ASSERT(conf->tdmv_span_no == 0); + wr = wan_remora_search(card); + if (wr){ + DEBUG_EVENT("%s: AFT remora FXO/FXS card already configured!\n", + card->devname); + return -EINVAL; + } + /* We are forcing to register wanpipe devices at the same sequence + * that it defines in /etc/zaptel.conf */ + WAN_LIST_FOREACH(tmp, &wan_tdmv_head, next){ + if (tmp->spanno == conf->tdmv_span_no){ + DEBUG_EVENT("%s: Registering device with an incorrect span number!\n", + card->devname); + DEBUG_EVENT("%s: Another wanpipe device already configured to span #%d!\n", + card->devname, conf->tdmv_span_no); + return -EINVAL; + } + if (!WAN_LIST_NEXT(tmp, next)){ + break; + } + } + + memset(&card->wan_tdmv, 0x0, sizeof(wan_tdmv_t)); + card->wan_tdmv.max_timeslots = card->fe.rm_param.max_fe_channels; + card->wan_tdmv.spanno = conf->tdmv_span_no; + card->wandev.fe_notify_iface.hook_state = wp_tdmv_remora_hook; + card->wandev.fe_notify_iface.check_hook_state = wp_tdmv_remora_check_hook; + + wr = wan_malloc(sizeof(wp_tdmv_remora_t)); + if (wr == NULL){ + return -ENOMEM; + } + memset(wr, 0x0, sizeof(wp_tdmv_remora_t)); + card->wan_tdmv.sc = wr; + wr->spanno = conf->tdmv_span_no-1; + wr->num = wp_remora_no++; + wr->card = card; + wr->devname = card->devname; + wr->max_timeslots = card->fe.rm_param.max_fe_channels; + wr->max_rxtx_len = 0; + wan_spin_lock_init(&wr->lock); + wan_spin_lock_init(&wr->tx_rx_lock); + + if (tmp){ + WAN_LIST_INSERT_AFTER(tmp, &card->wan_tdmv, next); + }else{ + WAN_LIST_INSERT_HEAD(&wan_tdmv_head, &card->wan_tdmv, next); + } + return 0; +} + + +/****************************************************************************** +** wp_tdmv_reg() - +** +** Returns: 0-31 - Return TDM Voice channel number. +** -EINVAL - otherwise +** OK +*/ +static int wp_tdmv_remora_reg(void* pcard, wanif_conf_t *conf, netdevice_t *dev) +{ + sdla_t *card = (sdla_t*)pcard; + sdla_fe_t *fe = &card->fe; + wan_tdmv_t *wan_tdmv = &card->wan_tdmv; + wp_tdmv_remora_t *wr = NULL; + int i, channo = 0; + + WAN_ASSERT(wan_tdmv->sc == NULL); + wr = wan_tdmv->sc; + + if (wan_test_bit(WP_TDMV_REGISTER, &wr->flags)){ + DEBUG_EVENT( + "%s: Error: Master device has already been configured!\n", + card->devname); + return -EINVAL; + } + + for(i = 0; i < wr->max_timeslots; i++){ + if (wan_test_bit(i, &conf->active_ch) && + wan_test_bit(i, &fe->rm_param.module_map)){ + if (conf->tdmv_echo_off){ + wan_set_bit(i, &wr->echo_off_map); + } + channo = i; + break; + } + } + + if (i == wr->max_timeslots){ + DEBUG_EVENT( + "%s: Error: TDMV iface %s failed to configure for %08lX timeslots!\n", + card->devname, + conf->name, + conf->active_ch); + return -EINVAL; + } + + DEBUG_EVENT( + "%s: Registering TDMV %s iface to module %d!\n", + card->devname, + WP_REMORA_DECODE_TYPE(fe->rm_param.mod[channo].type), + channo+1); + wan_set_bit(channo, &wr->reg_module_map); + + if (conf->tdmv_echo_off){ + DEBUG_EVENT("%s: TDMV Echo Ctrl:Off\n", + wr->devname); + } + memset(wr->chans[channo].sreadchunk, WAN_TDMV_IDLE_FLAG, ZT_CHUNKSIZE); + memset(wr->chans[channo].swritechunk, WAN_TDMV_IDLE_FLAG, ZT_CHUNKSIZE); + wr->chans[channo].readchunk = wr->chans[channo].sreadchunk; + wr->chans[channo].writechunk = wr->chans[channo].swritechunk; + wr->channelized = WAN_TRUE; + + wp_tdmv_remora_check_mtu(card, conf->active_ch, &wr->max_rxtx_len); + return channo; +} + + +/****************************************************************************** +** wp_tdmv_unreg() - +** +** OK +*/ +static int wp_tdmv_remora_unreg(void* pcard, unsigned long ts_map) +{ + sdla_t *card = (sdla_t*)pcard; + sdla_fe_t *fe = &card->fe; + wan_tdmv_t *wan_tdmv = &card->wan_tdmv; + wp_tdmv_remora_t *wr = NULL; + int channo = 0; + + WAN_ASSERT(wan_tdmv->sc == NULL); + wr = wan_tdmv->sc; + + for(channo = 0; channo < wr->max_timeslots; channo++){ + if (wan_test_bit(channo, &wr->reg_module_map)){ + DEBUG_EVENT( + "%s: Unregistering TDMV %s iface from module %d!\n", + card->devname, + WP_REMORA_DECODE_TYPE(fe->rm_param.mod[channo].type), + channo+1); + wan_clear_bit(channo, &wr->reg_module_map); + wan_clear_bit(channo, &wr->echo_off_map); + memset(wr->chans[channo].sreadchunk, + WAN_TDMV_IDLE_FLAG, + ZT_CHUNKSIZE); + memset(wr->chans[channo].swritechunk, + WAN_TDMV_IDLE_FLAG, + ZT_CHUNKSIZE); + wr->chans[channo].readchunk = + wr->chans[channo].sreadchunk; + wr->chans[channo].writechunk = + wr->chans[channo].swritechunk; + } + } + return 0; +} + + +/****************************************************************************** +** wp_tdmv_remove() - +** +** OK +*/ +static int wp_tdmv_remora_remove(void* pcard) +{ + sdla_t *card = (sdla_t*)pcard; + wan_tdmv_t *wan_tdmv = &card->wan_tdmv; + wp_tdmv_remora_t *wr = NULL; + + if (!card->wan_tdmv.sc){ + return 0; + } + + wr = wan_tdmv->sc; + /* Release span, possibly delayed */ + if (wr && wr->reg_module_map){ + DEBUG_EVENT( + "%s: Some interfaces are not unregistered (%08lX)!\n", + card->devname, + wr->reg_module_map); + return -EINVAL; + } + if (wr && wr->usecount){ + DEBUG_EVENT("%s: ERROR: Wanpipe is still used by Asterisk!\n", + card->devname); + return -EINVAL; + } + + if (wr){ + wan_clear_bit(WP_TDMV_RUNNING, &wr->flags); + wan_clear_bit(WP_TDMV_UP, &wr->flags); + wan_tdmv->sc = NULL; + WAN_LIST_REMOVE(wan_tdmv, next); + wp_tdmv_release(wr); + }else{ + wan_tdmv->sc = NULL; + } + return 0; +} + +static int wp_tdmv_remora_state(void* pcard, int state) +{ + sdla_t *card = (sdla_t*)pcard; + wan_tdmv_t *wan_tdmv = &card->wan_tdmv; + wp_tdmv_remora_t *wr = NULL; + + WAN_ASSERT(wan_tdmv->sc == NULL); + wr = (wp_tdmv_remora_t*)wan_tdmv->sc; + + switch(state){ + case WAN_CONNECTED: + DEBUG_TDMV("%s: TDMV Remora state is CONNECTED!\n", + wr->devname); + wan_set_bit(WP_TDMV_UP, &wr->flags); + break; + + case WAN_DISCONNECTED: + DEBUG_TDMV("%s: TDMV Remora state is DISCONNECTED!\n", + wr->devname); + wan_clear_bit(WP_TDMV_UP, &wr->flags); + break; + } + return 0; +} + +/****************************************************************************** +** wp_tdmv_running() - +** +** OK +*/ +static int wp_tdmv_remora_running(void* pcard) +{ + sdla_t *card = (sdla_t*)pcard; + wan_tdmv_t *wan_tdmv = &card->wan_tdmv; + wp_tdmv_remora_t *wr = NULL; + + wr = wan_tdmv->sc; + if (wr && wr->usecount){ + DEBUG_EVENT("%s: WARNING: Wanpipe is still used by Asterisk!\n", + card->devname); + return -EINVAL; + } + return 0; +} + +/****************************************************************************** +** wp_tdmv_remora_is_rbsbits() - +** +** OK +*/ +static int wp_tdmv_remora_is_rbsbits(wan_tdmv_t *wan_tdmv) +{ + return 0; +} + +/****************************************************************************** +** wp_tdmv_rx_chan() - +** +** OK +*/ +static int wp_tdmv_remora_rx_chan(wan_tdmv_t *wan_tdmv, int channo, + unsigned char *rxbuf, + unsigned char *txbuf) +{ + wp_tdmv_remora_t *wr = wan_tdmv->sc; +#ifdef CONFIG_PRODUCT_WANPIPE_TDM_VOICE_ECHOMASTER + wan_tdmv_rxtx_pwr_t *pwr_rxtx = NULL; +#endif + + WAN_ASSERT2(wr == NULL, -EINVAL); + WAN_ASSERT2(channo < 0, -EINVAL); + WAN_ASSERT2(channo > 31, -EINVAL); + + if (!IS_TDMV_UP(wr)){ + return -EINVAL; + } + +#ifdef CONFIG_PRODUCT_WANPIPE_TDM_VOICE_ECHOMASTER + pwr_rxtx = &wan_tdmv->chan_pwr[channo]; +#endif + +#if 0 +DEBUG_EVENT("Module %d: RX: %02X %02X %02X %02X %02X %02X %02X %02X\n", + channo, + rxbuf[0], + rxbuf[1], + rxbuf[2], + rxbuf[3], + rxbuf[4], + rxbuf[5], + rxbuf[6], + rxbuf[7] + ); +#endif + wr->chans[channo].readchunk = rxbuf; + wr->chans[channo].writechunk = txbuf; + +#ifdef CONFIG_PRODUCT_WANPIPE_TDM_VOICE_ECHOMASTER + wp_tdmv_echo_check(wan_tdmv, &wr->chans[channo], channo); +#endif + + if (!wan_test_bit(channo, &wr->echo_off_map)){ +/*Echo spike starts at 25bytes*/ +#ifdef CONFIG_PRODUCT_WANPIPE_TDM_VOICE_ECHOMASTER + if(pwr_rxtx->current_state != ECHO_ABSENT){ +#endif +#if 0 +/* Echo spike starts at 16 bytes */ + + zt_ec_chunk( + &wr->chans[channo], + wr->chans[channo].readchunk, + wr->chans[channo].writechunk); +#endif + +#if 1 +/*Echo spike starts at 9 bytes*/ + zt_ec_chunk( + &wr->chans[channo], + wr->chans[channo].readchunk, + wr->ec_chunk1[channo]); + memcpy( + wr->ec_chunk1[channo], + wr->chans[channo].writechunk, + ZT_CHUNKSIZE); +#endif + +#if 0 +/*Echo spike starts at bytes*/ + zt_ec_chunk( + &wr->chans[channo], + wr->chans[channo].readchunk, + wr->ec_chunk1[channo]); + memcpy( + wr->ec_chunk1[channo], + wr->ec_chunk2[channo], + ZT_CHUNKSIZE); + + memcpy( + wr->ec_chunk2[channo], + wr->chans[channo].writechunk, + ZT_CHUNKSIZE); +#endif + +#ifdef CONFIG_PRODUCT_WANPIPE_TDM_VOICE_ECHOMASTER + } /*if(pwr_rxtx->current_state != ECHO_ABSENT) */ +#endif + } /* if (!wan_test_bit(channo, &wr->echo_off_map)) */ + + return 0; +} + +static int wp_tdmv_remora_rx_tx_span(void *pcard) +{ + sdla_t *card = (sdla_t*)pcard; + sdla_fe_t *fe = &card->fe; + wan_tdmv_t *wan_tdmv = &card->wan_tdmv; + wp_tdmv_remora_t *wr = NULL; + int x; + + WAN_ASSERT(wan_tdmv->sc == NULL); + wr = wan_tdmv->sc; + + wr->intcount++; + for (x = 0; x < wr->max_timeslots; x++) { + if (!wan_test_bit(x, &wr->reg_module_map)){ + continue; + } + if (fe->rm_param.mod[x].type == MOD_TYPE_FXS){ +#if defined(REG_WRITE_SHADOW) + if (wr->mod[x].fxs.lasttxhook_update){ + WRITE_RM_REG(x, 64, wr->mod[x].fxs.lasttxhook); + wr->mod[x].fxs.lasttxhook_update = 0; + continue; + } +#endif + + if (wr->mod[x].fxs.lasttxhook == 0x4) { + /* RINGing, prepare for OHT */ + wr->mod[x].fxs.ohttimer = OHT_TIMER << 3; + if (fe->fe_cfg.cfg.remora.reversepolarity){ + /* OHT mode when idle */ + fe->rm_param.mod[x].u.fxs.idletxhookstate = 0x6; + }else{ + fe->rm_param.mod[x].u.fxs.idletxhookstate = 0x2; + } + } else { + if (wr->mod[x].fxs.ohttimer) { + wr->mod[x].fxs.ohttimer-= ZT_CHUNKSIZE; + if (!wr->mod[x].fxs.ohttimer) { + if (fe->fe_cfg.cfg.remora.reversepolarity){ + /* Switch to active */ + fe->rm_param.mod[x].u.fxs.idletxhookstate = 0x5; + }else{ + fe->rm_param.mod[x].u.fxs.idletxhookstate = 0x1; + } + if ((wr->mod[x].fxs.lasttxhook == 0x2) || (wr->mod[x].fxs.lasttxhook = 0x6)) { + /* Apply the change if appropriate */ + if (fe->fe_cfg.cfg.remora.reversepolarity){ + wr->mod[x].fxs.lasttxhook = 0x5; + }else{ + wr->mod[x].fxs.lasttxhook = 0x1; + } + WRITE_RM_REG(x, 64, wr->mod[x].fxs.lasttxhook); + } + } + } + } + + } else if (fe->rm_param.mod[x].type == MOD_TYPE_FXO) { + + if (wr->mod[x].fxo.echotune){ + DEBUG_EVENT("%s: Module %d: Setting echo registers: \n", + fe->name, x); + + /* Set the ACIM register */ + WRITE_RM_REG(x, 30, wr->mod[x].fxo.echoregs.acim); + + /* Set the digital echo canceller registers */ + WRITE_RM_REG(x, 45, wr->mod[x].fxo.echoregs.coef1); + WRITE_RM_REG(x, 46, wr->mod[x].fxo.echoregs.coef2); + WRITE_RM_REG(x, 47, wr->mod[x].fxo.echoregs.coef3); + WRITE_RM_REG(x, 48, wr->mod[x].fxo.echoregs.coef4); + WRITE_RM_REG(x, 49, wr->mod[x].fxo.echoregs.coef5); + WRITE_RM_REG(x, 50, wr->mod[x].fxo.echoregs.coef6); + WRITE_RM_REG(x, 51, wr->mod[x].fxo.echoregs.coef7); + WRITE_RM_REG(x, 52, wr->mod[x].fxo.echoregs.coef8); + + DEBUG_EVENT("%s: Module %d: Set echo registers successfully\n", + fe->name, x); + wr->mod[x].fxo.echotune = 0; + } +#if defined(REG_WRITE_SHADOW) + if (wr->reg0shadow_update[x]){ + /* Read first shadow reg */ + WRITE_RM_REG(x, 5, wr->reg0shadow[x]); + wr->reg0shadow_update[x] = 0; + } +#endif + } +#ifdef PULSE_DIALING + /* + ** Alex 31 Mar, 2006 + ** Check for HOOK status every interrupt + ** (in pulse mode is very critical) */ + wp_tdmv_remora_check_hook(fe, x); +#endif + } + + x = wr->intcount % MAX_REMORA_MODULES; + if (wan_test_bit(x, &wr->reg_module_map)) { +#if defined(REG_SHADOW) + if (fe->rm_param.mod[x].type == MOD_TYPE_FXS) { + /* Read first shadow reg */ + wr->reg0shadow[x] = READ_RM_REG(x, 68); + /* Read second shadow reg */ + wr->reg1shadow[x] = READ_RM_REG(x, 64); + /* Read third shadow reg */ + wr->reg2shadow[x] = READ_RM_REG(x, 8); + }else if (fe->rm_param.mod[x].type == MOD_TYPE_FXO) { + /* Read first shadow reg */ + wr->reg0shadow[x] = READ_RM_REG(x, 5); + /* Read second shadow reg */ + wr->reg1shadow[x] = READ_RM_REG(x, 29); + } +#endif + +#ifndef PULSE_DIALING + wp_tdmv_remora_check_hook(fe, x); +#endif + if (fe->rm_param.mod[x].type == MOD_TYPE_FXS) { + if (!(wr->intcount & 0xf0)) + wp_tdmv_remora_proslic_recheck_sanity(wr, x); + } + } + + if (!(wr->intcount % 10000)) { + /* Accept an alarm once per 10 seconds */ + for (x = 0; x < wr->max_timeslots; x++) + if (wan_test_bit(x, &wr->reg_module_map) && + (fe->rm_param.mod[x].type == MOD_TYPE_FXS)) { + if (wr->mod[x].fxs.palarms){ + wr->mod[x].fxs.palarms--; + } + } + } + + zt_receive(&wr->span); + zt_transmit(&wr->span); + + return 0; +} + diff -Nur linux.org/drivers/net/wan/sdla_sdlc.c linux-2.6.17/drivers/net/wan/sdla_sdlc.c --- linux.org/drivers/net/wan/sdla_sdlc.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/drivers/net/wan/sdla_sdlc.c 2006-08-30 10:07:16.000000000 +0000 @@ -0,0 +1,2452 @@ +/***************************************************************************** +* wanpipe_sdlc.c SDLC driver module. +* +* Authors: Nenad Corbic +* +* Copyright: (c) 2002 Sangoma Technologies Inc. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version +* 2 of the License, or (at your option) any later version. +* ============================================================================ +* Jul 24 2002 Nenad Corbic Initial Version +*****************************************************************************/ + +#include +#include +#include /* WANPIPE common user API definitions */ +#include /* WAN router definitions */ +#include +#include +#include /* Socket Driver common area */ +#include +#include /* CHDLC firmware API definitions */ + +/****** Defines & Macros ****************************************************/ + +/* Private critical flags */ +enum { + REG_CRIT = PRIV_CRIT +}; + +/* reasons for enabling the timer interrupt on the adapter */ +#define TMR_INT_ENABLED_UDP 0x01 +#define TMR_INT_ENABLED_UPDATE 0x02 + +#define CHDLC_DFLT_DATA_LEN 1500 /* default MTU */ +#define CHDLC_HDR_LEN 1 + +#define IFF_POINTTOPOINT 0x10 + +#define CHDLC_API 0x01 + +#define PORT(x) (x == 0 ? "PRIMARY" : "SECONDARY" ) +#define MAX_BH_BUFF 10 + +#define CRC_LENGTH 2 +#define PPP_HEADER_LEN 4 +#define MAX_TRACE_LEN 25 +#define MAX_TRACE_ASCII_LEN MAX_TRACE_LEN*3+5 +#define MAX_CMD_RETRY 10 /* max number of firmware retries */ + +#ifndef ARPHRD_SDLC +#define ARPHRD_SDLC 514 +#endif +/******Data Structures*****************************************************/ + +/* This structure is placed in the private data area of the device structure. + * The card structure used to occupy the private area but now the following + * structure will incorporate the card structure along with CHDLC specific data + */ + +typedef struct sdlc_private_area +{ + wanpipe_common_t common; + sdla_t *card; + int TracingEnabled; /* For enabling Tracing */ + unsigned long curr_trace_addr; /* Used for Tracing */ + unsigned long start_trace_addr; + unsigned long end_trace_addr; + unsigned long base_addr_trace_buffer; + unsigned long end_addr_trace_buffer; + unsigned short number_trace_elements; + unsigned available_buffer_space; + unsigned long router_start_time; + unsigned char route_status; + unsigned char route_removed; + unsigned long tick_counter; /* For 5s timeout counter */ + unsigned long router_up_time; + u32 IP_address; /* IP addressing */ + u32 IP_netmask; + unsigned char mc; /* Mulitcast support on/off */ + unsigned short udp_pkt_lgth; /* udp packet processing */ + char udp_pkt_src; + unsigned short timer_int_enabled; + char update_comms_stats; /* updating comms stats */ + + unsigned long trace_state; + + /* Entry in proc fs per each interface */ + struct proc_dir_entry* dent; + unsigned char ignore_modem; + + unsigned char udp_pkt_data[sizeof(wan_udp_pkt_t)+10]; + atomic_t udp_pkt_len; + + wp_sdlc_reg_t wp_sdlc_register; + +} sdlc_private_area_t; + +/* Route Status options */ +#define NO_ROUTE 0x00 +#define ADD_ROUTE 0x01 +#define ROUTE_ADDED 0x02 +#define REMOVE_ROUTE 0x03 + + +/****** Function Prototypes *************************************************/ +/* WAN link driver entry points. These are called by the WAN router module. */ +static int update (wan_device_t* wandev); +static int new_if (wan_device_t* wandev, netdevice_t* dev, + wanif_conf_t* conf); +static int del_if (wan_device_t* wandev, netdevice_t* dev); + +/* Network device interface */ +static int if_init (netdevice_t* dev); +static int if_open (netdevice_t* dev); +static int if_close (netdevice_t* dev); +static int if_send (struct sk_buff* skb, netdevice_t* dev); +static struct net_device_stats* if_stats (netdevice_t* dev); + +/* CHDLC Firmware interface functions */ +static int sdlc_configure (sdla_t* card, void* data); +static int sdlc_comm_enable (sdla_t* card); +static int sdlc_comm_disable (sdla_t* card); +static int sdlc_read_version (sdla_t* card, char* str); +static int sdlc_set_intr_mode (sdla_t* card, unsigned mode); +static int sdlc_send (sdla_t* card, void* data, unsigned len); +static int sdlc_list_stations_with_ifrms (sdla_t* card); + +static int sdlc_read_comm_err_stats (sdla_t* card); +static int sdlc_read_op_stats (sdla_t* card); +static int config_sdlc (sdla_t *card); + + +/* Miscellaneous CHDLC Functions */ +static int set_sdlc_config (sdla_t* card); +static int sdlc_error (sdla_t *card, int err, wan_mbox_t *mb); +static int process_sdlc_exception(sdla_t *card); +static int update_comms_stats(sdla_t* card, + sdlc_private_area_t* sdlc_priv_area); +static void port_set_state (sdla_t *card, int); + +/* Interrupt handlers */ +static void wp_sdlc_isr (sdla_t* card); +static void rx_intr (sdla_t* card); +static void tx_intr(sdla_t *card); +static void timer_intr(sdla_t *); + +/* Miscellaneous functions */ +static int intr_test( sdla_t* card); +static int process_udp_mgmt_pkt(sdla_t* card, netdevice_t* dev, + sdlc_private_area_t* sdlc_priv_area,int local_dev); + +static int chdlc_get_config_info(void* priv, struct seq_file* m, int*); +static int chdlc_get_status_info(void* priv, struct seq_file* m, int*); +static int chdlc_set_dev_config(struct file*, const char*, unsigned long, void *); +static int chdlc_set_if_info(struct file*, const char*, unsigned long, void *); + +void send_oob_msg(sdla_t *card, wan_mbox_t *mb); + + + + +/****** Public Functions ****************************************************/ + +/*============================================================================ + * Cisco HDLC protocol initialization routine. + * + * This routine is called by the main WANPIPE module during setup. At this + * point adapter is completely initialized and firmware is running. + * o read firmware version (to make sure it's alive) + * o configure adapter + * o initialize protocol-specific fields of the adapter data space. + * + * Return: 0 o.k. + * < 0 failure. + */ +int wp_sdlc_init (sdla_t* card, wandev_conf_t* conf) +{ + unsigned char port_num; + int err; + union{ + char str[80]; + } u; + + volatile wan_mbox_t* mb; + wan_mbox_t* mb1; + + /* Verify configuration ID */ + if (conf->config_id != WANCONFIG_SDLC) { + printk(KERN_INFO "%s: invalid configuration ID %u!\n", + card->devname, conf->config_id); + return -EINVAL; + } + + /* Find out which Port to use */ + if (conf->comm_port == WANOPT_PRI){ + card->u.sdlc.comm_port = conf->comm_port; + }else{ + printk(KERN_INFO "%s: ERROR - Invalid Port Selected!\n", + card->wandev.name); + return -EINVAL; + } + + + /* Initialize protocol-specific fields */ + /* Set a pointer to the actual mailbox in the allocated virtual + * memory area */ + /* Alex Apr 8 2004 Sangoma ISA card */ + card->mbox_off = BASE_ADDR_OF_MB_STRUCTS; + card->rxmb_off = 0xE230; + + mb = &card->wan_mbox; + mb1 = &card->wan_mbox; + + if (!card->configured){ + /* Wait for the board to initialize. */ + udelay(500); + } + + + /* TE1 and 56K boards are not supported by this firmware */ + if (IS_TE1_MEDIA(&conf->fe_cfg) || IS_56K_MEDIA(&conf->fe_cfg)) { + printk(KERN_INFO "%s: SDLC protocol doesn't support TE1 or 56K cards\n", + card->devname); + return -EINVAL; + } + + if (sdlc_read_version(card, u.str)) + return -EIO; + + printk(KERN_INFO "%s: Running SDLC firmware v%s\n", + card->devname,u.str); + + card->isr = &wp_sdlc_isr; + card->poll = NULL; + card->exec = NULL; + card->wandev.update = &update; + card->wandev.new_if = &new_if; + card->wandev.del_if = &del_if; + card->wandev.udp_port = conf->udp_port; + + card->wandev.new_if_cnt = 0; + + // Proc fs functions + card->wandev.get_config_info = &chdlc_get_config_info; + card->wandev.get_status_info = &chdlc_get_status_info; + card->wandev.set_dev_config = &chdlc_set_dev_config; + card->wandev.set_if_info = &chdlc_set_if_info; + + card->wandev.ttl = conf->ttl; + card->wandev.interface = conf->interface; + card->wandev.clocking = conf->clocking; + + port_num = card->u.sdlc.comm_port; + + /* Setup Port Bps */ + if(card->wandev.clocking) { + + if(conf->bps > MAX_PERMITTED_BAUD_RATE) { + conf->bps = MAX_PERMITTED_BAUD_RATE; + printk(KERN_INFO "%s: Baud too high!\n", + card->wandev.name); + printk(KERN_INFO "%s: Baud rate set to %u bps\n", + card->wandev.name, MAX_PERMITTED_BAUD_RATE); + } + + card->wandev.bps = conf->bps; + }else{ + card->wandev.bps = 0; + } + + /* For Primary Port 0 */ + card->wandev.mtu = (conf->mtu >= MIN_PERMITTED_I_FIELD_LENGTH) ? + wp_min(conf->mtu, MAX_PERMITTED_I_FIELD_LENGTH) : + MAX_PERMITTED_I_FIELD_LENGTH; + + + /* Alex Apr 8 2004 Sangoma ISA card */ + card->flags_off = ADDR_INTERRUPT_REPORT_INTERFACE_BYTE; + card->intr_type_off = + card->flags_off + + offsetof(INTERRUPT_INFORMATION_STRUCT, interrupt_type); + card->intr_perm_off = + card->flags_off + + offsetof(INTERRUPT_INFORMATION_STRUCT, interrupt_permission); + + /* This is for the ports link state */ + card->wandev.state = WAN_DUALPORT; + card->u.sdlc.state = WAN_DISCONNECTED; + + if (card->u.sdlc.comm_enabled){ + sdlc_comm_disable(card); + port_set_state(card, WAN_DISCONNECTED); + } + + memcpy(&card->wandev.sdlc_cfg,&conf->u.sdlc,sizeof(wan_sdlc_conf_t)); + + if (set_sdlc_config(card)) { + printk(KERN_INFO "%s: SDLC Configuration Failed: Off=%i\n", + card->devname,mb->wan_data_len); + return -EINVAL; + } + + if (!card->wandev.piggyback){ + err = intr_test(card); + + if(err || (card->timer_int_enabled < MAX_INTR_TEST_COUNTER)) { + printk(KERN_INFO "%s: Interrupt test failed (%i)\n", + card->devname, card->timer_int_enabled); + printk(KERN_INFO "%s: Please choose another interrupt\n", + card->devname); + return -EIO; + } + + printk(KERN_INFO "%s: Interrupt test passed (%i)\n", + card->devname, card->timer_int_enabled); + } + + err=config_sdlc(card); + if (err!=0){ + return err; + } + + printk(KERN_INFO "\n"); + + return 0; +} + +/******* WAN Device Driver Entry Points *************************************/ + +/*============================================================================ + * Update device status & statistics + * This procedure is called when updating the PROC file system and returns + * various communications statistics. These statistics are accumulated from 3 + * different locations: + * 1) The 'if_stats' recorded for the device. + * 2) Communication error statistics on the adapter. + * 3) CHDLC operational statistics on the adapter. + * The board level statistics are read during a timer interrupt. Note that we + * read the error and operational statistics during consecitive timer ticks so + * as to minimize the time that we are inside the interrupt handler. + * + */ +static int update (wan_device_t* wandev) +{ + sdla_t* card = wandev->private; + netdevice_t* dev; + volatile sdlc_private_area_t* sdlc_priv_area; + unsigned long timeout; + + /* sanity checks */ + if((wandev == NULL) || (wandev->private == NULL)) + return -EFAULT; + + if(wandev->state == WAN_UNCONFIGURED) + return -ENODEV; + + /* more sanity checks */ + if(!card->flags_off) + return -ENODEV; + + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + if(dev == NULL) + return -ENODEV; + + if((sdlc_priv_area=dev->priv) == NULL) + return -ENODEV; + + if(sdlc_priv_area->update_comms_stats){ + return -EAGAIN; + } + + /* we will need 2 timer interrupts to complete the */ + /* reading of the statistics */ + sdlc_priv_area->update_comms_stats = 2; + card->hw_iface.set_bit(card->hw, card->intr_perm_off, INTERRUPT_ON_TIMER); + sdlc_priv_area->timer_int_enabled = TMR_INT_ENABLED_UPDATE; + + /* wait a maximum of 1 second for the statistics to be updated */ + timeout = jiffies; + for(;;) { + if(sdlc_priv_area->update_comms_stats == 0) + break; + if ((jiffies - timeout) > (1 * HZ)){ + sdlc_priv_area->update_comms_stats = 0; + sdlc_priv_area->timer_int_enabled &= + ~TMR_INT_ENABLED_UPDATE; + return -EAGAIN; + } + } + + return 0; +} + + +/*============================================================================ + * Create new logical channel. + * This routine is called by the router when ROUTER_IFNEW IOCTL is being + * handled. + * o parse media- and hardware-specific configuration + * o make sure that a new channel can be created + * o allocate resources, if necessary + * o prepare network device structure for registaration. + * + * Return: 0 o.k. + * < 0 failure (channel will not be created) + */ +static int new_if (wan_device_t* wandev, netdevice_t* dev, wanif_conf_t* conf) +{ + + sdla_t* card = wandev->private; + sdlc_private_area_t* sdlc_priv_area; + int err = 0; + + if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) { + printk(KERN_INFO "%s: invalid interface name!\n", + card->devname); + return -EINVAL; + } + + /* allocate and initialize private data */ + sdlc_priv_area = kmalloc(sizeof(sdlc_private_area_t), GFP_KERNEL); + if(sdlc_priv_area == NULL){ + return -ENOMEM; + } + + memset(sdlc_priv_area, 0, sizeof(sdlc_private_area_t)); + + sdlc_priv_area->card = card; + + /* initialize data */ + strcpy(card->u.sdlc.if_name, conf->name); + + sdlc_priv_area->common.sk = NULL; + sdlc_priv_area->common.state = WAN_CONNECTING; + sdlc_priv_area->common.dev = dev; + + if(card->wandev.new_if_cnt > 0) { + err = -EEXIST; + goto new_if_error; + } + + card->wandev.new_if_cnt++; + + sdlc_priv_area->TracingEnabled = 0; + + printk(KERN_INFO "%s: Firmware running in SDLC Mode\n", + wandev->name); + + if(strcmp(conf->usedby, "STACK") == 0) { + printk(KERN_INFO "%s: Driver running in API STACK mode!\n", + wandev->name); + card->u.sdlc.usedby = STACK; + sdlc_priv_area->common.usedby=STACK; + }else{ + printk(KERN_INFO "%s: Driver running in API mode!\n", + wandev->name); + card->u.sdlc.usedby = API; + sdlc_priv_area->common.usedby =API; + } + + /* Get Multicast Information */ + sdlc_priv_area->mc = conf->mc; + + dev->init = &if_init; + dev->priv = sdlc_priv_area; + +#if 0 + /* + * Create interface file in proc fs. + */ + err = wanrouter_proc_add_interface(wandev, + &sdlc_priv_area->dent, + card->u.sdlc.if_name, + dev); + if (err){ + printk(KERN_INFO + "%s: can't create /proc/net/router/sdlc/%s entry!\n", + card->devname, card->u.sdlc.if_name); + goto new_if_error; + } +#endif + + return 0; + +new_if_error: + + if (sdlc_priv_area){ + kfree(sdlc_priv_area); + } + + dev->priv=NULL; + + return err; + +} + + + +/*============================================================================ + * Delete logical channel. + */ +static int del_if (wan_device_t* wandev, netdevice_t* dev) +{ + sdlc_private_area_t *sdlc_priv_area = dev->priv; + sdla_t *card = sdlc_priv_area->card; + unsigned long smp_lock; + + /* Delete interface name from proc fs. */ + //wanrouter_proc_delete_interface(wandev, card->u.sdlc.if_name); + + wan_spin_lock_irq(&wandev->lock,&smp_lock); + + /* Bug Fix: Kernel 2.2.X + * We must manually remove the ioctl call binding + * since in some cases (mrouted) daemons continue + * to call ioctl() after the device has gone down */ + dev->do_ioctl = NULL; + dev->hard_header = NULL; + dev->rebuild_header = NULL; + + sdlc_set_intr_mode(card, 0); + if (card->u.sdlc.comm_enabled){ + sdlc_comm_disable(card); + } + + wan_spin_unlock_irq(&wandev->lock,&smp_lock); + + port_set_state(card, WAN_DISCONNECTED); + + return 0; +} + +/** + * if_do_ioctl - Ioctl handler for fr + * @dev: Device subject to ioctl + * @ifr: Interface request block from the user + * @cmd: Command that is being issued + * + * This function handles the ioctls that may be issued by the user + * to control the settings of a FR. It does both busy + * and security checks. This function is intended to be wrapped by + * callers who wish to add additional ioctl calls of their own. + */ +/* SNMP */ +static int if_do_ioctl(netdevice_t *dev, struct ifreq *ifr, int cmd) +{ + sdlc_private_area_t* chan= (sdlc_private_area_t*)dev->priv; + unsigned long smp_flags; + sdla_t *card; + wan_udp_pkt_t *wan_udp_pkt; + wan_mbox_t *usr_mb, *mb; + int err=0; + char usedby=API; + + if (!chan){ + return -ENODEV; + } + card=chan->card; + mb=&card->wan_mbox; + + if (chan->common.usedby == STACK){ + //if (ifr->ifr_flags != STACK_IF_REQ){ + // printk(KERN_INFO + // "%s: Stack if cmd request with invalid flag %i, expecting %i\n", + // card->devname,ifr->ifr_flags,STACK_IF_REQ); + // return -EINVAL; + //} + usedby=STACK; + } + + + switch(cmd){ + + case SIOC_WANPIPE_DEV_STATE: + + err = chan->common.state; + break; + + case SIOC_WANPIPE_BIND_SK: + + if (!ifr){ + err= -EINVAL; + break; + } + + DEBUG_TEST("%s: SIOC_WANPIPE_BIND_SK \n",__FUNCTION__); + spin_lock_irqsave(&card->wandev.lock,smp_flags); + err=wan_bind_api_to_svc(chan,ifr->ifr_data); + spin_unlock_irqrestore(&card->wandev.lock,smp_flags); + break; + + case SIOC_WANPIPE_UNBIND_SK: + + if (!ifr){ + err= -EINVAL; + break; + } + + DEBUG_TEST("%s: SIOC_WANPIPE_UNBIND_SK \n",__FUNCTION__); + + spin_lock_irqsave(&card->wandev.lock,smp_flags); + err=wan_unbind_api_from_svc(chan,ifr->ifr_data); + spin_unlock_irqrestore(&card->wandev.lock,smp_flags); + break; + + + case SIOC_WANPIPE_PIPEMON: + + NET_ADMIN_CHECK(); + + if (atomic_read(&chan->udp_pkt_len) != 0){ + return -EBUSY; + } + + atomic_set(&chan->udp_pkt_len,MAX_LGTH_UDP_MGNT_PKT); + + /* For performance reasons test the critical + * here before spin lock */ + if (test_bit(0,&card->in_isr)){ + atomic_set(&chan->udp_pkt_len,0); + return -EBUSY; + } + + + wan_udp_pkt=(wan_udp_pkt_t*)chan->udp_pkt_data; + if (copy_from_user(&wan_udp_pkt->wan_udp_hdr, + ifr->ifr_data, + sizeof(wan_udp_hdr_t))){ + atomic_set(&chan->udp_pkt_len,0); + return -EFAULT; + } + + spin_lock_irqsave(&card->wandev.lock, smp_flags); + + /* We have to check here again because we don't know + * what happened during spin_lock */ + if (test_bit(0,&card->in_isr)) { + printk(KERN_INFO "%s:%s Pipemon command failed, Driver busy: try again.\n", + card->devname,dev->name); + atomic_set(&chan->udp_pkt_len,0); + spin_unlock_irqrestore(&card->wandev.lock, smp_flags); + return -EBUSY; + } + + process_udp_mgmt_pkt(card,dev,chan,1); + + spin_unlock_irqrestore(&card->wandev.lock, smp_flags); + + /* This area will still be critical to other + * PIPEMON commands due to udp_pkt_len + * thus we can release the irq */ + + if (atomic_read(&chan->udp_pkt_len) > sizeof(wan_udp_pkt_t)){ + printk(KERN_INFO "%s: Error: Pipemon buf too bit on the way up! %i\n", + card->devname,atomic_read(&chan->udp_pkt_len)); + atomic_set(&chan->udp_pkt_len,0); + return -EINVAL; + } + + if (copy_to_user(ifr->ifr_data,&wan_udp_pkt->wan_udp_hdr,sizeof(wan_udp_hdr_t))){ + atomic_set(&chan->udp_pkt_len,0); + return -EFAULT; + } + + atomic_set(&chan->udp_pkt_len,0); + return 0; + + case SIOC_WANPIPE_EXEC_CMD: + + usr_mb=(wan_mbox_t*)ifr->ifr_ifru.ifru_data; + if (!usr_mb){ + printk (KERN_INFO + "%s: Ioctl command %x, has no Mbox attached\n", + card->devname, cmd); + return -EINVAL; + } + + if (usedby == STACK){ + memcpy(&mb->wan_command,&usr_mb->wan_command,sizeof(wan_cmd_t)-1); + }else{ + if (copy_from_user(&mb->wan_command, &usr_mb->wan_command,sizeof(wan_cmd_t)-1)){ + printk(KERN_INFO "%s: SDLC Cmd: Failed to copy mb \n",card->devname); + err = -EFAULT; + break; + } + } + + if (mb->wan_data_len){ + if (usedby == STACK){ + memcpy(&mb->wan_data[0], &usr_mb->wan_data[0] ,mb->wan_data_len); + }else{ + if (copy_from_user(&mb->wan_data[0], &usr_mb->wan_data[0] ,mb->wan_data_len)){ + printk(KERN_INFO "%s: SDLC Cmd: Failed to copy mb data: len= %i\n", + card->devname, mb->wan_data_len); + err = -EFAULT; + break; + } + } + } + + spin_lock_irqsave(&card->wandev.lock,smp_flags); + + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != COMMAND_OK) { + spin_unlock_irqrestore(&card->wandev.lock,smp_flags); + break; + } + + spin_unlock_irqrestore(&card->wandev.lock,smp_flags); + + DEBUG_TEST("%s: CMD=0x%x Err=0x%X\n", + card->devname, + mb->wan_command,mb->wan_return_code); + + /* copy the result back to our buffer */ + + if (usedby == STACK){ + memcpy(&usr_mb->wan_command, &mb->wan_command,sizeof(wan_cmd_t)-1); + }else{ + if (copy_to_user(&usr_mb->wan_command, &mb->wan_command,sizeof(wan_cmd_t)-1)){ + err= -EFAULT; + break; + } + } + + if (mb->wan_data_len) { + if (usedby == STACK){ + memcpy(&usr_mb->wan_data[0], &mb->wan_data[0], mb->wan_data_len); + }else{ + if (copy_to_user(&usr_mb->wan_data[0], &mb->wan_data[0], mb->wan_data_len)){ + err= -EFAULT; + break; + } + } + } + + break; + + + default: + return -EOPNOTSUPP; + } + return err; +} + + + +/****** Network Device Interface ********************************************/ + +/*============================================================================ + * Initialize Linux network interface. + * + * This routine is called only once for each interface, during Linux network + * interface registration. Returning anything but zero will fail interface + * registration. + */ +static int if_init (netdevice_t* dev) +{ + sdlc_private_area_t* sdlc_priv_area = dev->priv; + sdla_t* card = sdlc_priv_area->card; + wan_device_t* wandev = &card->wandev; + + /* NOTE: Most of the dev initialization was + * done in sppp_attach(), called by new_if() + * function. All we have to do here is + * to link four major routines below. + */ + + /* Initialize device driver entry points */ + dev->open = &if_open; + dev->stop = &if_close; + dev->hard_start_xmit = &if_send; + dev->get_stats = &if_stats; +#if defined(LINUX_2_4)||defined(LINUX_2_6) + dev->tx_timeout = NULL; + dev->watchdog_timeo = 0; +#endif + dev->do_ioctl = if_do_ioctl; + + dev->type = ARPHRD_SDLC; /* This breaks the tcpdump */ + + dev->mtu = card->wandev.mtu+sizeof(wan_api_hdr_t); + + /* Initialize hardware parameters */ + dev->irq = wandev->irq; + dev->dma = wandev->dma; + dev->base_addr = wandev->ioport; + card->hw_iface.getcfg(card->hw, SDLA_MEMBASE, &dev->mem_start); //ALEX_TODAY wandev->maddr; + card->hw_iface.getcfg(card->hw, SDLA_MEMEND, &dev->mem_end); //ALEX_TODAY wandev->maddr + wandev->msize - 1; + + /* Set transmit buffer queue length + * If we over fill this queue the packets will + * be droped by the kernel. + * sppp_attach() sets this to 10, but + * 100 will give us more room at low speeds. + */ + dev->tx_queue_len = 100; + + return 0; +} + + +/*============================================================================ + * Open network interface. + * o enable communications and interrupts. + * o prevent module from unloading by incrementing use count + * + * Return 0 if O.k. or errno. + */ +static int if_open (netdevice_t* dev) +{ + sdlc_private_area_t* sdlc_priv_area = dev->priv; + sdla_t* card = sdlc_priv_area->card; + struct timeval tv; + + /* Only one open per interface is allowed */ + + if (open_dev_check(dev)) + return -EBUSY; + + do_gettimeofday(&tv); + sdlc_priv_area->router_start_time = tv.tv_sec; + + netif_start_queue(dev); + + wanpipe_open(card); + + port_set_state(card, WAN_CONNECTED); + + if (sdlc_priv_area->common.usedby==API){ + wan_wakeup_api(sdlc_priv_area); + } + return 0; +} + +/*============================================================================ + * Close network interface. + * o if this is the last close, then disable communications and interrupts. + * o reset flags. + */ +static int if_close (netdevice_t* dev) +{ + sdlc_private_area_t* sdlc_priv_area = dev->priv; + sdla_t* card = sdlc_priv_area->card; + + stop_net_queue(dev); + +#if defined(LINUX_2_1) + dev->start=0; +#endif + + wanpipe_close(card); + + port_set_state(card, WAN_DISCONNECTED); + return 0; +} + +/*============================================================================ + * Send a packet on a network interface. + * o set tbusy flag (marks start of the transmission) to block a timer-based + * transmit from overlapping. + * o check link state. If link is not up, then drop the packet. + * o execute adapter send command. + * o free socket buffer + * + * Return: 0 complete (socket buffer must be freed) + * non-0 packet may be re-transmitted (tbusy must be set) + * + * Notes: + * 1. This routine is called either by the protocol stack or by the "net + * bottom half" (with interrupts enabled). + * 2. Setting tbusy flag will inhibit further transmit requests from the + * protocol stack and can be used for flow control with protocol layer. + */ +static int if_send (struct sk_buff* skb, netdevice_t* dev) +{ + sdlc_private_area_t *sdlc_priv_area = dev->priv; + sdla_t *card = sdlc_priv_area->card; + unsigned long smp_flags; + int err=0; + + if (skb == NULL){ + /* If we get here, some higher layer thinks we've missed an + * tx-done interrupt. + */ + printk(KERN_INFO "%s: Received NULL skb buffer! interface %s got kicked!\n", + card->devname, dev->name); + + wake_net_dev(dev); + return 0; + } + +#if defined(LINUX_2_1) + if (dev->tbusy){ + + /* If our device stays busy for at least 5 seconds then we will + * kick start the device by making dev->tbusy = 0. We expect + * that our device never stays busy more than 5 seconds. So this + * is only used as a last resort. + */ + if((jiffies - sdlc_priv_area->tick_counter) < (5 * HZ)) { + return 1; + } + + ++card->wandev.stats.collisions; + + printk (KERN_INFO "%s: Transmit timed out on %s\n", card->devname,dev->name); + + netif_wake_queue (dev); + } +#endif + + sdlc_priv_area->tick_counter=jiffies; + err=0; + + if (test_and_set_bit(SEND_CRIT, (void*)&card->wandev.critical)){ + + printk(KERN_INFO "%s: Critical in if_send: %lx\n", + card->wandev.name,card->wandev.critical); + ++card->wandev.stats.tx_dropped; + goto if_send_crit_exit; + } + + if (card->wandev.state != WAN_CONNECTED){ + ++card->wandev.stats.tx_dropped; + goto if_send_crit_exit; + } + + wan_spin_lock_irq(&card->wandev.lock,&smp_flags); + err=sdlc_send(card, skb->data, skb->len); + wan_spin_unlock_irq(&card->wandev.lock,&smp_flags); + + if (err){ + err=1; + }else{ + ++card->wandev.stats.tx_packets; + card->wandev.stats.tx_bytes += skb->len; +#if defined(LINUX_2_4)||defined(LINUX_2_6) + dev->trans_start = jiffies; +#endif + + if (test_bit(0,&sdlc_priv_area->trace_state)){ + int i; + DEBUG_EVENT("%s:%s: OUTPUT:\n",card->devname,dev->name); + for (i=0; i < skb->len; i++){ + printk("%02X ",skb->data[i]); + } + printk("\n"); + } + + } + +if_send_crit_exit: + if (err==0){ + dev_kfree_skb_any(skb); + } + + start_net_queue(dev); + clear_bit(SEND_CRIT, (void*)&card->wandev.critical); + + return err; +} + +/*============================================================================ + * Get ethernet-style interface statistics. + * Return a pointer to struct enet_statistics. + */ +static struct net_device_stats* if_stats (netdevice_t* dev) +{ + sdla_t *my_card; + sdlc_private_area_t* sdlc_priv_area; + + /* Shutdown bug fix. In del_if() we kill + * dev->priv pointer. This function, gets + * called after del_if(), thus check + * if pointer has been deleted */ + if ((sdlc_priv_area=dev->priv) == NULL) + return NULL; + + my_card = sdlc_priv_area->card; + return &my_card->wandev.stats; +} + +/****** Cisco HDLC Firmware Interface Functions *******************************/ + +/*============================================================================ + * Read firmware code version. + * Put code version as ASCII string in str. + */ +static int sdlc_read_version (sdla_t* card, char* str) +{ + wan_mbox_t* mb = &card->wan_mbox; + int len; + char err; + mb->wan_data_len = 0; + mb->wan_command = READ_CODE_VERSION; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + + if(err != COMMAND_OK) { + sdlc_error(card,err,mb); + + }else if (str) { /* is not null */ + len = mb->wan_data_len; + memcpy(str, mb->wan_data, len); + str[len] = '\0'; + } + return (err); +} + +/*----------------------------------------------------------------------------- + * Configure CHDLC firmware. + */ +static int sdlc_configure (sdla_t* card, void* data) +{ + int err; + wan_mbox_t *mb = &card->wan_mbox; + int data_length = sizeof(SDLC_CONFIGURATION_STRUCT); + int retry=10; + + do { + mb->wan_data_len = data_length; + memcpy(mb->wan_data, data, data_length); + mb->wan_command = SET_SDLC_CONFIGURATION; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + + if (err != COMMAND_OK) + sdlc_error (card, err, mb); + + if (err != 0x30){ + break; + } + + }while((err!=COMMAND_OK) && --retry); + + return err; +} + +/*----------------------------------------------------------------------------- + * Configure CHDLC firmware. + */ +static int sdlc_read_config (sdla_t* card) +{ + int err; + wan_mbox_t *mb = &card->wan_mbox; + + mb->wan_data_len = 0; + mb->wan_command = READ_SDLC_CONFIGURATION; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + + if (err != COMMAND_OK) sdlc_error (card, err, mb); + + return err; +} + + +/*============================================================================ + * Set interrupt mode -- HDLC Version. + */ + +static int sdlc_set_intr_mode (sdla_t* card, unsigned mode) +{ + wan_mbox_t* mb = &card->wan_mbox; + SDLC_INT_TRIGGERS_STRUCT* int_data = + (SDLC_INT_TRIGGERS_STRUCT *)mb->wan_data; + int err; + + int_data->CHDLC_interrupt_triggers = mode; + int_data->IRQ = card->wandev.irq; // ALEX_TODAY card->hw.irq; + int_data->interrupt_timer = 1; + int_data->misc_interrupt_bits = 0; + + mb->wan_data_len = sizeof(SDLC_INT_TRIGGERS_STRUCT); + mb->wan_command = SET_INTERRUPT_TRIGGERS; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != COMMAND_OK) + sdlc_error (card, err, mb); + return err; +} + + +/*============================================================================ + * Enable communications. + */ + +static int sdlc_comm_enable (sdla_t* card) +{ + int err; + wan_mbox_t* mb = &card->wan_mbox; + + mb->wan_data_len = 0; + mb->wan_command = ENABLE_COMMUNICATIONS; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != COMMAND_OK) + sdlc_error(card, err, mb); + else + card->u.sdlc.comm_enabled=1; + + return err; +} + +/*============================================================================ + * Disable communications and Drop the Modem lines (DCD and RTS). + */ +static int sdlc_comm_disable (sdla_t* card) +{ + int err; + wan_mbox_t* mb = &card->wan_mbox; + + mb->wan_data_len = 0; + mb->wan_command = DISABLE_COMMUNICATIONS; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != COMMAND_OK) + sdlc_error(card,err,mb); + + return err; +} + +/*============================================================================ + * Read communication error statistics. + */ +static int sdlc_read_comm_err_stats (sdla_t* card) +{ + int err; + wan_mbox_t* mb = &card->wan_mbox; + + mb->wan_data_len = 0; + mb->wan_command = READ_COMMS_ERR_STATISTICS; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != COMMAND_OK) + sdlc_error(card,err,mb); + return err; +} + + +/*============================================================================ + * Read CHDLC operational statistics. + */ +static int sdlc_read_op_stats (sdla_t* card) +{ + int err; + wan_mbox_t* mb = &card->wan_mbox; + + mb->wan_data_len = 0; + mb->wan_command = READ_OPERATIONAL_STATISTICS; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != COMMAND_OK) + sdlc_error(card,err,mb); + return err; +} + + +/*============================================================================ + * Update communications error and general packet statistics. + */ +static int update_comms_stats(sdla_t* card, sdlc_private_area_t* sdlc_priv_area) +{ + wan_mbox_t* mb = &card->wan_mbox; + COMMS_ERROR_STATS_STRUCT *err_stats; + SDLC_OPERATIONAL_STATS_STRUCT *op_stats; + + /* on the first timer interrupt, read the comms error statistics */ + if(sdlc_priv_area->update_comms_stats == 2) { + if(sdlc_read_comm_err_stats(card)) + return 1; + err_stats = (COMMS_ERROR_STATS_STRUCT *)mb->wan_data; + card->wandev.stats.rx_over_errors = + err_stats->Rx_overrun_err_cnt; + card->wandev.stats.rx_crc_errors = + err_stats->CRC_err_cnt; + card->wandev.stats.rx_frame_errors = + err_stats->Rx_abort_cnt; + card->wandev.stats.rx_fifo_errors = + err_stats->Rx_frm_lgth_err_cnt; + card->wandev.stats.rx_missed_errors = + card->wandev.stats.rx_fifo_errors; + card->wandev.stats.tx_aborted_errors = + err_stats->msd_Tx_und_int_cnt; + } + + /* on the second timer interrupt, read the operational statistics */ + else { + if(sdlc_read_op_stats(card)) + return 1; + op_stats = (SDLC_OPERATIONAL_STATS_STRUCT *)mb->wan_data; + //FIXME + card->wandev.stats.rx_length_errors = + (op_stats->no_short_frames_Rx + + op_stats->no_short_frames_Rx); + } + + return 0; +} +/*============================================================================ + * Send packet. + * Return: 0 - o.k. + * 1 - no transmit buffers available + */ +static int sdlc_list_stations_with_ifrms (sdla_t* card) +{ + wan_mbox_t *mb = &card->wan_mbox; + int retry=MAX_CMD_RETRY; + int err; + + do { + mb->wan_command=LIST_STATIONS_WITH_I_FRMS_AVAILABLE; + mb->wan_return_code=0; + mb->wan_data_len=0; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err){ + sdlc_error(card,err,mb); + } + }while (err && --retry); + + return err; +} + +static int sdlc_read (sdla_t* card,unsigned char station) +{ + wan_mbox_t *mb = &card->wan_mbox; + volatile int retry=MAX_CMD_RETRY; + volatile int err; + + do { + mb->wan_command=SDLC_READ; + mb->wan_return_code=0; + mb->wan_data_len=0; + mb->wan_sdlc_address=station; + err = card->hw_iface.cmd(card->hw, card->rxmb_off, mb); + if (err){ + sdlc_error(card,err,mb); + } + }while (err && --retry); + + return err; +} + +/*============================================================================ + * Send packet. + * Return: 0 - o.k. + * 1 - no transmit buffers available + */ +static int sdlc_send (sdla_t* card, void* data, unsigned len) +{ + wan_mbox_t *mb = &card->wan_mbox; + wan_api_t* wan_api; + + if (mb->wan_opp_flag){ + printk(KERN_INFO "%s: Critical in sdlc_send() opp flag set!", + card->devname); + return 1; + } + + wan_api = (wan_api_t*)data; + len -= sizeof(wan_api_hdr_t); + + mb->wan_command =SDLC_WRITE; + mb->wan_return_code =0; + mb->wan_data_len = len; + mb->wan_sdlc_address = wan_api->wan_api_sdlc_station; + mb->wan_sdlc_poll_interval = wan_api->wan_api_sdlc_poll_interval; + mb->wan_sdlc_pf = wan_api->wan_api_sdlc_pf; + mb->wan_sdlc_general_mb_byte = wan_api->wan_api_sdlc_general_mb_byte; + + memcpy(mb->wan_data,wan_api->data,len); + + return card->hw_iface.cmd(card->hw, card->mbox_off, mb); +} +/****** Firmware Error Handler **********************************************/ + +/*============================================================================ + * Firmware error handler. + * This routine is called whenever firmware command returns non-zero + * return code. + * + * Return zero if previous command has to be cancelled. + */ +static int sdlc_error (sdla_t *card, int err, wan_mbox_t *mb) +{ + unsigned cmd = mb->wan_command; + + switch (err) { + + case CMD_TIMEOUT: + printk(KERN_INFO "%s: command 0x%02X timed out!\n", + card->devname, cmd); + break; + + case BUSY_WITH_BAUD_CALIBRATION: + /* Do not print here, because we have to wait in + * this contiditon */ + break; + + case BAUD_CALIBRATION_FAILED: + printk(KERN_INFO "%s: Baud calibration failed!\n", + card->devname); + break; + + default: + printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n", + card->devname, cmd, err); + } + + return 0; +} + +/****** Interrupt Handlers **************************************************/ + +/*============================================================================ + * Cisco HDLC interrupt service routine. + */ +static void wp_sdlc_isr (sdla_t* card) +{ + netdevice_t* dev; + INTERRUPT_INFORMATION_STRUCT flags; + + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + card->in_isr = 1; + card->hw_iface.peek(card->hw, card->flags_off, &flags, sizeof(flags)); + + /* If we get an interrupt with no network device, stop the interrupts + * and issue an error */ + if ((!dev || !dev->priv) && flags.interrupt_type != COMMAND_COMPLETE_INTERRUPT_PENDING){ + goto isr_done; + } + + /* if critical due to peripheral operations + * ie. update() or getstats() then reset the interrupt and + * wait for the board to retrigger. + */ + if(test_bit(PERI_CRIT, (void*)&card->wandev.critical)) { + goto isr_done; + } + + + /* On a 508 Card, if critical due to if_send + * Major Error !!! + */ + if(card->type != SDLA_S514) { + if(test_bit(0, (void*)&card->wandev.critical)) { + printk(KERN_INFO "%s: Critical while in ISR: %lx\n", + card->devname, card->wandev.critical); + goto isr_done; + } + } + + + switch(flags.interrupt_type) { + + case RX_INTERRUPT_PENDING: /* 0x01: receive interrupt */ + rx_intr(card); + break; + + case TX_INTERRUPT_PENDING: /* 0x02: transmit interrupt */ + + /* Not used, because, tx interrupt + * is not supported by Gideon */ + tx_intr(card); + card->hw_iface.clear_bit(card->hw, card->intr_perm_off, INTERRUPT_ON_TX_FRAME); + break; + + case COMMAND_COMPLETE_INTERRUPT_PENDING:/* 0x04: cmd cplt */ + ++ card->timer_int_enabled; + break; + + case EXCEPTION_CONDITION_INTERRUPT_PENDING: /* 0x20 */ + process_sdlc_exception(card); + break; + + case TIMER_INTERRUPT_PENDING: + timer_intr(card); + break; + + default: + printk(KERN_INFO "%s: spurious interrupt 0x%02X!\n", + card->devname, + flags.interrupt_type); + break; + } + +isr_done: + card->hw_iface.poke_byte(card->hw, card->intr_type_off, 0x00); + card->in_isr = 0; +} + +static unsigned char station_list[500]; + +/*============================================================================ + * Receive interrupt handler. + */ +static void rx_intr (sdla_t* card) +{ + netdevice_t *dev; + sdlc_private_area_t *chan; + wan_mbox_t *mb = &card->wan_mbox; + wan_mbox_t *rxmb = &card->wan_rxmb; + struct sk_buff *skb; + unsigned len,station_cnt; + unsigned char *buf; + int i,udp_type; + + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + if (!dev){ + goto rx_exit; + } + +#if defined(LINUX_2_4)||defined(LINUX_2_6) + if (!netif_running(dev)){ + goto rx_exit; + } +#else + if (!dev->start){ + goto rx_exit; + } +#endif + + chan = dev->priv; + + + if (sdlc_list_stations_with_ifrms(card) != 0){ + goto rx_exit; + } + + station_cnt=mb->wan_data_len; + memcpy(&station_list,mb->wan_data,station_cnt); + + for (i=0; i < station_cnt; i++){ + int err; + + err = sdlc_read(card,station_list[i]); + + if (err != 0){ + DEBUG_EVENT("%s: Receive failed for station %i\n", + card->devname, mb->wan_data[i]); + continue; + } + + card->hw_iface.peek(card->hw, card->rxmb_off, rxmb, sizeof(wan_cmd_t)); + len=rxmb->wan_data_len; + if (len){ + card->hw_iface.peek(card->hw, + card->rxmb_off+offsetof(wan_mbox_t, wan_data), + rxmb->wan_data, len); + } + + if (len > card->wandev.mtu){ + printk(KERN_INFO "%s: Rx packet too big len %i > MTU %i\n", + card->devname,len,card->wandev.mtu); + continue; + } + + /* Allocate socket buffer */ + skb = dev_alloc_skb(len+sizeof(wan_api_hdr_t)+2); + if (skb == NULL){ + if (net_ratelimit()){ + printk(KERN_INFO "%s: no socket buffers available!\n", + card->devname); + } + ++card->wandev.stats.rx_dropped; + goto rx_exit; + } + + /* Align to 16 byte boundary */ + skb_reserve(skb,2); + + buf=skb_put(skb,len); + memcpy(buf,rxmb->wan_data,len); + + skb->protocol = htons(ETH_P_IP); + + card->wandev.stats.rx_packets++; + card->wandev.stats.rx_bytes += skb->len; + + udp_type = wan_udp_pkt_type(card,skb->data); + + if (chan->common.usedby == API){ + + wan_api_hdr_t *api_hdr; + skb_push(skb,sizeof(wan_api_hdr_t)); + api_hdr = (wan_api_hdr_t*)&skb->data[0]; + api_hdr->wan_apihdr_sdlc_station =mb->wan_sdlc_address; + api_hdr->wan_apihdr_sdlc_pf =mb->wan_sdlc_pf; + api_hdr->wan_apihdr_sdlc_poll_interval =mb->wan_sdlc_poll_interval; + api_hdr->wan_apihdr_sdlc_general_mb_byte=mb->wan_sdlc_general_mb_byte; + + skb->pkt_type = WAN_PACKET_DATA; + + if (chan->common.sk == NULL){ + ++card->wandev.stats.rx_dropped; + + card->wandev.stats.rx_packets --; + card->wandev.stats.rx_bytes -= skb->len; + + dev_kfree_skb_any(skb); + continue; + } + + if (wan_api_rx(chan,skb) != 0){ + ++card->wandev.stats.rx_dropped; + + card->wandev.stats.rx_packets --; + card->wandev.stats.rx_bytes -= skb->len; + + dev_kfree_skb_any(skb); + } + + }else if (chan->common.usedby == STACK) { + + wan_api_hdr_t *api_hdr; + skb_push(skb,sizeof(wan_api_hdr_t)); + api_hdr = (wan_api_hdr_t*)&skb->data[0]; + api_hdr->wan_apihdr_sdlc_station=mb->wan_data[i]; + + skb->pkt_type = WAN_PACKET_DATA; + + if (!test_bit(REG_CRIT,&card->wandev.critical) || + !chan->wp_sdlc_register.sdlc_stack_rx){ + + ++card->wandev.stats.rx_dropped; + + card->wandev.stats.rx_packets --; + card->wandev.stats.rx_bytes -= skb->len; + + dev_kfree_skb_any(skb); + continue; + } + + skb->dev = dev; + skb->mac.raw = skb->data; + + if (chan->wp_sdlc_register.sdlc_stack_rx(skb) != 0){ + ++card->wandev.stats.rx_dropped; + + card->wandev.stats.rx_packets --; + card->wandev.stats.rx_bytes -= skb->len; + + dev_kfree_skb_any(skb); + } + + }else{ + /* Pass it up the protocol stack */ + skb->dev = dev; + skb->mac.raw = skb->data; + netif_rx(skb); + } + } + +rx_exit: + return; +} + +static void tx_intr(sdla_t *card) +{ + netdevice_t *dev; + sdlc_private_area_t* sdlc_priv_area; + + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + if (dev == NULL){ + return; + } + + if ((sdlc_priv_area=dev->priv) == NULL){ + return; + } + + if (sdlc_priv_area->common.usedby == API){ + start_net_queue(dev); + wan_wakeup_api(sdlc_priv_area); + }else{ + wake_net_dev(dev); + } +} + +/*============================================================================ + * Timer interrupt handler. + * The timer interrupt is used for two purposes: + * 1) Processing udp calls from 'cpipemon'. + * 2) Reading board-level statistics for updating the proc file system. + */ +void timer_intr(sdla_t *card) +{ + netdevice_t* dev; + sdlc_private_area_t* sdlc_priv_area = NULL; + + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + if (!dev) return; + sdlc_priv_area = dev->priv; + + /* read the communications statistics if required */ + if(sdlc_priv_area->timer_int_enabled & TMR_INT_ENABLED_UPDATE){ + update_comms_stats(card, sdlc_priv_area); + if (IS_TE1_CARD(card)) { + /* TE1 Update T1/E1 alarms */ + card->wandev.fe_iface.read_alarm(&card->fe, 0); + /* TE1 Update T1/E1 perfomance counters */ + card->wandev.fe_iface.read_pmon(&card->fe, 0); + + }else if (IS_56K_CARD(card)) { + /* 56K Update CSU/DSU alarms */ + card->wandev.fe_iface.read_alarm(&card->fe, 1); + } + + if(!(-- sdlc_priv_area->update_comms_stats)) { + sdlc_priv_area->timer_int_enabled &= + ~TMR_INT_ENABLED_UPDATE; + } + } + + /* only disable the timer interrupt if there are no udp or statistic */ + /* updates pending */ + if(!sdlc_priv_area->timer_int_enabled) { + card->hw_iface.clear_bit(card->hw, card->intr_perm_off, INTERRUPT_ON_TIMER); + } +} + +/*------------------------------------------------------------------------------ + Miscellaneous Functions + - set_sdlc_config() used to set configuration options on the board +------------------------------------------------------------------------------*/ + +static int set_sdlc_config(sdla_t* card) +{ + + SDLC_CONFIGURATION_STRUCT cfg; + + memset(&cfg, 0, sizeof(SDLC_CONFIGURATION_STRUCT)); + + /* Generate an interrupt on an exception condition, + * do not give it to me on a command */ + cfg.general_operational_config_bits |= APP_REQUESTS_PASSING_EXCEPT_COND; + + if(card->wandev.clocking){ + cfg.baud_rate = card->wandev.bps; + } + + /* the station configuration (primary or secondary) */ + cfg.station_configuration=card->wandev.sdlc_cfg.station_configuration; + + /* the maximum permitted Information field length supported */ + if (card->wandev.sdlc_cfg.max_I_field_length){ + cfg.max_I_field_length = card->wandev.mtu = card->wandev.sdlc_cfg.max_I_field_length; + }else{ + cfg.max_I_field_length = card->wandev.mtu; + } + + cfg.general_operational_config_bits=card->wandev.sdlc_cfg.general_operational_config_bits; + + if (card->wandev.interface != WANOPT_RS232){ + cfg.general_operational_config_bits |= INTERFACE_LEVEL_V35; + } + + + /* miscellaneous protocol configuration bits */ + cfg.protocol_config_bits=card->wandev.sdlc_cfg.protocol_config_bits; + + /* bits to specify which exception conditions are reported to the application */ + cfg.exception_condition_reporting_config=card->wandev.sdlc_cfg.exception_condition_reporting_config; + + /* modem operation configuration bits */ + cfg.modem_config_bits=card->wandev.sdlc_cfg.modem_config_bits; + + /* the statistics format byte */ + cfg.statistics_format=card->wandev.sdlc_cfg.statistics_format; + + /* the slow poll interval for a primary station (milliseconds) */ + cfg.pri_station_slow_poll_interval=card->wandev.sdlc_cfg.pri_station_slow_poll_interval; + + /* the permitted secondary station_response timeout (milliseconds) */ + cfg.permitted_sec_station_response_TO=card->wandev.sdlc_cfg.permitted_sec_station_response_TO; + + /* the number of consecutive secondary timeouts while */ + /* in the NRM before a SNRM is issued */ + cfg.no_consec_sec_TOs_in_NRM_before_SNRM_issued=card->wandev.sdlc_cfg.no_consec_sec_TOs_in_NRM_before_SNRM_issued; + + /* the maximum Information field length permitted in an XID */ + /* frame sent by a primary station */ + cfg.max_lgth_I_fld_pri_XID_frame=card->wandev.sdlc_cfg.max_lgth_I_fld_pri_XID_frame; + + /* the additional bit delay before transmitting the opening */ + /* character in a frame */ + cfg.opening_flag_bit_delay_count=card->wandev.sdlc_cfg.opening_flag_bit_delay_count; + + /* the additional bit delay before dropping RTS */ + cfg.RTS_bit_delay_count=card->wandev.sdlc_cfg.RTS_bit_delay_count; + + /* the permitted CTS timeout for switched CTS/RTS configurations */ + /* (in 1000ths/second) */ + cfg.CTS_timeout_1000ths_sec=card->wandev.sdlc_cfg.CTS_timeout_1000ths_sec; + + /* the adapter type and the CPU speed */ + cfg.SDLA_configuration=card->wandev.sdlc_cfg.SDLA_configuration; + + DEBUG_EVENT("\n"); + + DEBUG_EVENT("%s: SDLC Config:\n",card->devname); + + DEBUG_EVENT("%s: Station Cfg : 0x%X\n", + card->devname,cfg.station_configuration); + + DEBUG_EVENT("%s: Baud Rate : 0x%lX\n", + card->devname,cfg.baud_rate); + + DEBUG_EVENT("%s: Max I Frame Len : %i\n", + card->devname,cfg.max_I_field_length); + + DEBUG_EVENT("%s: Misc Oper. Cfg : 0x%X\n", + card->devname,cfg.general_operational_config_bits); + + DEBUG_EVENT("%s: Misc Protocol Cfg : 0x%X\n", + card->devname,cfg.protocol_config_bits); + + DEBUG_EVENT("%s: Exception Reporting : 0x%X\n", + card->devname,cfg.exception_condition_reporting_config); + + DEBUG_EVENT("%s: Modem Op Cfg : 0x%X\n", + card->devname,cfg.modem_config_bits); + + DEBUG_EVENT("%s: Statistics Format : 0x%X\n", + card->devname,cfg.statistics_format); + + DEBUG_EVENT("%s: Slow poll Inter Pri : %i\n", + card->devname,cfg.pri_station_slow_poll_interval); + + DEBUG_EVENT("%s: Sec Station Resp : %i\n", + card->devname,cfg.permitted_sec_station_response_TO); + + DEBUG_EVENT("%s: No Tout NRM b4 SNRM : %i\n", + card->devname,cfg.no_consec_sec_TOs_in_NRM_before_SNRM_issued); + + DEBUG_EVENT("%s: Max I Frm in XID Pri : %i\n", + card->devname,cfg.max_lgth_I_fld_pri_XID_frame); + + DEBUG_EVENT("%s: Bit delay b4 Tx Ch : %i\n", + card->devname,cfg.opening_flag_bit_delay_count); + + DEBUG_EVENT("%s: Bit delay b4 drop RTS : %i\n", + card->devname,cfg.RTS_bit_delay_count); + + DEBUG_EVENT("%s: CTS Timeout Sw CTS/RTS: %i\n", + card->devname,cfg.CTS_timeout_1000ths_sec); + + DEBUG_EVENT("%s: Adapter Type CPU Speed: 0x%X\n", + card->devname,cfg.SDLA_configuration); + + DEBUG_EVENT("\n"); + + return sdlc_configure(card, &cfg); +} + + +static void sdlc_modem_change(sdla_t *card, wan_mbox_t *mb) +{ + +#if 0 + if (IS_56K_CARD(card)) { + INTERRUPT_INFORMATION_STRUCT *flags = card->u.sdlc.flags; + FRONT_END_STATUS_STRUCT *FE_status = + (FRONT_END_STATUS_STRUCT *)&flags->FT1_info_struct.parallel_port_A_input; + card->wandev.RR8_reg_56k = + FE_status->FE_U.stat_56k.RR8_56k; + card->wandev.RRA_reg_56k = + FE_status->FE_U.stat_56k.RRA_56k; + card->wandev.RRC_reg_56k = + FE_status->FE_U.stat_56k.RRC_56k; + card->wandev.fe_iface.read_alarm(&card->fe, 0); + return; + } + + if (IS_TE1_CARD(card)) { + /* TE_INTR */ + card->wandev.fe_iface.isr(&card->fe); + return; + } +#endif + + printk(KERN_INFO "%s: Modem status change\n", + card->devname); + + switch(mb->wan_data[0] & (DCD_HIGH | CTS_HIGH)) { + case (DCD_HIGH): + printk(KERN_INFO "%s: DCD high, CTS low\n",card->devname); + break; + case (CTS_HIGH): + printk(KERN_INFO "%s: DCD low, CTS high\n",card->devname); + break; + case ((DCD_HIGH | CTS_HIGH)): + printk(KERN_INFO "%s: DCD high, CTS high\n",card->devname); + break; + default: + printk(KERN_INFO "%s: DCD low, CTS low\n",card->devname); + break; + } + + return; +} + +static void sdlc_state_change(sdla_t *card, wan_mbox_t *mb) +{ + int i; + netdevice_t *dev; + sdlc_private_area_t *sdlc_chan; + SDLC_STATE_STRUCT *sdlc_state=(SDLC_STATE_STRUCT *)mb->wan_data; + + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + if (!dev) + return; + + if ((sdlc_chan=dev->priv) == NULL) + return; + + for (i=0;iwan_data_len;i+=sizeof(SDLC_STATE_STRUCT)){ + printk(KERN_INFO "%s: Station %X State = %s\n", + card->devname, + sdlc_state->station, + sdlc_state->state?"Connected (NRM)":"Disconnected (NDM)"); + sdlc_state++; + } + + if (sdlc_chan->common.usedby != WANPIPE){ + send_oob_msg(card,mb); + } + return; +} + +/*============================================================================ + * Process chdlc exception condition + */ +static int process_sdlc_exception(sdla_t *card) +{ + wan_mbox_t* mb = &card->wan_mbox; + int err; + + mb->wan_data_len = 0; + mb->wan_command = READ_EXCEPTION_CONDITION; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if(err != CMD_TIMEOUT) { + + switch (err) { + + case EXCEP_COND_STATE_CHANGE: + /* the SDLC station changed state */ + sdlc_state_change(card,mb); + break; + + case EXCEP_COND_TIMEOUT_NRM: + /* a timeout occurred while the stations was in the NRM */ + + break; + + case EXCEP_COND_RD_FRM_RX_WHILE_IN_NRM: + /* a RD was received while the link was in the NRM */ + + break; + case EXCEP_COND_DM_FRM_RX_WHILE_IN_NRM: + /* a DM was received while the link was in the NRM */ + + break; + + case EXCEP_COND_SNRM_FRM_RX_WHILE_IN_NRM: + /* a SNRM was received while the link was in the NRM */ + + break; + + case EXCEP_COND_RIM_FRM_RX: + /* a RIM was received */ + + break; + + case EXCEP_COND_XID_FRM_RX: + /* an XID frame was received */ + + break; + + case EXCEP_COND_TEST_FRM_RX: + /* a TEST frame was received */ + + break; + + case EXCEP_COND_FRMR_FRM_RX_TX: + /* a FRMR condition occurred */ + + break; + + case EXCEP_COND_CHANGE_IN_MODEM_STATUS: + /* a modem status change occurred */ + sdlc_modem_change(card,mb); + break; + + default: + printk(KERN_INFO "%s: Exception Condition %x!\n", + card->devname,err); + break; + } + + } + return 0; +} + +/*============================================================================= + * Process UDP management packet. + */ + +static int process_udp_mgmt_pkt(sdla_t* card, netdevice_t* dev, + sdlc_private_area_t* sdlc_priv_area,int local_dev) +{ + unsigned char *buf; + unsigned int len; + struct sk_buff *new_skb; + int udp_mgmt_req_valid = 1; + wan_mbox_t *mb = &card->wan_mbox; + wan_udp_pkt_t *wan_udp_pkt; + struct timeval tv; + int err; + + wan_udp_pkt = (wan_udp_pkt_t *) sdlc_priv_area->udp_pkt_data; + + + if(sdlc_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK) { + + switch(wan_udp_pkt->wan_udp_command) { + case READ_MODEM_STATUS: + case READ_STATION_STATUS: + case CPIPE_ROUTER_UP_TIME: + case READ_COMMS_ERR_STATISTICS: + case READ_OPERATIONAL_STATISTICS: + + /* These two commands are executed for + * each request */ + case READ_SDLC_CONFIGURATION: + case READ_CODE_VERSION: + udp_mgmt_req_valid = 1; + break; + default: + udp_mgmt_req_valid = 0; + break; + } + } + + if(!udp_mgmt_req_valid) { + + /* set length to 0 */ + wan_udp_pkt->wan_udp_data_len = 0; + + /* set return code */ + wan_udp_pkt->wan_udp_return_code = 0xCD; + + if (net_ratelimit()){ + printk(KERN_INFO + "%s: Warning, Illegal UDP command attempted from network: %x\n", + card->devname,wan_udp_pkt->wan_udp_command); + } + + } else { + switch(wan_udp_pkt->wan_udp_command) { + + + case CPIPE_ROUTER_UP_TIME: + do_gettimeofday( &tv ); + sdlc_priv_area->router_up_time = tv.tv_sec - + sdlc_priv_area->router_start_time; + *(unsigned long *)&wan_udp_pkt->wan_udp_data = + sdlc_priv_area->router_up_time; + mb->wan_data_len = sizeof(unsigned long); + wan_udp_pkt->wan_udp_return_code = COMMAND_OK; + break; + + default: + /* it's a board command */ + mb->wan_command = wan_udp_pkt->wan_udp_command; + mb->wan_data_len = wan_udp_pkt->wan_udp_data_len; + if (mb->wan_data_len) { + memcpy(&mb->wan_data, (unsigned char *) wan_udp_pkt-> + wan_udp_data, mb->wan_data_len); + } + /* run the command on the board */ + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != COMMAND_OK) { + break; + } + + /* copy the result back to our buffer */ + memcpy(&wan_udp_pkt->wan_udp_hdr.wan_cmd, mb, sizeof(wan_cmd_t)); + + if (mb->wan_data_len) { + memcpy(&wan_udp_pkt->wan_udp_data, &mb->wan_data, + mb->wan_data_len); + } + + } /* end of switch */ + } /* end of else */ + + /* Fill UDP TTL */ + wan_udp_pkt->wan_ip_ttl = card->wandev.ttl; + + if (local_dev){ + + } + + len = wan_reply_udp(card, sdlc_priv_area->udp_pkt_data, mb->wan_data_len); + + if(sdlc_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK) { + if(!sdlc_send(card, sdlc_priv_area->udp_pkt_data, len)) { + ++ card->wandev.stats.tx_packets; + card->wandev.stats.tx_bytes += len; + } + } else { + + /* Pass it up the stack + Allocate socket buffer */ + if ((new_skb = dev_alloc_skb(len)) != NULL) { + /* copy data into new_skb */ + + buf = skb_put(new_skb, len); + memcpy(buf, sdlc_priv_area->udp_pkt_data, len); + + /* Decapsulate pkt and pass it up the protocol stack */ + new_skb->protocol = htons(ETH_P_IP); + new_skb->dev = dev; + new_skb->mac.raw = new_skb->data; + + netif_rx(new_skb); + } else { + + printk(KERN_INFO "%s: no socket buffers available!\n", + card->devname); + } + } + + sdlc_priv_area->udp_pkt_lgth = 0; + + return 0; +} + +/*============================================================================= + * Perform Interrupt Test by running READ_CHDLC_CODE_VERSION command MAX_INTR + * _TEST_COUNTER times. + */ +static int intr_test( sdla_t* card) +{ + wan_mbox_t* mb = &card->wan_mbox; + int err,i; + + card->timer_int_enabled = 0; + + /* The critical flag is unset because during intialization (if_open) + * we want the interrupts to be enabled so that when the wpc_isr is + * called it does not exit due to critical flag set. + */ + + err = sdlc_set_intr_mode(card, INTERRUPT_ON_COMMAND_COMPLETE); + + if (err == CMD_OK) { + for (i = 0; i < MAX_INTR_TEST_COUNTER; i ++) { + mb->wan_data_len = 0; + mb->wan_command = READ_CODE_VERSION; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + } + } + else { + return err; + } + + err = sdlc_set_intr_mode(card, 0); + + if (err != CMD_OK) + return err; + + return 0; +} + +/*============================================================================ + * Set PORT state. + */ +static void port_set_state (sdla_t *card, int state) +{ + netdevice_t *dev; + sdlc_private_area_t *sdlc_priv_area; + + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + if (!dev || !dev->priv){ + return; + } + + sdlc_priv_area=dev->priv; + + if (card->u.sdlc.state != state) + { + switch (state) + { + case WAN_CONNECTED: + printk (KERN_INFO "%s: SDLC comms enabled!\n", + card->devname); + break; + + case WAN_CONNECTING: + printk (KERN_INFO "%s: SDLC comms disabled!\n", + card->devname); + break; + + case WAN_DISCONNECTED: + printk (KERN_INFO "%s: SDLC comms disabled!\n", + card->devname); + break; + } + + card->wandev.state = card->u.sdlc.state = state; + sdlc_priv_area->common.state = state; + wan_update_api_state(sdlc_priv_area); + } +} + +/*=========================================================================== + * config_sdlc + * + * Configure the chdlc protocol and enable communications. + * + * The if_open() function binds this function to the poll routine. + * Therefore, this function will run every time the chdlc interface + * is brought up. We cannot run this function from the if_open + * because if_open does not have access to the remote IP address. + * + * If the communications are not enabled, proceed to configure + * the card and enable communications. + * + * If the communications are enabled, it means that the interface + * was shutdown by ether the user or driver. In this case, we + * have to check that the IP addresses have not changed. If + * the IP addresses have changed, we have to reconfigure the firmware + * and update the changed IP addresses. Otherwise, just exit. + * + */ + +static int config_sdlc (sdla_t *card) +{ + wan_mbox_t *mb=&card->wan_mbox; + unsigned long timeout; + int err=0; + + /* Set interrupt mode and mask */ + if (sdlc_set_intr_mode(card, INTERRUPT_ON_RX_FRAME | + INTERRUPT_ON_EXCEPTION_CONDITION | + INTERRUPT_ON_TIMER)){ + printk (KERN_INFO "%s: Failed to set interrupt triggers!\n", + card->devname); + return -EINVAL; + } + + + /* Mask the Transmit and Timer interrupt */ + card->hw_iface.clear_bit(card->hw, card->intr_perm_off, (INTERRUPT_ON_TIMER)); + + timeout=jiffies; + while ((jiffies-timeout) < 2*HZ){ + err = sdlc_comm_enable(card); + + if (err == BUSY_WITH_BAUD_CALIBRATION){ + udelay(100); + schedule(); + continue; + }else{ + break; + } + } + + if (err !=0){ + printk(KERN_INFO "%s: Failed to enable sdlc communications!\n", + card->devname); + card->hw_iface.poke_byte(card->hw, card->intr_perm_off, 0x00); + card->u.sdlc.comm_enabled=0; + sdlc_set_intr_mode(card,0); + return -EINVAL; + } + + err = sdlc_read_config(card); + if (err==0){ + SDLC_CONFIGURATION_STRUCT *sdla_cfg = + (SDLC_CONFIGURATION_STRUCT *)mb->wan_data; + printk(KERN_INFO "%s: Baud rate calibrated at %li bps\n", + card->devname,sdla_cfg->baud_rate); + }else{ + printk(KERN_INFO "%s: Failed to read configuration!\n", + card->devname); + card->hw_iface.poke_byte(card->hw, card->intr_perm_off, 0x00); + sdlc_set_intr_mode(card,0); + sdlc_comm_disable(card); + return -EINVAL; + } + + return 0; +} + +/* + * ****************************************************************** + * Proc FS function + */ +#define PROC_CFG_FRM "%-15s| %-12s|\n" +#define PROC_STAT_FRM "%-15s| %-12s| %-14s|\n" +static char chdlc_config_hdr[] = + "Interface name | Device name |\n"; +static char chdlc_status_hdr[] = + "Interface name | Device name | Status |\n"; + +static int chdlc_get_config_info(void* priv, struct seq_file* m, int* stop_cnt) +{ + sdlc_private_area_t* sdlc_priv_area = priv; + sdla_t* card = NULL; + + if (sdlc_priv_area == NULL) + return m->count; + card = sdlc_priv_area->card; + + if ((m->from == 0 && m->count == 0) || (m->from && m->from == *stop_cnt)){ + PROC_ADD_LINE(m, + "%s", chdlc_config_hdr); + } + + PROC_ADD_LINE(m, + PROC_CFG_FRM, card->u.sdlc.if_name, card->devname); + return m->count; +} + +static int chdlc_get_status_info(void* priv, struct seq_file* m, int* stop_cnt) +{ + sdlc_private_area_t* sdlc_priv_area = priv; + sdla_t* card = NULL; + + if (sdlc_priv_area == NULL) + return m->count; + card = sdlc_priv_area->card; + + if ((m->from == 0 && m->count == 0) || (m->from && m->from == *stop_cnt)){ + PROC_ADD_LINE(m, + "%s", chdlc_status_hdr); + } + + PROC_ADD_LINE(m, + PROC_STAT_FRM, + card->u.sdlc.if_name, card->devname, STATE_DECODE(sdlc_priv_area->common.state)); + return m->count; +} + +#define PROC_DEV_FR_S_FRM "%-20s| %-14s|\n" +#define PROC_DEV_FR_D_FRM "%-20s| %-14d|\n" +#define PROC_DEV_SEPARATE "=====================================\n" + + +static int chdlc_set_dev_config(struct file *file, + const char *buffer, + unsigned long count, + void *data) +{ + int cnt = 0; + wan_device_t* wandev = (void*)data; + sdla_t* card = NULL; + + if (wandev == NULL) + return cnt; + + card = (sdla_t*)wandev->private; + + printk(KERN_INFO "%s: New device config (%s)\n", + wandev->name, buffer); + /* Parse string */ + + return count; +} + + +#define PROC_IF_FR_S_FRM "%-30s\t%-14s\n" +#define PROC_IF_FR_D_FRM "%-30s\t%-14d\n" +#define PROC_IF_FR_L_FRM "%-30s\t%-14ld\n" +#define PROC_IF_SEPARATE "====================================================\n" + +static int chdlc_set_if_info(struct file *file, + const char *buffer, + unsigned long count, + void *data) +{ + netdevice_t* dev = (void*)data; + sdlc_private_area_t* sdlc_priv_area = NULL; + sdla_t* card = NULL; + + if (dev == NULL || dev->priv == NULL) + return count; + sdlc_priv_area = (sdlc_private_area_t*)dev->priv; + if (sdlc_priv_area->card == NULL) + return count; + card = sdlc_priv_area->card; + + printk(KERN_INFO "%s: New interface config (%s)\n", + card->u.sdlc.if_name, buffer); + /* Parse string */ + + return count; +} + +int wanpipe_sdlc_register(netdevice_t *dev, void *reg_data) +{ + netdevice_t *dev1; + wp_sdlc_reg_t *wp_sdlc_reg = (wp_sdlc_reg_t *)reg_data; + sdlc_private_area_t *chan; + sdla_t *card=NULL; + + if (!dev || !wp_sdlc_reg){ + return -ENODEV; + } + + if (dev->type != ARPHRD_SDLC){ + printk(KERN_INFO "%s: Device %s type not SDLC! type=%i\n", + card->devname,dev->name,dev->type); + return -EINVAL; + } + + if ((chan=dev->priv) == NULL){ + return -ENODEV; + } + + if ((card=chan->card) == NULL){ + return -ENODEV; + } + + dev1 = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + if (dev != dev1){ + return -EINVAL; + } + + if (chan->common.usedby != STACK){ + printk(KERN_INFO "%s: Device %s doesn't support registration!\n", + card->devname,dev->name); + return -EINVAL; + } + + if (test_bit(REG_CRIT,&card->wandev.critical)){ + printk(KERN_INFO "%s: Device %s already registered!\n", + card->devname,dev->name); + return -EBUSY; + } + + memcpy(&chan->wp_sdlc_register,wp_sdlc_reg,sizeof(wp_sdlc_reg_t)); + set_bit(REG_CRIT,&card->wandev.critical); + + printk(KERN_INFO "%s: Registering sdlc device %s \n", + card->devname,dev->name); + + return 0; +} + +int wanpipe_sdlc_unregister(netdevice_t *dev) +{ + netdevice_t *dev1; + sdlc_private_area_t *chan; + sdla_t *card; + + if (!dev){ + return -ENODEV; + } + + if ((chan=dev->priv) == NULL){ + return -ENODEV; + } + + if ((card=chan->card) == NULL){ + return -ENODEV; + } + + dev1 = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + if (dev != dev1){ + return -EINVAL; + } + + if (chan->common.usedby != STACK){ + printk(KERN_INFO "%s: Device %s doesn't support un-registration!\n", + card->devname,dev->name); + return -EINVAL; + } + + if (test_bit(REG_CRIT,&card->wandev.critical)){ + clear_bit(REG_CRIT,&card->wandev.critical); + + printk(KERN_INFO "%s: Unregistering sdlc device %s \n", + card->devname,dev->name); + } + + return 0; +} + +void send_oob_msg(sdla_t *card, wan_mbox_t *mb) +{ + struct sk_buff *skb; + netdevice_t *dev; + sdlc_private_area_t *chan; + wan_api_t *wan_api; + + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + if (!dev || !wan_netif_priv(dev)) + return; + chan = wan_netif_priv(dev); + if (chan->common.usedby == WANPIPE){ + return; + } + + skb=dev_alloc_skb(sizeof(wan_api_hdr_t)+mb->wan_data_len+10); + if (!skb){ + printk(KERN_INFO "%s: OOB msg failed: faild to allocate skb!\n", + card->devname); + return; + } + + wan_api=(wan_api_t *)skb_put(skb,sizeof(wan_api_hdr_t)+mb->wan_data_len); + wan_api->wan_api_pktType = mb->wan_command; + wan_api->wan_api_length=mb->wan_data_len; + wan_api->wan_api_sdlc_station = 0; + + memcpy(wan_api->data,mb->wan_data,mb->wan_data_len); + + skb->dev=dev; + skb->pkt_type = WAN_PACKET_CMD; + + if (chan->common.usedby == API){ + + if (chan->common.sk == NULL){ + ++card->wandev.stats.rx_dropped; + dev_kfree_skb_any(skb); + } + + if (wan_api_rx(chan,skb) != 0){ + ++card->wandev.stats.rx_dropped; + dev_kfree_skb_any(skb); + } + + }else if (chan->common.usedby == STACK) { + + if (!test_bit(REG_CRIT,&card->wandev.critical) || + !chan->wp_sdlc_register.sdlc_stack_rx){ + + ++card->wandev.stats.rx_dropped; + dev_kfree_skb_any(skb); + } + + skb->dev = dev; + skb->mac.raw = skb->data; + + if (chan->wp_sdlc_register.sdlc_stack_rx(skb) != 0){ + ++card->wandev.stats.rx_dropped; + dev_kfree_skb_any(skb); + } + } +} + +/****** End ****************************************************************/ diff -Nur linux.org/drivers/net/wan/sdla_tdmv.c linux-2.6.17/drivers/net/wan/sdla_tdmv.c --- linux.org/drivers/net/wan/sdla_tdmv.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/drivers/net/wan/sdla_tdmv.c 2006-08-30 10:07:16.000000000 +0000 @@ -0,0 +1,2260 @@ +/*************************************************************************** + * sdla_tdmv.c WANPIPE(tm) Multiprotocol WAN Link Driver. + * TDM voice board configuration. + * + * Author: Alex Feldman + * Nenad Corbic + * David Rokvargh + * + * Copyright: (c) 1995-2005 Sangoma Technologies Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * ============================================================================ + * Jul 22, 2001 Nenad Corbic Initial version. + * Oct 01, 2001 Gideon Hack Modifications for interrupt usage. + * Aug 9, 2005 David Rokhvarg Added Echo Detection and Control (EDAC). + ****************************************************************************** + */ +/* + ****************************************************************************** + INCLUDE FILES + ****************************************************************************** +*/ + +#if defined(__FreeBSD__) || defined(__OpenBSD__) +# include +# include +# include +# include +# include +# include +# include /* WANPIPE TDM Voice definitions */ +# include +#elif (defined __WINDOWS__) +# include +#else + +#if 0 +# define CONFIG_ZAPATA_BRI_DCHANS +#endif + +# include +# include +# include +# include +# include /* WANPIPE TDM Voice definitions */ +#endif + +/* + ****************************************************************************** + DEFINES AND MACROS + ****************************************************************************** +*/ +#define DEBUG_ECHO if(0) DEBUG_EVENT + +#define WP_MAX_CARDS 32 + +#define FIXME_MSG(func) DEBUG_EVENT("(%s): FIXME: line %d\n", func, __LINE__) +#define DBG_FUNC_START(func) DEBUG_EVENT("(DEBUG)(TDM Voice): %s - Start\n", func) +#define DBG_FUNC_END(func) DEBUG_EVENT("(DEBUG)(TDM Voice): %s - End\n", func) + +/* flags bits */ +#define WP_TDMV_REGISTER 1 /*0x01*/ +#define WP_TDMV_RUNNING 2 /*0x02*/ +#define WP_TDMV_UP 3 /*0x04*/ +#define WP_TDMV_SIG_ENABLE 4 /*0x08*/ +#define WP_TDMV_SIG_POLL 5 /*0x10*/ +#define WP_TDMV_RBS_READY 6 /*0x20*/ +#define WP_TDMV_RBS_BUSY 7 /*0x40*/ +#define WP_TDMV_RBS_UPDATE 8 /*0x80*/ + +#define IS_TDMV_RUNNING(wp) wan_test_bit(WP_TDMV_RUNNING, &(wp)->flags) +#define IS_TDMV_UP(wp) wan_test_bit(WP_TDMV_UP, &(wp)->flags) +#define IS_TDMV_SIG_POLL(wp) wan_test_bit(WP_TDMV_SIG_POLL, &(wp)->flags) +#define IS_TDMV_SIG_ENABLE(wp) wan_test_bit(WP_TDMV_SIG_ENABLE, &(wp)->flags) +#define IS_TDMV_UP_RUNNING(wp) (IS_TDMV_UP(wp) && IS_TDMV_RUNNING(wp)) +#define IS_TDMV_SIG(wp) (IS_TDMV_SIG_POLL(wp) && IS_TDMV_SIG_ENABLE(wp)) + +#define WP_TDMV_ENABLE 0x01 +#define WP_TDMV_DISABLE 0x02 + +#if defined(__FreeBSD__) +extern short *__zt_mulaw; +#endif + + +#if 0 +static unsigned char wp_tdmv_ulaw[] = { + 0, 0, 0, 0, 0, 1, 1, 1, + 1, 2, 2, 2, 2, 3, 3, 3, + 3, 4, 4, 4, 4, 5, 5, 5, + 5, 6, 6, 6, 6, 7, 7, 7, + 7, 8, 8, 8, 8, 9, 9, 9, + 9, 10, 10, 10, 10, 11, 11, 11, + 11, 12, 12, 12, 12, 13, 13, 13, + 13, 14, 14, 14, 14, 15, 15, 15, + 15, 16, 16, 17, 17, 18, 18, 19, + 19, 20, 20, 21, 21, 22, 22, 23, + 23, 24, 24, 25, 25, 26, 26, 27, + 27, 28, 28, 29, 29, 30, 30, 31, + 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, + 47, 49, 51, 53, 55, 57, 59, 61, + 63, 66, 70, 74, 78, 84, 92, 104, + 254, 231, 219, 211, 205, 201, 197, 193, + 190, 188, 186, 184, 182, 180, 178, 176, + 175, 174, 173, 172, 171, 170, 169, 168, + 167, 166, 165, 164, 163, 162, 161, 160, + 159, 159, 158, 158, 157, 157, 156, 156, + 155, 155, 154, 154, 153, 153, 152, 152, + 151, 151, 150, 150, 149, 149, 148, 148, + 147, 147, 146, 146, 145, 145, 144, 144, + 143, 143, 143, 143, 142, 142, 142, 142, + 141, 141, 141, 141, 140, 140, 140, 140, + 139, 139, 139, 139, 138, 138, 138, 138, + 137, 137, 137, 137, 136, 136, 136, 136, + 135, 135, 135, 135, 134, 134, 134, 134, + 133, 133, 133, 133, 132, 132, 132, 132, + 131, 131, 131, 131, 130, 130, 130, 130, + 129, 129, 129, 129, 128, 128, 128, 128, +}; +#endif + +/* + ****************************************************************************** + STRUCTURES AND TYPEDEFS + ****************************************************************************** +*/ +typedef struct wp_tdmv_pvt_area +{ + sdla_t* card; + char* devname; + wan_spinlock_t lock; + wan_spinlock_t tx_rx_lock; + int ise1; + int num; + int spanno; + int flags; + int lbo; + int lcode; + int frame; + int usecount; + int sync; + int blinktimer; + int alarmtimer; + int loopupcnt; + int loopdowncnt; +#ifdef FANCY_ALARM + int alarmpos; +#endif + /* T1 signalling */ + struct zt_span span; /* Span */ + struct zt_chan chans[31]; /* Channels */ + unsigned char ec_chunk1[31][ZT_CHUNKSIZE]; + unsigned char ec_chunk2[31][ZT_CHUNKSIZE]; + unsigned long config_tsmap; + unsigned long timeslot_map; + int max_timeslots; /* T1: 24, E1: 31 */ + int timeslots; /* configured timeslots */ + unsigned long sig_timeslot_map; + int sig_timeslots; + unsigned long rbs_tx_status; + unsigned long rbs_tx1_status; + unsigned char rbs_tx[31]; + unsigned char rbs_tx1[31]; + unsigned char rbs_rx[31]; + unsigned long rbs_rx_pending; + int intcount; + int rbscount; + unsigned int brt_ctrl; + unsigned char echo_off; + unsigned long echo_off_map; + unsigned int max_rxtx_len; + + unsigned int channelized; /* WAN_TRUE or WAN_FALSE */ + unsigned char *tx_unchan; /* tx data pointer for unchannelized mode */ + + /* AHDLC: Hardware HDLC arguments */ + unsigned int dchan; + netdevice_t *dchan_dev; + +} wp_tdmv_softc_t; + + + +/* +******************************************************************************* +** GLOBAL VARIABLES +******************************************************************************* +*/ +static int wp_card_no = 0; +WAN_LIST_HEAD(, wan_tdmv_) wan_tdmv_head = + WAN_LIST_HEAD_INITIALIZER(&wan_tdmv_head); +/* +******************************************************************************* +** FUNCTION PROTOTYPES +******************************************************************************* +*/ + +static int wp_tdmv_check_mtu(void* pcard, unsigned long timeslot_map, int *mtu); +static int wp_tdmv_create(void* pcard, wan_xilinx_conf_t *conf); +static int wp_tdmv_remove(void* pcard); +static int wp_tdmv_reg(void* pcard, wanif_conf_t *conf, netdevice_t *dev); +static int wp_tdmv_unreg(void* pcard, unsigned long ts_map); +static int wp_tdmv_software_init(wan_tdmv_t *wan_tdmv); +static int wp_tdmv_startup(struct zt_span *span); +static int wp_tdmv_shutdown(struct zt_span *span); +static int wp_tdmv_maint(struct zt_span *span, int cmd); +static int wp_tdmv_chanconfig(struct zt_chan *chan, int sigtype); +static int wp_tdmv_spanconfig(struct zt_span *span, struct zt_lineconfig *lc); +static int wp_tdmv_open(struct zt_chan *chan); +static int wp_tdmv_close(struct zt_chan *chan); +static void wp_tdmv_release(wp_tdmv_softc_t *wp); + +#if defined(__FreeBSD__) || defined(__OpenBSD__) +static int wp_tdmv_ioctl(struct zt_chan*, unsigned int, caddr_t); +#else +static int wp_tdmv_ioctl(struct zt_chan*, unsigned int, unsigned long); +#endif + +static int wp_tdmv_hwec(struct zt_chan *chan, int enable); + +static int wp_tdmv_state(void* pcard, int state); +static int wp_tdmv_running(void* pcard); + +/* RBS functions */ +static int wp_tdmv_sigctrl(sdla_t* card, wp_tdmv_softc_t *wp, int status); +static int wp_tdmv_rbsbits(struct zt_chan *chan, int bits); +static int wp_tdmv_tx_rbsbits(wp_tdmv_softc_t *wp); +static int wp_tdmv_is_rbsbits(wan_tdmv_t *wan_tdmv); +static int wp_tdmv_rbsbits_poll(wan_tdmv_t *wan_tdmv, void *card1); +static void wp_tdmv_report_rbsbits(void* pcard, int channel, unsigned char status); + +static void wp_tdmv_report_alarms(void* pcard, unsigned long te_alarm); + +/* Rx/Tx functions */ +static int wp_tdmv_rx_tx(void* pcard, netskb_t* skb); +static int wp_tdmv_rx_tx_span(void *pcard); +static int wp_tdmv_rx_chan(wan_tdmv_t*, int, unsigned char*, unsigned char*); +#if defined(CONFIG_PRODUCT_WANPIPE_TDM_VOICE_DCHAN) +static int wp_tdmv_tx_dchan(struct zt_chan *chan, int len); +static int wp_tdmv_rx_dchan(wan_tdmv_t*, int, unsigned char*, unsigned int); +#endif +static int wp_tdmv_rxcopy(wan_tdmv_t *wan_tdmv, unsigned char* rxbuf, int max_len); +static int wp_tdmv_rxprep(wan_tdmv_t* wan_tdmv, unsigned char*, int); +static int wp_tdmv_txcopy(wan_tdmv_t* wan_tdmv, unsigned char*, int); +static int wp_tdmv_txprep(wan_tdmv_t* wan_tdmv, unsigned char*, int); + +static inline void start_alarm(wp_tdmv_softc_t* wp); +static inline void stop_alarm(wp_tdmv_softc_t* wp); + +static int wp_tdmv_init(void* pcard, wanif_conf_t *conf); + +/****************************************************************************** +** wp_tdmv_te1_init() - +** +** OK +*/ +int wp_tdmv_te1_init(wan_tdmv_iface_t *iface) +{ + WAN_ASSERT(iface == NULL); + + iface->check_mtu = wp_tdmv_check_mtu; + iface->create = wp_tdmv_create; + iface->remove = wp_tdmv_remove; + iface->reg = wp_tdmv_reg; + iface->unreg = wp_tdmv_unreg; + iface->software_init = wp_tdmv_software_init; + iface->state = wp_tdmv_state; + iface->running = wp_tdmv_running; + iface->rx_tx = wp_tdmv_rx_tx; + iface->rx_chan = wp_tdmv_rx_chan; +#if defined(CONFIG_PRODUCT_WANPIPE_TDM_VOICE_DCHAN) + iface->rx_dchan = wp_tdmv_rx_dchan; +#endif + iface->rx_tx_span = wp_tdmv_rx_tx_span; + iface->is_rbsbits = wp_tdmv_is_rbsbits; + iface->rbsbits_poll = wp_tdmv_rbsbits_poll; + iface->init = wp_tdmv_init; + + return 0; +} + +static int wp_tdmv_check_mtu(void* pcard, unsigned long timeslot_map, int *mtu) +{ + sdla_t *card = (sdla_t*)pcard; + int x, num_of_channels = 0, max_channels; + + max_channels = GET_TE_CHANNEL_RANGE(&card->fe); + for (x = 0; x < max_channels; x++) { + if (wan_test_bit(x,×lot_map)){ + num_of_channels++; + } + } + *mtu = ZT_CHUNKSIZE * num_of_channels; + return 0; +} + +/****************************************************************************** +** wp_tdmv_create() - +** +** OK +*/ +static int wp_tdmv_create(void* pcard, wan_xilinx_conf_t *conf) +{ + sdla_t *card = (sdla_t*)pcard; + wp_tdmv_softc_t *wp = NULL; + wan_tdmv_t *tmp = NULL; + + WAN_ASSERT(card == NULL); + WAN_ASSERT(conf->tdmv_span_no == 0); + memset(&card->wan_tdmv, 0x0, sizeof(wan_tdmv_t)); + /* We are forcing to register wanpipe devices at the same sequence + * that it defines in /etc/zaptel.conf */ + WAN_LIST_FOREACH(tmp, &wan_tdmv_head, next){ + if (tmp->spanno == conf->tdmv_span_no){ + DEBUG_EVENT("%s: Registering device with an incorrect span number!\n", + card->devname); + DEBUG_EVENT("%s: Another wanpipe device already configured to span #%d!\n", + card->devname, conf->tdmv_span_no); + return -EINVAL; + } + if (!WAN_LIST_NEXT(tmp, next)){ + break; + } + } + + card->wan_tdmv.max_timeslots = GET_TE_CHANNEL_RANGE(&card->fe); + card->wan_tdmv.spanno = conf->tdmv_span_no; + card->wandev.te_report_rbsbits = wp_tdmv_report_rbsbits; + card->wandev.te_report_alarms = wp_tdmv_report_alarms; + + wp = wan_malloc(sizeof(wp_tdmv_softc_t)); + if (wp == NULL){ + return -ENOMEM; + } + memset(wp, 0x0, sizeof(wp_tdmv_softc_t)); + card->wan_tdmv.sc = wp; + wp->spanno = conf->tdmv_span_no-1; + wp->num = wp_card_no++; + wp->card = card; + wp->devname = card->devname; + wp->lcode = WAN_FE_LCODE(&card->fe); + wp->frame = WAN_FE_FRAME(&card->fe); + wp->lbo = WAN_TE1_LBO(&card->fe); + wp->ise1 = IS_E1_FEMEDIA(&card->fe) ? 1 : 0; + wp->max_timeslots = IS_E1_FEMEDIA(&card->fe) ? 31: 24; + wp->max_rxtx_len = 0; + wan_spin_lock_init(&wp->lock); + wan_spin_lock_init(&wp->tx_rx_lock); + /* AHDLC */ + if (conf->tdmv_dchan){ + /* PRI signalling is selected with hw HDLC (dchan is not 0) */ + wp->dchan = conf->tdmv_dchan; + } + + if (tmp){ + WAN_LIST_INSERT_AFTER(tmp, &card->wan_tdmv, next); + }else{ + WAN_LIST_INSERT_HEAD(&wan_tdmv_head, &card->wan_tdmv, next); + } + + return 0; +} + +/****************************************************************************** +** wp_tdmv_reg() - +** +** Returns: 0-31 - Return TDM Voice channel number. +** -EINVAL - otherwise +** OK +*/ +static int wp_tdmv_reg(void* pcard, wanif_conf_t *conf, netdevice_t *dev) +{ + sdla_t *card = (sdla_t*)pcard; + wan_tdmv_t *wan_tdmv = &card->wan_tdmv; + wp_tdmv_softc_t *wp = NULL; + int i, channo = 0, cnt = 0; + + WAN_ASSERT(wan_tdmv->sc == NULL); + wp = wan_tdmv->sc; + + if (wan_test_bit(WP_TDMV_REGISTER, &wp->flags)){ + DEBUG_EVENT("%s: Error: Master device has already been configured!\n", + card->devname); + return -EINVAL; + } + + /* + * T1: 1-24 + * E1: 0-31 */ + for(i = 0; imax_timeslots; i++){ + if (wan_test_bit(i, &conf->active_ch)){ + wan_set_bit(i, &wp->timeslot_map); + if (conf->tdmv_echo_off){ + wan_set_bit(i, &wp->echo_off_map); + } + channo = i; + cnt++; + } + } + + if (!cnt){ + DEBUG_EVENT("%s: Error: TDMV iface %s configured with 0 timeslots!\n", + card->devname, conf->name); + return -EINVAL; + } + + if (cnt > 1){ + /* Unchannelized implementation */ + DEBUG_EVENT("%s: TDMV Mode :Unchannelized!\n", + wp->devname); + channo = 0; +#if 0 + if (is_last != WAN_TRUE){ + DEBUG_EVENT("%s: Error: Unchannelized interface must be the Master If (slots=%i)!\n", + wp->devname,cnt); + return -EINVAL; + } +#endif + if (conf->tdmv_echo_off){ + DEBUG_EVENT("%s: TDMV Echo Ctrl:Off\n", + wp->devname); + } + wp->channelized = WAN_FALSE; + + if (wp->dchan){ + if (dev == NULL){ + DEBUG_EVENT("%s: ERROR: Device pointer is NULL for D-chan!\n", + wp->devname); + return -EINVAL; + } + wp->dchan_dev = dev; + } + }else{ + + /* Channelized implementation */ + if (wp->dchan-1 == channo){ + if (dev == NULL){ + DEBUG_EVENT("%s: ERROR: Device pointer is NULL for D-chan!\n", + wp->devname); + return -EINVAL; + } + wp->dchan_dev = dev; + } + if (conf->tdmv_echo_off){ + DEBUG_EVENT("%s: TDMV Echo Ctrl:Off\n", + wp->devname); + } + memset(wp->chans[channo].sreadchunk, WAN_TDMV_IDLE_FLAG, ZT_CHUNKSIZE); + memset(wp->chans[channo].swritechunk, WAN_TDMV_IDLE_FLAG, ZT_CHUNKSIZE); + wp->chans[channo].readchunk = wp->chans[channo].sreadchunk; + wp->chans[channo].writechunk = wp->chans[channo].swritechunk; + wp->channelized = WAN_TRUE; + } + wp_tdmv_check_mtu(card, conf->active_ch, &wp->max_rxtx_len); + return channo; +} + + +/****************************************************************************** +** wp_tdmv_del() - +** +** OK +*/ +static int wp_tdmv_unreg(void* pcard, unsigned long ts_map) +{ + sdla_t *card = (sdla_t*)pcard; + wan_tdmv_t *wan_tdmv = &card->wan_tdmv; + wp_tdmv_softc_t *wp = NULL; + int channo = 0; + + WAN_ASSERT(wan_tdmv->sc == NULL); + wp = wan_tdmv->sc; + + + for(channo = 0; channo < wp->max_timeslots; channo++){ + if (wan_test_bit(channo, &wp->timeslot_map)){ + wan_clear_bit(channo, &wp->timeslot_map); + wan_clear_bit(channo, &wp->echo_off_map); + memset(wp->chans[channo].sreadchunk, + WAN_TDMV_IDLE_FLAG, + ZT_CHUNKSIZE); + memset(wp->chans[channo].swritechunk, + WAN_TDMV_IDLE_FLAG, + ZT_CHUNKSIZE); + wp->chans[channo].readchunk = + wp->chans[channo].sreadchunk; + wp->chans[channo].writechunk = + wp->chans[channo].swritechunk; + } + } + return 0; +} + + +/****************************************************************************** +** wp_tdmv_running() - +** +** OK +*/ +static int wp_tdmv_running(void* pcard) +{ + sdla_t *card = (sdla_t*)pcard; + wan_tdmv_t *wan_tdmv = &card->wan_tdmv; + wp_tdmv_softc_t *wp = NULL; + + wp = wan_tdmv->sc; + if (wp && wp->usecount){ + DEBUG_EVENT("%s: WARNING: Wanpipe is still used by Asterisk!\n", + card->devname); + return -EINVAL; + } + return 0; +} + +/****************************************************************************** +** wp_tdmv_remove() - +** +** OK +*/ +static int wp_tdmv_remove(void* pcard) +{ + sdla_t *card = (sdla_t*)pcard; + wan_tdmv_t *wan_tdmv = &card->wan_tdmv; + wp_tdmv_softc_t *wp = NULL; + wan_smp_flag_t flags; + + if (!card->wan_tdmv.sc){ + return 0; + } + + wp = wan_tdmv->sc; + /* Release span, possibly delayed */ + if (wp && wp->timeslot_map){ + DEBUG_EVENT("%s: Some interfaces are not unregistered (%08lX)!\n", + card->devname, wp->timeslot_map); + return -EINVAL; + } + if (wp && wp->usecount){ + DEBUG_EVENT("%s: ERROR: Wanpipe is still used by Asterisk!\n", + card->devname); + return -EINVAL; + } + + wan_spin_lock_irq(&wp->lock, &flags); + card->wandev.te_report_rbsbits = NULL; + card->wandev.te_report_alarms = NULL; + wan_spin_unlock_irq(&wp->lock, &flags); + + if (wp){ + wan_clear_bit(WP_TDMV_RUNNING, &wp->flags); + wan_clear_bit(WP_TDMV_UP, &wp->flags); + wan_tdmv->sc = NULL; + wp_tdmv_sigctrl(card, wp, WP_TDMV_DISABLE); + WAN_LIST_REMOVE(wan_tdmv, next); + wp_tdmv_release(wp); + }else{ + wan_tdmv->sc = NULL; + } + return 0; +} + +static int wp_tdmv_state(void* pcard, int state) +{ + sdla_t* card = (sdla_t*)pcard; + wan_tdmv_t* wan_tdmv = &card->wan_tdmv; + wp_tdmv_softc_t* wp = NULL; + + WAN_ASSERT(wan_tdmv->sc == NULL); + wp = (wp_tdmv_softc_t*)wan_tdmv->sc; + + switch(state){ + case WAN_CONNECTED: + wan_set_bit(WP_TDMV_UP, &wp->flags); + break; + + case WAN_DISCONNECTED: + wan_clear_bit(WP_TDMV_UP, &wp->flags); + wp->rbs_rx_pending = wp->sig_timeslot_map; + break; + } + return 0; +} + +static int wp_tdmv_sigctrl(sdla_t* card, wp_tdmv_softc_t *wp, int status) +{ + + WAN_ASSERT(wp == NULL); + WAN_ASSERT(card == NULL); + +#if 0 + if (wp->sig_timeslots == wp->span.channels){ + /* All channels are configured to FXO/FXS. + * Only in this case we can use Signalling interrupt */ + if (!wan_test_bit(WP_TDMV_SIG_POLL, &wp->flags)){ + if (status == WP_TDMV_ENABLE){ + DEBUG_EVENT("%s: Enable Signalling interrupt (span=%d)!\n", + card->devname, + wp->spanno); + card->wandev.fe_iface.set_fe_sigcfg(&card->fe, 0); + wan_set_bit(WP_TDMV_SIG_ENABLE, &wp->flags); + } + }else{ + if (status == WP_TDMV_DISABLE){ + DEBUG_EVENT("%s: Disable Signalling interrupt (span=%d)!\n", + card->devname, + wp->spanno); + card->wandev.fe_iface.set_fe_sigcfg(&card->fe, 0); + wp->flags &= ~WP_TDMV_SIG_NONE; + } + } + }else{ + wp->sig_status = (status == WP_TDMV_ENABLE) ? + WP_TDMV_SIG_POLL : WP_TDMV_SIG_NONE; + } +#else + switch(status){ + case WP_TDMV_ENABLE: + wan_set_bit(WP_TDMV_SIG_ENABLE, &wp->flags); + wan_set_bit(WP_TDMV_RBS_READY, &wp->flags); + if (!wan_test_bit(WP_TDMV_SIG_POLL, &wp->flags)){ + card->wandev.fe_iface.set_fe_sigctrl( + &card->fe, WAN_TE_SIG_INTR); + } + break; + case WP_TDMV_DISABLE: + wan_clear_bit(WP_TDMV_RBS_READY, &wp->flags); + wan_clear_bit(WP_TDMV_SIG_ENABLE, &wp->flags); + break; + default: + DEBUG_EVENT("%s: Unknown signalling mode (%d)\n", + wp->devname, status); + return -EINVAL; + } +#endif + return 0; +} + +/****************************************************************************** +** wp_tdmv_report_rbsbits() - Report A,B bit status changes to TDM Voice +** requests. +** +** DONE +*/ +static void wp_tdmv_report_rbsbits(void* pcard, int channel, unsigned char status) +{ + sdla_t* card = (sdla_t*)pcard; + wan_tdmv_t* wan_tdmv = &card->wan_tdmv; + wp_tdmv_softc_t* wp = NULL; + int rxs = 0, i = 0; + + WAN_ASSERT1(wan_tdmv->sc == NULL); + wp = (wp_tdmv_softc_t*)wan_tdmv->sc; + + if (!wan_test_bit(channel-1, &wp->timeslot_map)){ + return; + } + + if (status & WAN_RBS_SIG_A) rxs |= ZT_ABIT; + if (status & WAN_RBS_SIG_B) rxs |= ZT_BBIT; + if (status & WAN_RBS_SIG_C) rxs |= ZT_CBIT; + if (status & WAN_RBS_SIG_D) rxs |= ZT_DBIT; +#if 0 + if (wp->ise1){ + FIXME_MSG("wp_tdmv_report_rbsbits"); + /* Read 5 registers at a time, loading 10 channels at a time */ + for (i = (x *5); i < (x * 5) + 5; i++) { + /* FIXME a = __t1_get_reg(wp, 0x31 + i); */ + /* Get high channel in low bits */ + rxs = (a & 0xf); + if (!(wp->chans[i+15].sig & ZT_SIG_CLEAR)) { + if (wp->chans[i+15].rxsig != rxs) + zt_rbsbits(&wp->chans[i+15], rxs); + } + rxs = (a >> 4) & 0xf; + if (!(wp->chans[i].sig & ZT_SIG_CLEAR)) { + if (wp->chans[i].rxsig != rxs) + zt_rbsbits(&wp->chans[i], rxs); + } + } + } +#endif + for(i=0; i < wp->span.channels;i++){ + if (wp->chans[i].chanpos == channel) + break; + } + if (i == wp->span.channels){ + return; + } + if (!(wp->chans[i].sig & ZT_SIG_CLEAR) && + (wp->chans[i].rxsig != rxs)){ + zt_rbsbits(&wp->chans[i], rxs); +#if 0 + DEBUG_EVENT("[TDMV] %s: %s:%02d(%d) RX RBS: A:%1d B:%1d C:%1d D:%1d\n", + wp->devname, + (wp->ise1) ? "E1" : "T1", + channel, wp->chans[i].channo, + (rxs & ZT_ABIT) ? 1 : 0, + (rxs & ZT_BBIT) ? 1 : 0, + (rxs & ZT_CBIT) ? 1 : 0, + (rxs & ZT_DBIT) ? 1 : 0); +#endif + } +} + +/****************************************************************************** +** wp_tdmv_report_alarms() - +** +** DONE +*/ +static void wp_tdmv_report_alarms(void* pcard, unsigned long te_alarm) +{ + sdla_t *card = (sdla_t*)pcard; + wan_tdmv_t *wan_tdmv = &card->wan_tdmv; + wp_tdmv_softc_t *wp = NULL; + int alarms = 0, prev_alarms; + int x,j; + + /* The sc pointer can be NULL, on shutdown. In this + * case don't generate error, just get out */ + wp = wan_tdmv->sc; + if (!wp){ + return; + } + + /* And consider only carrier alarms */ + wp->span.alarms &= (ZT_ALARM_RED | ZT_ALARM_BLUE | ZT_ALARM_NOTOPEN); + prev_alarms = wp->span.alarms; + + if (wp->ise1){ + /* XXX Implement me XXX */ + }else{ + /* Detect loopup code if we're not sending one */ + if (!wp->span.mainttimer && (te_alarm & WAN_TE_BIT_LOOPUP_CODE)){ + /* Loop-up code detected */ + if ((wp->loopupcnt++ > 80) && (wp->span.maintstat != ZT_MAINT_REMOTELOOP)){ + card->wandev.fe_iface.set_fe_lbmode( + &wp->card->fe, + WAN_TE1_DDLB_MODE, + WAN_TE1_DEACTIVATE_LB); + card->wandev.fe_iface.set_fe_lbmode( + &wp->card->fe, + WAN_TE1_LINELB_MODE, + WAN_TE1_ACTIVATE_LB); + wp->span.maintstat = ZT_MAINT_REMOTELOOP; + } + }else{ + wp->loopupcnt = 0; + } + /* Same for loopdown code */ + if (!wp->span.mainttimer && (te_alarm & WAN_TE_BIT_LOOPDOWN_CODE)){ + /* Loop-down code detected */ + if ((wp->loopdowncnt++ > 80) && (wp->span.maintstat == ZT_MAINT_REMOTELOOP)){ + card->wandev.fe_iface.set_fe_lbmode( + &wp->card->fe, + WAN_TE1_DDLB_MODE, + WAN_TE1_DEACTIVATE_LB); + card->wandev.fe_iface.set_fe_lbmode( + &wp->card->fe, + WAN_TE1_LINELB_MODE, + WAN_TE1_DEACTIVATE_LB); + wp->span.maintstat = ZT_MAINT_NONE; + } + }else{ + wp->loopdowncnt = 0; + } + } + + if (wp->span.lineconfig & ZT_CONFIG_NOTOPEN) { + for (x=0,j=0;x < wp->span.channels;x++){ + if ((wp->chans[x].flags & ZT_FLAG_OPEN) || + (wp->chans[x].flags & ZT_FLAG_NETDEV)){ + j++; + } + } + if (!j){ + alarms |= ZT_ALARM_NOTOPEN; + } + } + + if (wp->ise1) { + if (te_alarm & WAN_TE_BIT_RED_ALARM) + alarms |= ZT_ALARM_RED; + if (te_alarm & WAN_TE_BIT_AIS_ALARM) + alarms |= ZT_ALARM_BLUE; + } else { + /* Check actual alarm status */ + if (te_alarm & WAN_TE_BIT_RED_ALARM) + alarms |= ZT_ALARM_RED; + if (te_alarm & WAN_TE_BIT_AIS_ALARM) + alarms |= ZT_ALARM_BLUE; + } + /* Keep track of recovering */ + if ((!alarms) && wp->span.alarms) + wp->alarmtimer = ZT_ALARMSETTLE_TIME; + +#if 0 + /* If receiving alarms, go into Yellow alarm state */ + if (alarms && (!wp->span.alarms)) { + DEBUG_TDMV("%s: Going into yellow alarm\n", + wp->devname); + if (card->wandev.fe_iface.set_fe_alarm){ + card->wandev.fe_iface.set_fe_alarm(&card->fe, WAN_TE_BIT_YEL_ALARM); + } + } +#endif + + if (wp->span.alarms != alarms) { + /* FIXME: Alarm status changed!!! */ + DEBUG_TDMV("%s: Alarm status changed %X!\n", + wp->devname,alarms); + } + /* + ** if (wp->alarmtimer) + ** alarms |= ZT_ALARM_RECOVER; */ + if (te_alarm & WAN_TE_BIT_YEL_ALARM) + alarms |= ZT_ALARM_YELLOW; + + wp->span.alarms = alarms; + if (wan_test_bit(WP_TDMV_RUNNING, &wp->flags)){ +#if 0 + /* If receiving alarms, go into Yellow alarm state */ + if (alarms && (!prev_alarms)) { + DEBUG_TDMV("%s: Going into yellow alarm\n", + wp->devname); + if (card->wandev.fe_iface.set_fe_alarm){ + card->wandev.fe_iface.set_fe_alarm( + &card->fe, + WAN_TE_BIT_YEL_ALARM); + } + } +#endif + zt_alarm_notify(&wp->span); + } + return; +} + +/****************************************************************************** +** wp_tdmv_txcopy() - +** +** OK +*/ +static int +wp_tdmv_txcopy(wan_tdmv_t *wan_tdmv, unsigned char* txbuf, int max_len) +{ + wp_tdmv_softc_t *wp = wan_tdmv->sc; + int x = 0, y = 0, offset = 0; + + WAN_ASSERT(wp == NULL); + for (y=0;yspan.channels;x++){ + if (!wan_test_bit(x,&wp->timeslot_map)){ + continue; + } + txbuf[offset++] = wp->chans[x].writechunk[y]; + } + } + return (offset+1); +} + +/****************************************************************************** +** wp_tdmv_txprep() - +** +** OK +*/ +static int +wp_tdmv_txprep(wan_tdmv_t *wan_tdmv, unsigned char* txbuf, int max_len) +{ + wp_tdmv_softc_t *wp = wan_tdmv->sc; + + WAN_ASSERT2(wp == NULL, 0); + zt_transmit(&wp->span); + return wp_tdmv_txcopy(wan_tdmv, txbuf, max_len); +} + +/****************************************************************************** +** wp_tdmv_rxcopy() - +** +** OK +*/ +static int +wp_tdmv_rxcopy(wan_tdmv_t *wan_tdmv, unsigned char* rxbuf, int max_len) +{ + wp_tdmv_softc_t *wp = wan_tdmv->sc; + int x, y, offset = 0; + int channels = wp->span.channels; + unsigned char value; + + WAN_ASSERT(wp == NULL); + for (y=0;ytimeslot_map)){ + value = rxbuf[offset++]; + }else{ + value = WAN_TDMV_IDLE_FLAG; /* 0xFE; */ + } + wp->chans[x].readchunk[y] = value; + } + } + return offset; +} + +/****************************************************************************** +** wp_tdmv_rxprep() - +** +** OK +*/ +static int +wp_tdmv_rxprep(wan_tdmv_t *wan_tdmv, unsigned char* rxbuf, int max_len) +{ + wp_tdmv_softc_t *wp = wan_tdmv->sc; + int x, offset = 0, channels = wp->span.channels; + + WAN_ASSERT2(wp == NULL, 0); + + offset = wp_tdmv_rxcopy(wan_tdmv, rxbuf, max_len); + + if (!wp->echo_off_map){ + for (x = 0; x < channels; x++){ +#ifdef CONFIG_PRODUCT_WANPIPE_TDM_VOICE_ECHOMASTER + wan_tdmv_rxtx_pwr_t *pwr_rxtx = &wan_tdmv->chan_pwr[x]; + wp_tdmv_echo_check(wan_tdmv, &wp->chans[0], x); + if(pwr_rxtx->current_state != ECHO_ABSENT){ +#endif + zt_ec_chunk( + &wp->chans[x], + wp->chans[x].readchunk, + wp->chans[x].writechunk); +#if 0 + zt_ec_chunk( + &wp->chans[x], + wp->chans[x].readchunk, + wp->ec_chunk1[x]); + memcpy( + wp->ec_chunk1[x], + wp->chans[x].writechunk, + ZT_CHUNKSIZE); +#endif + +#ifdef CONFIG_PRODUCT_WANPIPE_TDM_VOICE_ECHOMASTER + }/* if() */ +#endif + }/* for() */ + }/* if() */ + + zt_receive(&wp->span); + return (offset); +} + + +/****************************************************************************** +** wp_tdmv_rx_tx() - +** +** OK +*/ +static int wp_tdmv_rx_tx(void* pcard, netskb_t* skb) +{ + sdla_t *card = (sdla_t*)pcard; + wan_tdmv_t *wan_tdmv = &card->wan_tdmv; + wp_tdmv_softc_t *wp = NULL; + int len; + + WAN_ASSERT(wan_tdmv->sc == NULL); + WAN_ASSERT(skb == NULL); + wp = wan_tdmv->sc; + + if (wan_skb_len(skb) != wp->max_rxtx_len){ + if (WAN_NET_RATELIMIT()) { + DEBUG_EVENT("%s: Internal Error[%s:%d]: Wrong buffer lenght %d (%d)!\n", + wp->devname, + __FUNCTION__,__LINE__, + wan_skb_len(skb), + wp->max_rxtx_len); + } + return 0; + } + + wp->intcount ++; + + len = wp_tdmv_rxprep( + wan_tdmv, + wan_skb_data(skb), + wan_skb_len(skb)); + len = wp_tdmv_txprep( + wan_tdmv, + wan_skb_data(skb), + wan_skb_len(skb)); + + if (wan_test_bit(WP_TDMV_RBS_UPDATE, &wp->flags)){ + if (card->wandev.fe_iface.report_rbsbits){ + card->wandev.fe_iface.report_rbsbits(&card->fe); + } + wan_clear_bit(WP_TDMV_RBS_UPDATE, &wp->flags); + wan_clear_bit(WP_TDMV_RBS_BUSY, &wp->flags); + } + + return wp->max_rxtx_len; +} + + +/* +** STATIC FUNCTION DEFINITIONS +** +*/ + +/****************************************************************************** +** wp_tdmv_software_init() - +** +** OK +*/ +static int wp_tdmv_software_init(wan_tdmv_t *wan_tdmv) +{ + sdla_t *card = NULL; + wp_tdmv_softc_t *wp = wan_tdmv->sc; + int x = 0; + + WAN_ASSERT(wp == NULL); + WAN_ASSERT(wp->card == NULL); + card = wp->card; + + if (wan_test_bit(WP_TDMV_REGISTER, &wp->flags)){ + DEBUG_EVENT("%s: Wanpipe device is already registered to Zaptel span # %d!\n", + wp->devname, wp->span.spanno); + return 0; + } +#if 0 + if (wp->ise1 && wp->channelized == WAN_FALSE){ + /* Timeslot map for E1 includes ts0. TDM voice does never + ** use ts0, so i will shift map 1 bit right to get + ** everything alignment as T1 */ + wp->timeslot_map = wp->timeslot_map >> 1; + wp->echo_off_map = wp->echo_off_map >> 1; + } +#endif + if (wp->ise1){ + sprintf(wp->span.name, "WPE1/%d", wp->num); + }else{ + sprintf(wp->span.name, "WPT1/%d", wp->num); + } + sprintf(wp->span.desc, "%s card %d", wp->devname, wp->num); + wp->span.spanconfig = wp_tdmv_spanconfig; + wp->span.chanconfig = wp_tdmv_chanconfig; + wp->span.startup = wp_tdmv_startup; + wp->span.shutdown = wp_tdmv_shutdown; + wp->span.rbsbits = wp_tdmv_rbsbits; + wp->span.maint = wp_tdmv_maint; + wp->span.open = wp_tdmv_open; + wp->span.close = wp_tdmv_close; + wp->span.channels = wp->max_timeslots; + wp->span.chans = wp->chans; + wp->span.flags = ZT_FLAG_RBS; + wp->span.linecompat = ZT_CONFIG_AMI | ZT_CONFIG_B8ZS | ZT_CONFIG_D4 | ZT_CONFIG_ESF; + wp->span.ioctl = wp_tdmv_ioctl; + /* Set this pointer only if card has hw echo canceller module */ + if (card->wandev.ec_dev){ + wp->span.echocan = wp_tdmv_hwec; + } + wp->span.pvt = wp; + if (wp->ise1){ + wp->span.deflaw = ZT_LAW_ALAW; + card->fe.fe_cfg.tdmv_law = WAN_TDMV_ALAW; + }else{ + wp->span.deflaw = ZT_LAW_MULAW; + card->fe.fe_cfg.tdmv_law = WAN_TDMV_MULAW; + } +#if !defined(__FreeBSD__) && !defined(__OpenBSD__) + init_waitqueue_head(&wp->span.maintq); +#endif + for (x=0;xspan.channels;x++) { + sprintf(wp->chans[x].name, "%s/%d", wp->span.name, x+1); + if (wan_test_bit(x,&wp->timeslot_map)){ + DEBUG_TEST("%s: Configure channel %d for voice (%s)!\n", + wp->devname, + x + 1, + wp->chans[x].name); + wp->chans[x].sigcap = + ZT_SIG_EM | ZT_SIG_CLEAR | ZT_SIG_EM_E1 | + ZT_SIG_FXSLS | ZT_SIG_FXSGS | + ZT_SIG_FXSKS | ZT_SIG_FXOLS | + ZT_SIG_FXOGS | ZT_SIG_FXOKS | ZT_SIG_CAS; + }else{ + wp->chans[x].sigcap = ZT_SIG_NONE; + } + wp->chans[x].pvt = wp; + wp->chans[x].chanpos = x + 1; + wp->chans[x].rxsig = 0x00; + } + + if (zt_register(&wp->span, 0)) { + DEBUG_EVENT("%s: Unable to register span with zaptel\n", + wp->devname); + return -EINVAL; + } + + if (wp->span.spanno != wp->spanno +1){ + DEBUG_EVENT("\n"); + DEBUG_EVENT("WARNING: Span number %d is already used by another device!\n", + wp->spanno + 1); + DEBUG_EVENT(" Possible cause: Another TDM driver already loaded!\n"); + DEBUG_EVENT(" Solution: Unload wanpipe and check currently\n"); + DEBUG_EVENT(" used spans in /proc/zaptel directory.\n"); + DEBUG_EVENT(" Reconfiguring device %s to new span number # %d\n", + wp->devname,wp->span.spanno); + DEBUG_EVENT("\n"); + wp->spanno = wp->span.spanno-1; + }else{ + DEBUG_EVENT("%s: Wanpipe device is registered to Zaptel span # %d!\n", + wp->devname, wp->span.spanno); + } + if (wp->channelized == WAN_FALSE && wp->dchan){ + /* Apr 15, 2005 + * For unchannelized mode, if HW HDLC protocol is selected + * by using dchan configuration option, remove dchan timeslot + * from timeslot and echo map. */ + wan_clear_bit(wp->dchan-1, &wp->timeslot_map); + wan_clear_bit(wp->dchan-1, &wp->echo_off_map); + } + wp_tdmv_check_mtu(card, wp->timeslot_map, &wp->max_rxtx_len); + wan_set_bit(WP_TDMV_REGISTER, &wp->flags); + wan_set_bit(WP_TDMV_SIG_POLL, &wp->flags); + + return 0; +} + + + + + + + +/****************************************************************************** +** wp_tdmv_startup() - +** +** OK +*/ +static int wp_tdmv_startup(struct zt_span *span) +{ + wp_tdmv_softc_t* wp = NULL; + int i; + + WAN_ASSERT2(span == NULL, -ENODEV); + WAN_ASSERT2(span->pvt == NULL, -ENODEV); + wp = span->pvt; + + /* initialize the start value for the entire chunk of last ec buffer */ + for(i = 0; i < span->channels; i++){ + memset(wp->ec_chunk1[i], + ZT_LIN2X(0,&span->chans[i]),ZT_CHUNKSIZE); + memset(wp->ec_chunk2[i], + ZT_LIN2X(0,&span->chans[i]),ZT_CHUNKSIZE); + } + + + if (!(span->flags & ZT_FLAG_RUNNING)) { + /* Only if we're not already going */ + span->flags |= ZT_FLAG_RUNNING; + } + + return 0; +} + +/****************************************************************************** +** wp_tdmv_shutdown() - +** +** OK +*/ +static int wp_tdmv_shutdown(struct zt_span *span) +{ + wp_tdmv_softc_t* wp = NULL; + wan_smp_flag_t flags; + + WAN_ASSERT2(span == NULL, -ENODEV); + WAN_ASSERT2(span->pvt == NULL, -ENODEV); + wp = span->pvt; + wan_spin_lock_irq(&wp->lock, &flags); + span->flags &= ~ZT_FLAG_RUNNING; + wan_spin_unlock_irq(&wp->lock, &flags); + return 0; +} + +/****************************************************************************** +** wp_tdmv_maint() - +** +** OK +*/ +static int wp_tdmv_maint(struct zt_span *span, int cmd) +{ + wp_tdmv_softc_t *wp = span->pvt; + sdla_t *card = wp->card; + int res = 0; + wan_smp_flag_t flags; + + WAN_ASSERT2(span == NULL, -ENODEV); + WAN_ASSERT2(span->pvt == NULL, -ENODEV); + wp = span->pvt; + wan_spin_lock_irq(&wp->lock, &flags); + if (wp->ise1) { +#if 0 + /* FIXME: Support E1 */ + switch(cmd) { + case ZT_MAINT_NONE: + DEBUG_EVENT("%s: E1: Set to normal mode (no local/remote loops)\n", + wp->card->devname); + /* FIXME __t1_set_reg(wp,0xa8,0); */ /* no loops */ + break; + case ZT_MAINT_LOCALLOOP: + DEBUG_EVENT("%s: E1: Set to local loopback mode\n", + wp->card->devname); + /* FIXME __t1_set_reg(wp,0xa8,0x40); */ /* local loop */ + break; + case ZT_MAINT_REMOTELOOP: + DEBUG_EVENT("%s: E1: Set to remote loopback mode\n", + wp->card->devname); + /* FIXME __t1_set_reg(wp,0xa8,0x80);*/ /* remote loop */ + break; + case ZT_MAINT_LOOPUP: + case ZT_MAINT_LOOPDOWN: + case ZT_MAINT_LOOPSTOP: + res = -ENOSYS; + break; + default: + DEBUG_EVENT("%s: E1: Unknown maintenance mode (%d)\n", + wp->card->devname, cmd); + res = -EINVAL; + break; + } +#endif + }else{ + switch(cmd) { + case ZT_MAINT_NONE: + DEBUG_EVENT("%s: T1: Set to normal mode (no local/remote loop)\n", + wp->card->devname); + card->wandev.fe_iface.set_fe_lbmode( + &wp->card->fe, + WAN_TE1_DDLB_MODE, + WAN_TE1_DEACTIVATE_LB); + card->wandev.fe_iface.set_fe_lbmode( + &wp->card->fe, + WAN_TE1_LINELB_MODE, + WAN_TE1_DEACTIVATE_LB); + break; + case ZT_MAINT_LOCALLOOP: + DEBUG_EVENT("%s: T1: Set to local loopback mode (local/no remote loop)\n", + wp->card->devname); + card->wandev.fe_iface.set_fe_lbmode( + &wp->card->fe, + WAN_TE1_LINELB_MODE, + WAN_TE1_DEACTIVATE_LB); + card->wandev.fe_iface.set_fe_lbmode( + &wp->card->fe, + WAN_TE1_DDLB_MODE, + WAN_TE1_ACTIVATE_LB); + break; + case ZT_MAINT_REMOTELOOP: + DEBUG_EVENT("%s: T1: Set to remote loopback mode (no local/remote loop)\n", + wp->card->devname); + card->wandev.fe_iface.set_fe_lbmode( + &wp->card->fe, + WAN_TE1_LINELB_MODE, + WAN_TE1_ACTIVATE_LB); + card->wandev.fe_iface.set_fe_lbmode( + &wp->card->fe, + WAN_TE1_LINELB_MODE, + WAN_TE1_DEACTIVATE_LB); + break; + case ZT_MAINT_LOOPUP: + DEBUG_EVENT("%s: T1: Send loopup code\n", + wp->card->devname); + card->wandev.fe_iface.set_fe_lbmode( + &wp->card->fe, + WAN_TE1_TX_LB_MODE, + WAN_TE1_ACTIVATE_LB); + break; + case ZT_MAINT_LOOPDOWN: + DEBUG_EVENT("%s: T1: Send loopdown code\n", + wp->card->devname); + card->wandev.fe_iface.set_fe_lbmode( + &wp->card->fe, + WAN_TE1_TX_LB_MODE, + WAN_TE1_DEACTIVATE_LB); + break; + case ZT_MAINT_LOOPSTOP: + DEBUG_EVENT("%s: T1: Stop sending loop code\n", + wp->card->devname); + /* FIXME __t1_set_reg(wp,0x30,0); */ /* stop sending loopup code */ + break; + default: + DEBUG_EVENT("%s: T1: Unknown maintenance mode (%d)\n", + wp->card->devname, cmd); + res = -EINVAL; + } + } + wan_spin_unlock_irq(&wp->lock, &flags); + return res; +} + +static void wp_tdmv_set_clear(wp_tdmv_softc_t* wp) +{ + WAN_ASSERT1(wp == NULL); + + /* FIXME: Add action for this function */ +} + +/****************************************************************************** +** sigstr() - +** +** OK +*/ +#if 0 +static char *wp_tdmv_sigstr(int sig) +{ + switch (sig) { + case ZT_SIG_FXSLS: + return "FXSLS"; + case ZT_SIG_FXSKS: + return "FXSKS"; + case ZT_SIG_FXSGS: + return "FXSGS"; + case ZT_SIG_FXOLS: + return "FXOLS"; + case ZT_SIG_FXOKS: + return "FXOKS"; + case ZT_SIG_FXOGS: + return "FXOGS"; + case ZT_SIG_EM: + return "E&M"; + case ZT_SIG_CLEAR: + return "Clear"; + case ZT_SIG_HDLCRAW: + return "HDLCRAW"; + case ZT_SIG_HDLCFCS: + return "HDLCFCS"; + case ZT_SIG_HDLCNET: + return "HDLCNET"; + case ZT_SIG_SLAVE: + return "Slave"; + case ZT_SIG_CAS: + return "CAS"; + case ZT_SIG_DACS: + return "DACS"; + case ZT_SIG_SF: + return "SF (ToneOnly)"; + case ZT_SIG_NONE: + default: + return "Unconfigured"; + } + +} +#endif + +static int wp_tdmv_chanconfig(struct zt_chan *chan, int sigtype) +{ + sdla_t *card; + wp_tdmv_softc_t *wp = NULL; + + WAN_ASSERT2(chan == NULL, -ENODEV); + WAN_ASSERT2(chan->pvt == NULL, -ENODEV); + wp = chan->pvt; + card = (sdla_t*)wp->card; + + if (chan->span->flags & ZT_FLAG_RUNNING){ + wp_tdmv_set_clear(wp); + } + + if (!wan_test_and_set_bit(chan->chanpos, &wp->config_tsmap)){ + wp->timeslots++; + } + if (!(sigtype & ZT_SIG_CLEAR)){ + /* Set Signalling channel map */ + if (!wan_test_and_set_bit(chan->chanpos-1, &wp->sig_timeslot_map)){ + wp->sig_timeslots ++; + wan_set_bit(chan->chanpos-1, &wp->rbs_rx_pending); + } + wp_tdmv_sigctrl(card, wp, WP_TDMV_ENABLE); + } + return 0; +} + +/****************************************************************************** +** wp_tdmv_spanconfig() - +** +** OK +*/ +static int wp_tdmv_spanconfig(struct zt_span *span, struct zt_lineconfig *lc) +{ + wp_tdmv_softc_t *wp = NULL; + sdla_t *card = NULL; + int err = 0; + + WAN_ASSERT2(span == NULL, -ENODEV); + WAN_ASSERT2(span->pvt == NULL, -ENODEV); + wp = span->pvt; + card = (sdla_t*)wp->card; + switch(wp->lcode){ + case WAN_LCODE_AMI: + span->lineconfig |= ZT_CONFIG_AMI; + break; + case WAN_LCODE_B8ZS: + span->lineconfig |= ZT_CONFIG_B8ZS; + break; + case WAN_LCODE_HDB3: + span->lineconfig |= ZT_CONFIG_HDB3; + break; + } + switch(wp->frame){ + case WAN_FR_ESF: + span->lineconfig |= ZT_CONFIG_ESF; + break; + case WAN_FR_D4: + span->lineconfig |= ZT_CONFIG_D4; + break; + case WAN_FR_CRC4: + span->lineconfig |= ZT_CONFIG_CRC4; + break; + } + if (wp->ise1){ + if (lc->lineconfig & ZT_CONFIG_CCS){ + span->lineconfig |= ZT_CONFIG_CCS; + card->fe.fe_cfg.cfg.te_cfg.sig_mode = WAN_TE1_SIG_CCS; + }else{ + card->fe.fe_cfg.cfg.te_cfg.sig_mode = WAN_TE1_SIG_CAS; + } + if (card->wandev.fe_iface.post_config){ + card->wandev.fe_iface.post_config(&card->fe); + } + } + span->txlevel = 0; + switch(wp->lbo){ + case WAN_T1_LBO_0_DB: + DEBUG_TE1("%s: LBO 0 dB\n", card->devname); + span->txlevel = 0; + break; + case WAN_T1_LBO_75_DB: + DEBUG_TE1("%s: LBO 7.5 dB\n", card->devname); + span->txlevel = 5; + break; + case WAN_T1_LBO_15_DB: + DEBUG_TE1("%s: LBO 15 dB\n", card->devname); + span->txlevel = 6; + break; + case WAN_T1_LBO_225_DB: + DEBUG_TE1("%s: LBO 22.5 dB\n", card->devname); + span->txlevel = 7; + break; + case WAN_T1_0_110: + DEBUG_TE1("%s: LBO 0-110 ft.\n", card->devname); + span->txlevel = 0; + break; + case WAN_T1_110_220: + DEBUG_TE1("%s: LBO 110-220 ft.\n", card->devname); + span->txlevel = 1; + break; + case WAN_T1_220_330: + DEBUG_TE1("%s: LBO 220-330 ft.\n", card->devname); + span->txlevel = 2; + break; + case WAN_T1_330_440: + DEBUG_TE1("%s: LBO 330-440 ft.\n", card->devname); + span->txlevel = 3; + break; + case WAN_T1_440_550: + DEBUG_TE1("%s: LBO 440-550 ft.\n", card->devname); + span->txlevel = 3; + break; + case WAN_T1_550_660: + DEBUG_TE1("%s: LBO 550-660 ft.\n", card->devname); + span->txlevel = 4; + break; + } + + span->rxlevel = 0; + /* Do we want to SYNC on receive or not */ + wp->sync = lc->sync; + /* */ + /* If already running, apply changes immediately */ + if (span->flags & ZT_FLAG_RUNNING){ + err = wp_tdmv_startup(span); + } + + return err; +} + + +/****************************************************************************** +** wp_tdmv_rbsbits() - Set A,B bits according TDM Voice requests. +** +** DONE +*/ +static int wp_tdmv_rbsbits(struct zt_chan *chan, int bits) +{ + wp_tdmv_softc_t *wp = NULL; + sdla_t *card = NULL; + unsigned char ABCD_bits = 0x00; + + /* Byte offset */ + WAN_ASSERT2(chan == NULL, 0); + if ((wp = chan->pvt) == NULL) return 0; + WAN_ASSERT2(wp->card == NULL, 0); + card = (sdla_t*)wp->card; + if (!wan_test_bit(chan->chanpos-1, &wp->timeslot_map)){ + return 0; + } + if (!wan_test_bit(WP_TDMV_SIG_ENABLE, &wp->flags)){ + return 0; + } + if (bits & ZT_ABIT) ABCD_bits |= WAN_RBS_SIG_A; + if (bits & ZT_BBIT) ABCD_bits |= WAN_RBS_SIG_B; + if (bits & ZT_CBIT) ABCD_bits |= WAN_RBS_SIG_C; + if (bits & ZT_DBIT) ABCD_bits |= WAN_RBS_SIG_D; + + if (chan->flags & ZT_FLAG_HDLC){ + return 0; + } +#if 0 + DEBUG_EVENT("[TDMV] %s: %s:%02d(%d) TX RBS: A:%1d B:%1d C:%1d D:%1d\n", + wp->devname, + (wp->ise1) ? "E1" : "T1", + chan->chanpos, chan->channo, + (ABCD_bits & WAN_RBS_SIG_A) ? 1 : 0, + (ABCD_bits & WAN_RBS_SIG_B) ? 1 : 0, + (ABCD_bits & WAN_RBS_SIG_C) ? 1 : 0, + (ABCD_bits & WAN_RBS_SIG_D) ? 1 : 0); +#endif + + if (wan_test_and_set_bit(chan->chanpos-1, &wp->rbs_tx_status)){ + if (ABCD_bits == wp->rbs_tx[chan->chanpos-1]){ + return 0; + } + if (wan_test_and_set_bit(chan->chanpos-1, &wp->rbs_tx1_status)){ + if (ABCD_bits == wp->rbs_tx1[chan->chanpos-1]){ + return 0; + } + DEBUG_EVENT("%s: Critical Error: TX RBS for channel %d\n", + wp->devname, + chan->chanpos); + } + wp->rbs_tx1[chan->chanpos-1] = ABCD_bits; + }else{ + wp->rbs_tx[chan->chanpos-1] = ABCD_bits; + } +#if 0 + wan_set_bit(7, &ABCD_bits); + if (wan_test_and_set_bit(7, &wp->rbs_tx[chan->chanpos-1])){ + if (ABCD_bits == wp->rbs_tx[chan->chanpos-1]){ + return 0; + } + if (wan_test_and_set_bit(7, &wp->rbs_tx1[chan->chanpos-1])){ + if (ABCD_bits == wp->rbs_tx1[chan->chanpos-1]){ + return 0; + } + DEBUG_EVENT("%s: Critical Error: TX RBS for channel %d\n", + wp->devname, + chan->chanpos); + } + wp->rbs_tx1[chan->chanpos-1] = ABCD_bits; + }else{ + wp->rbs_tx[chan->chanpos-1] = ABCD_bits; + } +#endif + return 0; +} + + +/****************************************************************************** +** wp_tdmv_is_rbsbits() - +** +** Returns: 1 - start RBS poll routine, 0 - otherwise +*/ +static int wp_tdmv_is_rbsbits(wan_tdmv_t *wan_tdmv) +{ + wp_tdmv_softc_t *wp = NULL; + + WAN_ASSERT(wan_tdmv->sc == NULL); + wp = wan_tdmv->sc; + + /* Do not read signalling bits if Asterisk not configured to */ + if (!IS_TDMV_SIG(wp)){ + return 0; + } + + if (wan_test_and_set_bit(WP_TDMV_RBS_BUSY, &wp->flags)){ + /* RBS read still in progress or not ready*/ + return 0; + } + + if (wp->rbs_tx_status || wp->rbs_tx1_status){ + return 1; + } + + if (!IS_TDMV_UP(wp)){ + wan_clear_bit(WP_TDMV_RBS_BUSY, &wp->flags); + return 0; + } + + /* Increment RX/TX interrupt counter */ + wp->rbscount++; + + /* RBS_POLL + ** Update RBS bits now (we don't have to do very often) */ + if (!(wp->rbscount & 0xF)){ + return 1; + } + + /* Wait for the next time */ + wan_clear_bit(WP_TDMV_RBS_BUSY, &wp->flags); + return 0; +} + +/****************************************************************************** +** wp_tdmv_rbsbits_poll() - +** +** DONE +*/ +static int wp_tdmv_rbsbits_poll(wan_tdmv_t *wan_tdmv, void *card1) +{ + sdla_t *card = (sdla_t*)card1; + wp_tdmv_softc_t *wp = NULL; + int i, x; + + WAN_ASSERT(wan_tdmv->sc == NULL); + wp = wan_tdmv->sc; + + /* TX rbsbits */ + if (wp->rbs_tx_status || wp->rbs_tx1_status){ + wp_tdmv_tx_rbsbits(wp); + } + + if (!IS_TDMV_UP(wp)){ + wan_clear_bit(WP_TDMV_RBS_BUSY, &wp->flags); + return 0; + } + if (wp->rbs_rx_pending){ + DEBUG_TEST("%s: %s:%d: Reading RBS (pending)\n", + wp->devname, + __FUNCTION__,__LINE__); + for(i=0; i < wp->max_timeslots;i++){ + if (wan_test_bit(i, &wp->rbs_rx_pending)){ + wan_clear_bit(i, &wp->rbs_rx_pending); + card->wandev.fe_iface.read_rbsbits( + &card->fe, + i+1, + WAN_TE_RBS_UPDATE|WAN_TE_RBS_REPORT); + } + } + wan_set_bit(WP_TDMV_RBS_UPDATE, &wp->flags); + return 0; + } + + /* RX rbsbits */ + DEBUG_TEST("%s: %s:%d: Reading RBS (%s)\n", + wp->devname, + __FUNCTION__,__LINE__, + (wp->rbscount % 1000) ? "Normal" : "Sanity"); + if (wp->rbscount % 1000 == 0){ + for(x = 0; x < wp->max_timeslots; x++){ + if (wan_test_bit(x, &wp->sig_timeslot_map)){ + card->wandev.fe_iface.read_rbsbits( + &card->fe, + x+1, + WAN_TE_RBS_UPDATE); + } + } + }else{ + if (card->wandev.fe_iface.check_rbsbits == NULL){ + DEBUG_EVENT("%s: Internal Error [%s:%d]!\n", + wp->devname, + __FUNCTION__,__LINE__); + return -EINVAL; + } + card->wandev.fe_iface.check_rbsbits( + &card->fe, + 1, wp->sig_timeslot_map, 0); + card->wandev.fe_iface.check_rbsbits( + &card->fe, + 9, wp->sig_timeslot_map, 0); + card->wandev.fe_iface.check_rbsbits( + &card->fe, + 17, wp->sig_timeslot_map, 0); + if (wp->ise1){ + card->wandev.fe_iface.check_rbsbits( + &card->fe, + 25, wp->sig_timeslot_map, 0); + } + } + wan_set_bit(WP_TDMV_RBS_UPDATE, &wp->flags); + return 0; +} + +/****************************************************************************** +** wp_tdmv_tx_rbsbits() - +** +** DONE +*/ +static int wp_tdmv_tx_rbsbits(wp_tdmv_softc_t *wp) +{ + sdla_t *card; + int x; + + WAN_ASSERT2(wp->card == NULL, 0); + card = (sdla_t*)wp->card; + for(x=0;xmax_timeslots;x++){ + if (wan_test_bit(x, &wp->rbs_tx_status)){ + card->wandev.fe_iface.set_rbsbits( + &wp->card->fe, + x+1, + wp->rbs_tx[x]); + wan_clear_bit(x, &wp->rbs_tx_status); + if (wan_test_bit(x, &wp->rbs_tx1_status)){ + card->wandev.fe_iface.set_rbsbits( + &wp->card->fe, + x+1, + wp->rbs_tx1[x]); + wan_clear_bit(x, &wp->rbs_tx1_status); + } + } + } +#if 0 + for(x=0;xmax_timeslots;x++){ + if (wan_test_bit(7, &wp->rbs_tx[x])){ + card->wandev.fe_iface.set_rbsbits( + &wp->card->fe, + x+1, + wp->rbs_tx[x]); + wan_clear_bit(7, &wp->rbs_tx[x]); + if (wan_test_bit(7, &wp->rbs_tx1[x])){ + card->wandev.fe_iface.set_rbsbits( + &wp->card->fe, + x+1, + wp->rbs_tx1[x]); + wan_clear_bit(7, &wp->rbs_tx1[x]); + } + } + } +#endif + return 0; +} + +/****************************************************************************** +** wp_tdmv_ioctl() - +** +** OK +*/ +static int +#if defined(__FreeBSD__) || defined(__OpenBSD__) +wp_tdmv_ioctl(struct zt_chan *chan, unsigned int cmd, caddr_t data) +#else +wp_tdmv_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long data) +#endif +{ + int err = -ENOTTY; +#if defined(CONFIG_PRODUCT_WANPIPE_TDM_VOICE_DCHAN) + wp_tdmv_softc_t *wp = NULL; +#endif +#ifdef CONFIG_PRODUCT_WANPIPE_TDM_VOICE_ECHOMASTER + wp_tdmv_softc_t *echo_detect_wp = NULL; + int echo_detect_chan = 0; +#endif + + switch(cmd) + { +#if defined(CONFIG_PRODUCT_WANPIPE_TDM_VOICE_DCHAN) + case ZT_DCHAN_TX: + + WAN_ASSERT(chan == NULL || chan->pvt == NULL); + wp = chan->pvt; + + if (wp->dchan_dev && wp->dchan_dev->hard_start_xmit){ + wp_tdmv_tx_dchan(chan, (int)data); + err=0; + }else{ + err=-EOPNOTSUPP; + } + break; +#endif + +#ifdef CONFIG_PRODUCT_WANPIPE_TDM_VOICE_ECHOMASTER + case SANGOMA_GET_ED_STATE: + DEBUG_ECHO("%s():SANGOMA_GET_ED_STATE\n", __FUNCTION__); + + WAN_ASSERT(chan == NULL || chan->pvt == NULL); + + echo_detect_wp = chan->pvt; + echo_detect_chan = chan->chanpos - 1; + + DEBUG_ECHO("on span: %d, chanpos: %d\n", echo_detect_wp->spanno, + echo_detect_chan); + + if(echo_detect_chan > 30 || echo_detect_chan < 0){ + err=-EOPNOTSUPP; + }else{ + wan_tdmv_t *wan_tdmv = &echo_detect_wp->card->wan_tdmv; + wan_tdmv_rxtx_pwr_t *pwr_rxtx = &wan_tdmv->chan_pwr[echo_detect_chan]; + + DEBUG_ECHO("%s():using %s table.\n", __FUNCTION__, + (chan->xlaw == __zt_mulaw ? "MULAW" : "ALAW")); + + /* This will be used when reporting Echo Cancellation state + from Asterisk CLI. + */ + chan->echo_detect_struct.echo_state = pwr_rxtx->current_state; + + DEBUG_ECHO("echo_state:%s\n", + TDMV_SAMPLE_STATE_DECODE(chan->echo_detect_struct.echo_state)); + + chan->echo_detect_struct.echo_present_samples_number = + pwr_rxtx->echo_present_samples_number_history; + chan->echo_detect_struct.echo_absent_samples_number = + pwr_rxtx->echo_absent_samples_number_history; + } + + err = 0; + break; +#endif /* CONFIG_PRODUCT_WANPIPE_TDM_VOICE_ECHOMASTER */ + + default: + /*DEBUG_EVENT("%s(): uknown cmd!\n", __FUNCTION__);*/ + err = -ENOTTY; + break; + } + return err; +} + +/****************************************************************************** +** wp_tdmv_hwec() - +** +** OK +*/ +static int wp_tdmv_hwec(struct zt_chan *chan, int enable) +{ + wp_tdmv_softc_t *wp = NULL; + sdla_t *card = NULL; + int channel = chan->chanpos; + int err = -EINVAL; + + WAN_ASSERT2(chan == NULL, -ENODEV); + WAN_ASSERT2(chan->pvt == NULL, -ENODEV); + wp = chan->pvt; + WAN_ASSERT2(wp->card == NULL, -ENODEV); + card = wp->card; + + if (card->wandev.ec_enable){ + DEBUG_TDMV("[TDMV]: %s: %s HW echo canceller on channel %d\n", + wp->devname, + (enable) ? "Enable" : "Disable", + channel); + if (!wp->ise1){ + channel--; + } + err = card->wandev.ec_enable(card, enable, channel); + /*card->hwec_enable(card, enable, channel);*/ + } + + return err; +} + +/****************************************************************************** +** wp_tdmv_open() - +** +** OK +*/ +static int wp_tdmv_open(struct zt_chan *chan) +{ + wp_tdmv_softc_t *wp = NULL; + sdla_t *card = NULL; + + WAN_ASSERT2(chan == NULL, -ENODEV); + WAN_ASSERT2(chan->pvt == NULL, -ENODEV); + wp = chan->pvt; + WAN_ASSERT2(wp->card == NULL, -ENODEV); + card = wp->card; + wp->usecount++; + if (wp->usecount == wp->timeslots){ + wan_set_bit(WP_TDMV_RUNNING, &wp->flags); + } + DEBUG_TDMV("%s: Open (usecount=%d, channo=%d, chanpos=%d)...\n", + wp->devname, + wp->usecount, + chan->channo, + chan->chanpos); + return 0; +} + + +/****************************************************************************** +** wp_tdmv_close() - +** +** OK +*/ +static int wp_tdmv_close(struct zt_chan *chan) +{ + wp_tdmv_softc_t* wp = NULL; + + WAN_ASSERT2(chan == NULL, -ENODEV); + WAN_ASSERT2(chan->pvt == NULL, -ENODEV); + wp = chan->pvt; + wp->usecount--; + wan_clear_bit(WP_TDMV_RUNNING, &wp->flags); + DEBUG_TDMV("%s: Close (usecount=%d, channo=%d, chanpos=%d)...\n", + wp->devname, + wp->usecount, + chan->channo, + chan->chanpos); + return 0; +} + +/****************************************************************************** +** wp_tdmv_release() - +** +** OK +*/ +static void wp_tdmv_release(wp_tdmv_softc_t *wp) +{ + WAN_ASSERT1(wp == NULL); + if (wan_test_bit(WP_TDMV_REGISTER, &wp->flags)){ + DEBUG_EVENT("%s: Unregister Wanpipe device from Zaptel!\n", + wp->devname); + wan_clear_bit(WP_TDMV_SIG_POLL, &wp->flags); + wan_clear_bit(WP_TDMV_REGISTER, &wp->flags); + zt_unregister(&wp->span); + wan_clear_bit(WP_TDMV_REGISTER, &wp->flags); + } + wan_free(wp); +} + +static inline void start_alarm(wp_tdmv_softc_t* wp) +{ + WAN_ASSERT1(wp == NULL); +#ifdef FANCY_ALARM + wp->alarmpos = 0; +#endif + wp->blinktimer = 0; +} + +static inline void stop_alarm(wp_tdmv_softc_t* wp) +{ + WAN_ASSERT1(wp == NULL); +#ifdef FANCY_ALARM + wp->alarmpos = 0; +#endif + wp->blinktimer = 0; +} + +/************************************************************************************ + * Channelized code for rx/tx + * *********************************************************************************/ + +#if defined(CONFIG_PRODUCT_WANPIPE_TDM_VOICE_DCHAN) +/****************************************************************************** +** wp_tdmv_rx_dchan() - +** +** OK +*/ +static int wp_tdmv_rx_dchan(wan_tdmv_t *wan_tdmv, int channo, + unsigned char *rxbuf, unsigned int len) +{ + wp_tdmv_softc_t *wp = wan_tdmv->sc; + struct zt_chan *chan = NULL, *ms = NULL; + wan_smp_flag_t smp_flags; + unsigned char *buf = NULL; + int oldbuf; + int i, left; + + WAN_ASSERT(wp == NULL); + WAN_ASSERT(channo != wp->dchan-1); + chan = &wp->chans[wp->dchan-1]; + WAN_ASSERT(chan == NULL || chan->master == NULL); + ms = chan->master; + + if (!IS_TDMV_UP(wp)){ + DEBUG_TDMV("%s: Asterisk is not running!\n", + wp->devname); + return -EINVAL; + } + if (!(ms->flags & ZT_FLAG_HDLC)){ + DEBUG_TDMV("%s: ERROR: %s not defined as D-CHAN!\n", + wp->devname, ms->name); + return -EINVAL; + } + + if (ms->inreadbuf < 0){ + return -EINVAL; + } + + if (ms->inreadbuf >= ZT_MAX_NUM_BUFS){ + DEBUG_EVENT("%s: RX buffer (%s) is out of range (%d-%d)!\n", + wp->devname, ms->name, ms->inreadbuf,ZT_MAX_NUM_BUFS); + return -EINVAL; + } + + /* FIXME wan_spin_lock_irqsave(&wp->tx_rx_lock, smp_flags); */ + wan_spin_lock_irq(&chan->lock, &smp_flags); + buf = ms->readbuf[ms->inreadbuf]; + left = ms->blocksize - ms->readidx[ms->inreadbuf]; + if (len + 2 > left) { + DEBUG_EVENT("%s: ERROR: Not ehough space for RX HDLC packet (%d:%d)!\n", + wp->devname, len+2, left); + wan_spin_unlock_irq(&chan->lock, &smp_flags); + return -EINVAL; + } + for(i = 0; i < len; i++){ + buf[ms->readidx[ms->inreadbuf]++] = rxbuf[i]; + } + /* Add extra 2 bytes for checksum */ + buf[ms->readidx[ms->inreadbuf]++] = 0x00; + buf[ms->readidx[ms->inreadbuf]++] = 0x00; + + oldbuf = ms->inreadbuf; + ms->readn[ms->inreadbuf] = ms->readidx[ms->inreadbuf]; + ms->inreadbuf = (ms->inreadbuf + 1) % ms->numbufs; + if (ms->inreadbuf == ms->outreadbuf) { + /* Whoops, we're full, and have no where else + to store into at the moment. We'll drop it + until there's a buffer available */ + ms->inreadbuf = -1; + /* Enable the receiver in case they've got POLICY_WHEN_FULL */ + ms->rxdisable = 0; + } + if (ms->outreadbuf < 0) { /* start out buffer if not already */ + ms->outreadbuf = oldbuf; + } + /* FIXME wan_spin_unlock_irq(&wp->tx_rx_lock, &smp_flags); */ + wan_spin_unlock_irq(&chan->lock, &smp_flags); + if (!ms->rxdisable) { /* if receiver enabled */ + DEBUG_TDMV("%s: HDLC block is ready!\n", + wp->devname); + /* Notify a blocked reader that there is data available + to be read, unless we're waiting for it to be full */ +#if defined(__LINUX__) + wake_up_interruptible(&ms->readbufq); + wake_up_interruptible(&ms->sel); + if (ms->iomask & ZT_IOMUX_READ) + wake_up_interruptible(&ms->eventbufq); +#elif defined(__FreeBSD__) || defined(__OpenBSD__) + wakeup(&ms->readbufq); + wakeup(&ms->sel); + if (ms->iomask & ZT_IOMUX_READ) + wakeup(&ms->eventbufq); + +#endif + } + return 0; +} +#endif + +#if defined(CONFIG_PRODUCT_WANPIPE_TDM_VOICE_DCHAN) +static int wp_tdmv_tx_dchan(struct zt_chan *chan, int len) +{ + wp_tdmv_softc_t *wp = NULL; + netskb_t *skb = NULL; + wan_smp_flag_t smp_flags; + unsigned char *data = NULL; + int err = 0; + + WAN_ASSERT2(chan == NULL, -ENODEV); + WAN_ASSERT2(chan->pvt == NULL, -ENODEV); + wp = chan->pvt; + WAN_ASSERT(wp->dchan_dev == NULL); + + wan_spin_lock_irq(&chan->lock, &smp_flags); + if (len <= 2){ + wan_spin_unlock_irq(&chan->lock, &smp_flags); + return -EINVAL; + } + len -= 2; /* Remove checksum */ + skb = wan_skb_alloc(len+1); + if (skb == NULL){ + wan_spin_unlock_irq(&chan->lock, &smp_flags); + return -ENOMEM; + } + data = wan_skb_put(skb, len); + memcpy(data, chan->writebuf[chan->inwritebuf], len); +#if 0 + { + int i; + DEBUG_EVENT("TX DCHAN: "); + for(i = 0; i < len; i++){ + _DEBUG_EVENT("%02X ", data[i]); + } + _DEBUG_EVENT("\n"); + } +#endif + wan_spin_unlock_irq(&chan->lock, &smp_flags); + if (skb){ + err = wp->dchan_dev->hard_start_xmit(skb, wp->dchan_dev); + if (err){ + wan_skb_free(skb); + } + } + + return err; +} +#endif + + +/****************************************************************************** +** wp_tdmv_rx_chan() - +** +** OK +*/ +static int wp_tdmv_rx_chan(wan_tdmv_t *wan_tdmv, int channo, + unsigned char *rxbuf, + unsigned char *txbuf) +{ + wp_tdmv_softc_t *wp = wan_tdmv->sc; + + WAN_ASSERT2(wp == NULL, -EINVAL); + WAN_ASSERT2(channo < 0, -EINVAL); + WAN_ASSERT2(channo > 31, -EINVAL); + + if (!IS_TDMV_UP(wp)){ + return -EINVAL; + } + + if (wp->channelized == WAN_TRUE){ +#ifdef CONFIG_PRODUCT_WANPIPE_TDM_VOICE_ECHOMASTER + wan_tdmv_rxtx_pwr_t *pwr_rxtx = &wan_tdmv->chan_pwr[channo]; +#endif + + wp->chans[channo].readchunk = rxbuf; + wp->chans[channo].writechunk = txbuf; + +#ifdef CONFIG_PRODUCT_WANPIPE_TDM_VOICE_ECHOMASTER + wp_tdmv_echo_check(wan_tdmv, &wp->chans[channo], channo); +#endif + + if (!wan_test_bit(channo, &wp->echo_off_map)){ +/*Echo spike starts at 25bytes*/ +#ifdef CONFIG_PRODUCT_WANPIPE_TDM_VOICE_ECHOMASTER + if(pwr_rxtx->current_state != ECHO_ABSENT){ +#endif +#if 0 +/* Echo spike starts at 16 bytes */ + + zt_ec_chunk( + &wp->chans[channo], + wp->chans[channo].readchunk, + wp->chans[channo].writechunk); +#endif + +#if 1 +/*Echo spike starts at 9 bytes*/ + zt_ec_chunk( + &wp->chans[channo], + wp->chans[channo].readchunk, + wp->ec_chunk1[channo]); + memcpy( + wp->ec_chunk1[channo], + wp->chans[channo].writechunk, + ZT_CHUNKSIZE); +#endif + +#if 0 +/*Echo spike starts at bytes*/ + zt_ec_chunk( + &wp->chans[channo], + wp->chans[channo].readchunk, + wp->ec_chunk1[channo]); + memcpy( + wp->ec_chunk1[channo], + wp->ec_chunk2[channo], + ZT_CHUNKSIZE); + + memcpy( + wp->ec_chunk2[channo], + wp->chans[channo].writechunk, + ZT_CHUNKSIZE); +#endif + +#ifdef CONFIG_PRODUCT_WANPIPE_TDM_VOICE_ECHOMASTER + } /* if(pwr_rxtx->current_state != ECHO_ABSENT) */ +#endif + } /* if (!wan_test_bit(channo, &wp->echo_off_map)) */ + }else{ + int x, channels = wp->span.channels; + + wp->tx_unchan = txbuf; + wp_tdmv_rxcopy(wan_tdmv, rxbuf, wp->max_rxtx_len); + + if (!wp->echo_off_map){ + for (x = 0; x < channels; x++){ +#if 0 + /* This code never runs. Instead wp_tdmv_rx_chan() + ** is called for A101/A102. All Echo Detection is + ** done there for A101/A102. */ + wp_tdmv_echo_check(wan_tdmv, &wp->chans[0], x); +#endif + + zt_ec_chunk( + &wp->chans[x], + wp->chans[x].readchunk, + wp->chans[x].writechunk); + +#if 0 + zt_ec_chunk( + &wp->chans[x], + wp->chans[x].readchunk, + wp->ec_chunk1[x]); + memcpy( + wp->ec_chunk1[x], + wp->chans[x].writechunk, + ZT_CHUNKSIZE); +#endif + } + }/* if() */ + }/* if() */ + + return 0; +} + +/****************************************************************************** +** wp_tdmv_rx_tx_span() - +** +** OK +*/ +static int wp_tdmv_rx_tx_span(void *pcard) +{ + sdla_t *card = (sdla_t*)pcard; + wan_tdmv_t *wan_tdmv = &card->wan_tdmv; + wp_tdmv_softc_t *wp = NULL; + + WAN_ASSERT(wan_tdmv->sc == NULL); + wp = wan_tdmv->sc; + + wp->intcount++; + zt_receive(&wp->span); + zt_transmit(&wp->span); + + if (wp->channelized == WAN_FALSE){ + wp_tdmv_txcopy(wan_tdmv, + wp->tx_unchan, + wp->max_rxtx_len); + } + + if (wan_test_bit(WP_TDMV_RBS_UPDATE, &wp->flags)){ + DEBUG_TEST("%s: %s:%d: Updating RBS status \n", + wp->devname, + __FUNCTION__,__LINE__); + if (card->wandev.fe_iface.report_rbsbits){ + card->wandev.fe_iface.report_rbsbits(&card->fe); + } + wan_clear_bit(WP_TDMV_RBS_UPDATE, &wp->flags); + wan_clear_bit(WP_TDMV_RBS_BUSY, &wp->flags); + } + return 0; +} + + +/****************************************************************************** +** wp_tdmv_init() - +* +** OK +*/ +static int wp_tdmv_init(void* pcard, wanif_conf_t *conf) +{ + return -EINVAL; +} + diff -Nur linux.org/drivers/net/wan/sdla_te1.c linux-2.6.17/drivers/net/wan/sdla_te1.c --- linux.org/drivers/net/wan/sdla_te1.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/drivers/net/wan/sdla_te1.c 2006-08-30 10:07:16.000000000 +0000 @@ -0,0 +1,7250 @@ +/* + * Copyright (c) 2001 + * Alex Feldman . All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Alex Feldman. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Alex Feldman AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Alex Feldman OR THE VOICES IN HIS HEAD + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + * $Id$ + */ + +/* + ****************************************************************************** + * sdla_te1.c WANPIPE(tm) Multiprotocol WAN Link Driver. + * T1/E1 board configuration. + * + * Author: Alex Feldman + * + * ============================================================================ + * Aprl 29, 2001 Alex Feldma Initial version. + ****************************************************************************** + */ + +/****************************************************************************** +* INCLUDE FILES +******************************************************************************/ +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) +# include +# if !defined(CONFIG_PRODUCT_WANPIPE_GENERIC) +# include +# endif +# include +# include /* WANPIPE common user API definitions */ +# include +#elif (defined __WINDOWS__) +# include +# include /* WANPIPE common user API definitions */ +# include +# include +# if defined te_cfg +# undef te_cfg +# endif +#elif (defined __LINUX__) || (defined __KERNEL__) +# include +# include +# include +# include +# if !defined(CONFIG_PRODUCT_WANPIPE_GENERIC) +# include +# endif +# include +# include /* WANPIPE common user API definitions */ +#else +# error "No OS Defined" +#endif + +/****************************************************************************** +* DEFINES AND MACROS +******************************************************************************/ +#define FIRST_SAMPLE 0 +#define LAST_SAMPLE 23 +#define FIRST_UI 0 +#define LAST_UI 4 + +#define MAX_BUSY_READ 0x05 + +/* Read/Write to front-end register */ +#define WRITE_REG(reg,val) \ + fe->write_fe_reg( \ + fe->card, \ + (int)((reg) + (fe->fe_cfg.line_no*PMC4_LINE_DELTA)), \ + (int)(val)) + +#define WRITE_REG_LINE(fe_line_no, reg,val) \ + fe->write_fe_reg( \ + fe->card, \ + (int)((reg) + (fe_line_no)*PMC4_LINE_DELTA), \ + (int)(val)) + +#define READ_REG(reg) \ + fe->read_fe_reg( \ + fe->card, \ + (int)((reg) + (fe->fe_cfg.line_no*PMC4_LINE_DELTA))) + +#define READ_REG_LINE(fe_line_no, reg) \ + fe->read_fe_reg( \ + fe->card, \ + (int)((reg) + (fe_line_no)*PMC4_LINE_DELTA)) + +/* Enabling/Disabling register debugging */ +#undef WAN_DEBUG_TE1_REG +#ifdef WAN_DEBUG_TE1_REG + +# define TEST_REG(reg,value){ \ + unsigned char test_value = READ_REG(reg); \ + if (test_value != value){ \ + DEBUG_EVENT("%s:%d: Test Failed\n", \ + __FILE__,__LINE__); \ + DEBUG_EVENT("%s:%d: (Reg=%02x, Val=%02x)\n", \ + reg, value); \ + } \ +} + +# define TEST_RPSC_REG(fe,reg,channel,value){ \ + unsigned char test_value = ReadRPSCReg(fe,channel,reg); \ + if (test_value != value){ \ + DEBUG_EVENT("%s:%d: RPSC Test Failed\n", \ + __FILE__, __LINE__); \ + DEBUG_EVENT("%s:%d: (Reg=%02x,Channel=%d,Val=%02x)\n", \ + reg, channel, value); \ + } \ +} + +# define TEST_TPSC_REG(fe,reg,channel,value){ \ + unsigned char test_value = ReadTPSCReg(fe,channel,reg); \ + if (test_value != value){ \ + DEBUG_EVENT("%s:%d: TPSC Test Failed\n", \ + __FILE__, __LINE__); \ + DEBUG_EVENT("%s:%d: (Reg=%02x,Channel=%d,Val=%02x)\n", \ + reg, channel, value); \ + } \ +} + +#else +# define TEST_REG(reg,value) +# define TEST_RPSC_REG(fe,reg,channel,value) +# define TEST_TPSC_REG(fe,reg,channel,value) +#endif + +#if 0 +#define READ_REG(reg) card->wandev.read_front_end_reg(card,reg) +#define WRITE_REG(reg,value) card->wandev.write_front_end_reg(card,reg,(unsigned char)(value)) +#endif +#define READ_RPSC_REG(reg,channel) ReadRPSCReg(fe,reg,channel) +#define READ_TPSC_REG(reg,channel) ReadTPSCReg(fe,reg,channel) +#define READ_SIGX_REG(reg,channel) ReadSIGXReg(fe,reg,channel) +#define WRITE_RPSC_REG(reg,channel,value) \ + { \ + WriteRPSCReg(fe,reg,channel,(unsigned char)value); \ + TEST_RPSC_REG(fe,reg,channel,(unsigned char)value); \ + } + +#define WRITE_TPSC_REG(reg,channel,value) \ + { \ + WriteTPSCReg(fe,reg,channel,(unsigned char)value); \ + TEST_TPSC_REG(fe,reg,channe,(unsigned char)value); \ + } + +#if 0 +#define WRITE_SIGX_REG(reg,channel,value) \ + { \ + WriteSIGXReg(fe,reg,channel,(unsigned char)value); \ + TEST_SIGX_REG(fe,reg,channel,(unsigned char)value); \ + } +#endif + +#define IS_T1_ALARM(alarm) \ + (alarm & \ + ( \ + WAN_TE_BIT_RED_ALARM | \ + WAN_TE_BIT_AIS_ALARM | \ + WAN_TE_BIT_OOF_ALARM | \ + WAN_TE_BIT_LOS_ALARM \ + )) + +#define IS_E1_ALARM(alarm) \ + (alarm & \ + ( \ + WAN_TE_BIT_RED_ALARM | \ + WAN_TE_BIT_AIS_ALARM | \ + WAN_TE_BIT_OOF_ALARM | \ + WAN_TE_BIT_LOS_ALARM \ + )) + +#if 0 +# define FE_ALOS_ENABLE + +# define FE_OOF_PRINT +# define FE_LOS_PRINT +# define FE_ALOS_PRINT +#endif + +/****************************************************************************** +* STRUCTURES AND TYPEDEFS +******************************************************************************/ +typedef unsigned char TX_WAVEFORM[LAST_SAMPLE-FIRST_SAMPLE+1][LAST_UI-FIRST_UI+1]; +typedef struct RLPS_EQUALIZER_RAM_T { + /*unsigned char address;*/ + unsigned char byte1; + unsigned char byte2; + unsigned char byte3; + unsigned char byte4; +} RLPS_EQUALIZER_RAM; + +/* + ****************************************************************************** + GLOBAL VARIABLES + ****************************************************************************** +*/ + + +/* Transmit Waveform Values for T1 Long Haul (LBO 0db) + * unsigned char t1_tx_waveform_lh_0db[LAST_SAMPLE-FIRST_SAMPLE+1][LAST_UI-FIRST_UI+1] = + */ +TX_WAVEFORM pmc_t1_tx_waveform_lh_0db = +{ + { 0x00, 0x44, 0x00, 0x00, 0x00 }, + { 0x0A, 0x44, 0x00, 0x00, 0x00 }, + { 0x20, 0x43, 0x00, 0x00, 0x00 }, + { 0x32, 0x43, 0x00, 0x00, 0x00 }, + { 0x3E, 0x42, 0x00, 0x00, 0x00 }, + { 0x3D, 0x42, 0x00, 0x00, 0x00 }, + { 0x3C, 0x41, 0x00, 0x00, 0x00 }, + { 0x3B, 0x41, 0x00, 0x00, 0x00 }, + { 0x3A, 0x00, 0x00, 0x00, 0x00 }, + { 0x39, 0x00, 0x00, 0x00, 0x00 }, + { 0x39, 0x00, 0x00, 0x00, 0x00 }, + { 0x38, 0x00, 0x00, 0x00, 0x00 }, + { 0x37, 0x00, 0x00, 0x00, 0x00 }, + { 0x36, 0x00, 0x00, 0x00, 0x00 }, + { 0x34, 0x00, 0x00, 0x00, 0x00 }, + { 0x29, 0x00, 0x00, 0x00, 0x00 }, + { 0x4F, 0x00, 0x00, 0x00, 0x00 }, + { 0x4C, 0x00, 0x00, 0x00, 0x00 }, + { 0x4A, 0x00, 0x00, 0x00, 0x00 }, + { 0x49, 0x00, 0x00, 0x00, 0x00 }, + { 0x47, 0x00, 0x00, 0x00, 0x00 }, + { 0x47, 0x00, 0x00, 0x00, 0x00 }, + { 0x46, 0x00, 0x00, 0x00, 0x00 }, + { 0x46, 0x00, 0x00, 0x00, 0x00 } +}; +TX_WAVEFORM pmc4_t1_tx_waveform_lh_0db = +{ + { 0x00, 0x46, 0x00, 0x00, 0x00 }, + { 0x0A, 0x45, 0x00, 0x00, 0x00 }, + { 0x20, 0x43, 0x00, 0x00, 0x00 }, + { 0x32, 0x41, 0x00, 0x00, 0x00 }, + { 0x3E, 0x40, 0x00, 0x00, 0x00 }, + { 0x3D, 0x40, 0x00, 0x00, 0x00 }, + { 0x3C, 0x00, 0x00, 0x00, 0x00 }, + { 0x3B, 0x00, 0x00, 0x00, 0x00 }, + { 0x3A, 0x00, 0x00, 0x00, 0x00 }, + { 0x39, 0x00, 0x00, 0x00, 0x00 }, + { 0x39, 0x00, 0x00, 0x00, 0x00 }, + { 0x38, 0x00, 0x00, 0x00, 0x00 }, + { 0x37, 0x00, 0x00, 0x00, 0x00 }, + { 0x36, 0x00, 0x00, 0x00, 0x00 }, + { 0x30, 0x00, 0x00, 0x00, 0x00 }, + { 0x10, 0x00, 0x00, 0x00, 0x00 }, + { 0x49, 0x00, 0x00, 0x00, 0x00 }, + { 0x51, 0x00, 0x00, 0x00, 0x00 }, + { 0x50, 0x00, 0x00, 0x00, 0x00 }, + { 0x4E, 0x00, 0x00, 0x00, 0x00 }, + { 0x4C, 0x00, 0x00, 0x00, 0x00 }, + { 0x4A, 0x00, 0x00, 0x00, 0x00 }, + { 0x48, 0x00, 0x00, 0x00, 0x00 }, + { 0x47, 0x00, 0x00, 0x00, 0x00 } +}; + +/* Transmit Waveform Values for T1 Long Haul (LBO 7.5 dB): + * unsigned char t1_tx_waveform_lh_75db[LAST_SAMPLE-FIRST_SAMPLE+1][LAST_UI-FIRST_UI+1] = + */ +TX_WAVEFORM pmc_t1_tx_waveform_lh_75db = +{ + { 0x00, 0x10, 0x00, 0x00, 0x00 }, + { 0x01, 0x0E, 0x00, 0x00, 0x00 }, + { 0x02, 0x0C, 0x00, 0x00, 0x00 }, + { 0x04, 0x0A, 0x00, 0x00, 0x00 }, + { 0x08, 0x08, 0x00, 0x00, 0x00 }, + { 0x0C, 0x06, 0x00, 0x00, 0x00 }, + { 0x10, 0x04, 0x00, 0x00, 0x00 }, + { 0x16, 0x02, 0x00, 0x00, 0x00 }, + { 0x1A, 0x01, 0x00, 0x00, 0x00 }, + { 0x1E, 0x00, 0x00, 0x00, 0x00 }, + { 0x22, 0x00, 0x00, 0x00, 0x00 }, + { 0x26, 0x00, 0x00, 0x00, 0x00 }, + { 0x2A, 0x00, 0x00, 0x00, 0x00 }, + { 0x2B, 0x00, 0x00, 0x00, 0x00 }, + { 0x2C, 0x00, 0x00, 0x00, 0x00 }, + { 0x2D, 0x00, 0x00, 0x00, 0x00 }, + { 0x2C, 0x00, 0x00, 0x00, 0x00 }, + { 0x28, 0x00, 0x00, 0x00, 0x00 }, + { 0x24, 0x00, 0x00, 0x00, 0x00 }, + { 0x20, 0x00, 0x00, 0x00, 0x00 }, + { 0x1C, 0x00, 0x00, 0x00, 0x00 }, + { 0x18, 0x00, 0x00, 0x00, 0x00 }, + { 0x14, 0x00, 0x00, 0x00, 0x00 }, + { 0x12, 0x00, 0x00, 0x00, 0x00 } +}; +TX_WAVEFORM pmc4_t1_tx_waveform_lh_75db = +{ + { 0x00, 0x10, 0x00, 0x00, 0x00 }, + { 0x01, 0x0E, 0x00, 0x00, 0x00 }, + { 0x02, 0x0C, 0x00, 0x00, 0x00 }, + { 0x04, 0x0A, 0x00, 0x00, 0x00 }, + { 0x08, 0x08, 0x00, 0x00, 0x00 }, + { 0x0C, 0x06, 0x00, 0x00, 0x00 }, + { 0x10, 0x04, 0x00, 0x00, 0x00 }, + { 0x16, 0x02, 0x00, 0x00, 0x00 }, + { 0x1A, 0x01, 0x00, 0x00, 0x00 }, + { 0x1E, 0x00, 0x00, 0x00, 0x00 }, + { 0x22, 0x00, 0x00, 0x00, 0x00 }, + { 0x26, 0x00, 0x00, 0x00, 0x00 }, + { 0x2A, 0x00, 0x00, 0x00, 0x00 }, + { 0x2B, 0x00, 0x00, 0x00, 0x00 }, + { 0x2C, 0x00, 0x00, 0x00, 0x00 }, + { 0x2D, 0x00, 0x00, 0x00, 0x00 }, + { 0x2C, 0x00, 0x00, 0x00, 0x00 }, + { 0x28, 0x00, 0x00, 0x00, 0x00 }, + { 0x24, 0x00, 0x00, 0x00, 0x00 }, + { 0x20, 0x00, 0x00, 0x00, 0x00 }, + { 0x1C, 0x00, 0x00, 0x00, 0x00 }, + { 0x18, 0x00, 0x00, 0x00, 0x00 }, + { 0x14, 0x00, 0x00, 0x00, 0x00 }, + { 0x12, 0x00, 0x00, 0x00, 0x00 } +}; + + +/* Transmit Waveform Values for T1 Long Haul (LBO 15 dB) + * unsigned char t1_tx_waveform_lh_15db[LAST_SAMPLE-FIRST_SAMPLE+1][LAST_UI-FIRST_UI+1] = + */ +TX_WAVEFORM pmc_t1_tx_waveform_lh_15db = +{ + { 0x00, 0x2A, 0x09, 0x01, 0x00 }, + { 0x00, 0x28, 0x08, 0x01, 0x00 }, + { 0x00, 0x26, 0x08, 0x01, 0x00 }, + { 0x00, 0x24, 0x07, 0x01, 0x00 }, + { 0x01, 0x22, 0x07, 0x01, 0x00 }, + { 0x02, 0x20, 0x06, 0x01, 0x00 }, + { 0x04, 0x1E, 0x06, 0x01, 0x00 }, + { 0x07, 0x1C, 0x05, 0x00, 0x00 }, + { 0x0A, 0x1B, 0x05, 0x00, 0x00 }, + { 0x0D, 0x19, 0x05, 0x00, 0x00 }, + { 0x10, 0x18, 0x04, 0x00, 0x00 }, + { 0x14, 0x16, 0x04, 0x00, 0x00 }, + { 0x18, 0x15, 0x04, 0x00, 0x00 }, + { 0x1B, 0x13, 0x03, 0x00, 0x00 }, + { 0x1E, 0x12, 0x03, 0x00, 0x00 }, + { 0x21, 0x10, 0x03, 0x00, 0x00 }, + { 0x24, 0x0F, 0x03, 0x00, 0x00 }, + { 0x27, 0x0D, 0x03, 0x00, 0x00 }, + { 0x2A, 0x0D, 0x02, 0x00, 0x00 }, + { 0x2D, 0x0B, 0x02, 0x00, 0x00 }, + { 0x30, 0x0B, 0x02, 0x00, 0x00 }, + { 0x30, 0x0A, 0x02, 0x00, 0x00 }, + { 0x2E, 0x0A, 0x02, 0x00, 0x00 }, + { 0x2C, 0x09, 0x02, 0x00, 0x00 } +}; +TX_WAVEFORM pmc4_t1_tx_waveform_lh_15db = +{ + { 0x00, 0x2A, 0x09, 0x01, 0x00 }, + { 0x00, 0x28, 0x08, 0x01, 0x00 }, + { 0x00, 0x26, 0x08, 0x01, 0x00 }, + { 0x00, 0x24, 0x07, 0x01, 0x00 }, + { 0x01, 0x22, 0x07, 0x01, 0x00 }, + { 0x02, 0x20, 0x06, 0x01, 0x00 }, + { 0x04, 0x1E, 0x06, 0x01, 0x00 }, + { 0x07, 0x1C, 0x05, 0x00, 0x00 }, + { 0x0A, 0x1B, 0x05, 0x00, 0x00 }, + { 0x0D, 0x19, 0x05, 0x00, 0x00 }, + { 0x10, 0x18, 0x04, 0x00, 0x00 }, + { 0x14, 0x16, 0x04, 0x00, 0x00 }, + { 0x18, 0x15, 0x04, 0x00, 0x00 }, + { 0x1B, 0x13, 0x03, 0x00, 0x00 }, + { 0x1E, 0x12, 0x03, 0x00, 0x00 }, + { 0x21, 0x10, 0x03, 0x00, 0x00 }, + { 0x24, 0x0F, 0x03, 0x00, 0x00 }, + { 0x27, 0x0D, 0x03, 0x00, 0x00 }, + { 0x2A, 0x0D, 0x02, 0x00, 0x00 }, + { 0x2D, 0x0B, 0x02, 0x00, 0x00 }, + { 0x30, 0x0B, 0x02, 0x00, 0x00 }, + { 0x30, 0x0A, 0x02, 0x00, 0x00 }, + { 0x2E, 0x0A, 0x02, 0x00, 0x00 }, + { 0x2C, 0x09, 0x02, 0x00, 0x00 } +}; + + +/* Transmit Waveform Values for T1 Long Haul (LBO 22.5 dB) + * unsigned char t1_tx_waveform_lh_225db[LAST_SAMPLE-FIRST_SAMPLE+1][LAST_UI-FIRST_UI+1] = + */ +TX_WAVEFORM pmc_t1_tx_waveform_lh_225db = +{ + { 0x00, 0x1F, 0x16, 0x06, 0x01 }, + { 0x00, 0x20, 0x15, 0x05, 0x01 }, + { 0x00, 0x21, 0x15, 0x05, 0x01 }, + { 0x00, 0x22, 0x14, 0x05, 0x01 }, + { 0x00, 0x22, 0x13, 0x04, 0x00 }, + { 0x00, 0x23, 0x12, 0x04, 0x00 }, + { 0x01, 0x23, 0x12, 0x04, 0x00 }, + { 0x01, 0x24, 0x11, 0x03, 0x00 }, + { 0x01, 0x23, 0x10, 0x03, 0x00 }, + { 0x02, 0x23, 0x10, 0x03, 0x00 }, + { 0x03, 0x22, 0x0F, 0x03, 0x00 }, + { 0x05, 0x22, 0x0E, 0x03, 0x00 }, + { 0x07, 0x21, 0x0E, 0x02, 0x00 }, + { 0x09, 0x20, 0x0D, 0x02, 0x00 }, + { 0x0B, 0x1E, 0x0C, 0x02, 0x00 }, + { 0x0E, 0x1D, 0x0C, 0x02, 0x00 }, + { 0x10, 0x1B, 0x0B, 0x02, 0x00 }, + { 0x13, 0x1B, 0x0A, 0x02, 0x00 }, + { 0x15, 0x1A, 0x0A, 0x02, 0x00 }, + { 0x17, 0x19, 0x09, 0x01, 0x00 }, + { 0x19, 0x19, 0x08, 0x01, 0x00 }, + { 0x1B, 0x18, 0x08, 0x01, 0x00 }, + { 0x1D, 0x17, 0x07, 0x01, 0x00 }, + { 0x1E, 0x17, 0x06, 0x01, 0x00 } +}; +TX_WAVEFORM pmc4_t1_tx_waveform_lh_225db = +{ + { 0x00, 0x1F, 0x16, 0x06, 0x01 }, + { 0x00, 0x20, 0x15, 0x05, 0x01 }, + { 0x00, 0x21, 0x15, 0x05, 0x01 }, + { 0x00, 0x22, 0x14, 0x05, 0x01 }, + { 0x00, 0x22, 0x13, 0x04, 0x00 }, + { 0x00, 0x23, 0x12, 0x04, 0x00 }, + { 0x01, 0x23, 0x12, 0x04, 0x00 }, + { 0x01, 0x24, 0x11, 0x03, 0x00 }, + { 0x01, 0x23, 0x10, 0x03, 0x00 }, + { 0x02, 0x23, 0x10, 0x03, 0x00 }, + { 0x03, 0x22, 0x0F, 0x03, 0x00 }, + { 0x05, 0x22, 0x0E, 0x03, 0x00 }, + { 0x07, 0x21, 0x0E, 0x02, 0x00 }, + { 0x09, 0x20, 0x0D, 0x02, 0x00 }, + { 0x0B, 0x1E, 0x0C, 0x02, 0x00 }, + { 0x0E, 0x1D, 0x0C, 0x02, 0x00 }, + { 0x10, 0x1B, 0x0B, 0x02, 0x00 }, + { 0x13, 0x1B, 0x0A, 0x02, 0x00 }, + { 0x15, 0x1A, 0x0A, 0x02, 0x00 }, + { 0x17, 0x19, 0x09, 0x01, 0x00 }, + { 0x19, 0x19, 0x08, 0x01, 0x00 }, + { 0x1B, 0x18, 0x08, 0x01, 0x00 }, + { 0x1D, 0x17, 0x07, 0x01, 0x00 }, + { 0x1E, 0x17, 0x06, 0x01, 0x00 } +}; + + +/* Transmit Waveform Values for T1 Short Haul (0 - 110 ft.) + * unsigned char t1_tx_waveform_sh_110ft[LAST_SAMPLE-FIRST_SAMPLE+1][LAST_UI-FIRST_UI+1] = + */ +TX_WAVEFORM pmc_t1_tx_waveform_sh_110ft = +{ + { 0x00, 0x45, 0x00, 0x00, 0x00 }, + { 0x0A, 0x44, 0x00, 0x00, 0x00 }, + { 0x20, 0x43, 0x00, 0x00, 0x00 }, + { 0x3F, 0x43, 0x00, 0x00, 0x00 }, + { 0x3F, 0x42, 0x00, 0x00, 0x00 }, + { 0x3F, 0x42, 0x00, 0x00, 0x00 }, + { 0x3C, 0x41, 0x00, 0x00, 0x00 }, + { 0x3B, 0x41, 0x00, 0x00, 0x00 }, + { 0x3A, 0x00, 0x00, 0x00, 0x00 }, + { 0x39, 0x00, 0x00, 0x00, 0x00 }, + { 0x39, 0x00, 0x00, 0x00, 0x00 }, + { 0x38, 0x00, 0x00, 0x00, 0x00 }, + { 0x37, 0x00, 0x00, 0x00, 0x00 }, + { 0x36, 0x00, 0x00, 0x00, 0x00 }, + { 0x34, 0x00, 0x00, 0x00, 0x00 }, + { 0x29, 0x00, 0x00, 0x00, 0x00 }, + { 0x59, 0x00, 0x00, 0x00, 0x00 }, + { 0x55, 0x00, 0x00, 0x00, 0x00 }, + { 0x50, 0x00, 0x00, 0x00, 0x00 }, + { 0x4D, 0x00, 0x00, 0x00, 0x00 }, + { 0x4A, 0x00, 0x00, 0x00, 0x00 }, + { 0x48, 0x00, 0x00, 0x00, 0x00 }, + { 0x46, 0x00, 0x00, 0x00, 0x00 }, + { 0x46, 0x00, 0x00, 0x00, 0x00 } +}; +TX_WAVEFORM pmc4_t1_tx_waveform_sh_110ft = +{ + { 0x00, 0x46, 0x00, 0x00, 0x00 }, + { 0x0A, 0x45, 0x00, 0x00, 0x00 }, + { 0x20, 0x43, 0x00, 0x00, 0x00 }, + { 0x3D, 0x41, 0x00, 0x00, 0x00 }, + { 0x3D, 0x40, 0x00, 0x00, 0x00 }, + { 0x3C, 0x40, 0x00, 0x00, 0x00 }, + { 0x3C, 0x00, 0x00, 0x00, 0x00 }, + { 0x3B, 0x00, 0x00, 0x00, 0x00 }, + { 0x3A, 0x00, 0x00, 0x00, 0x00 }, + { 0x39, 0x00, 0x00, 0x00, 0x00 }, + { 0x39, 0x00, 0x00, 0x00, 0x00 }, + { 0x38, 0x00, 0x00, 0x00, 0x00 }, + { 0x37, 0x00, 0x00, 0x00, 0x00 }, + { 0x36, 0x00, 0x00, 0x00, 0x00 }, + { 0x30, 0x00, 0x00, 0x00, 0x00 }, + { 0x10, 0x00, 0x00, 0x00, 0x00 }, + { 0x58, 0x00, 0x00, 0x00, 0x00 }, + { 0x53, 0x00, 0x00, 0x00, 0x00 }, + { 0x50, 0x00, 0x00, 0x00, 0x00 }, + { 0x4E, 0x00, 0x00, 0x00, 0x00 }, + { 0x4C, 0x00, 0x00, 0x00, 0x00 }, + { 0x4A, 0x00, 0x00, 0x00, 0x00 }, + { 0x48, 0x00, 0x00, 0x00, 0x00 }, + { 0x47, 0x00, 0x00, 0x00, 0x00 } +}; + + +/* Transmit Waveform Values for T1 Short Haul (110 - 220 ft.) + * unsigned char t1_tx_waveform_sh_220ft[LAST_SAMPLE-FIRST_SAMPLE+1][LAST_UI-FIRST_UI+1] = + */ +TX_WAVEFORM pmc_t1_tx_waveform_sh_220ft = +{ + { 0x00, 0x44, 0x00, 0x00, 0x00 }, + { 0x0A, 0x44, 0x00, 0x00, 0x00 }, + { 0x3F, 0x43, 0x00, 0x00, 0x00 }, + { 0x3F, 0x43, 0x00, 0x00, 0x00 }, + { 0x36, 0x42, 0x00, 0x00, 0x00 }, + { 0x34, 0x42, 0x00, 0x00, 0x00 }, + { 0x30, 0x41, 0x00, 0x00, 0x00 }, + { 0x2F, 0x41, 0x00, 0x00, 0x00 }, + { 0x2E, 0x00, 0x00, 0x00, 0x00 }, + { 0x2D, 0x00, 0x00, 0x00, 0x00 }, + { 0x2C, 0x00, 0x00, 0x00, 0x00 }, + { 0x2B, 0x00, 0x00, 0x00, 0x00 }, + { 0x2A, 0x00, 0x00, 0x00, 0x00 }, + { 0x28, 0x00, 0x00, 0x00, 0x00 }, + { 0x26, 0x00, 0x00, 0x00, 0x00 }, + { 0x4A, 0x00, 0x00, 0x00, 0x00 }, + { 0x68, 0x00, 0x00, 0x00, 0x00 }, + { 0x54, 0x00, 0x00, 0x00, 0x00 }, + { 0x4F, 0x00, 0x00, 0x00, 0x00 }, + { 0x4A, 0x00, 0x00, 0x00, 0x00 }, + { 0x49, 0x00, 0x00, 0x00, 0x00 }, + { 0x47, 0x00, 0x00, 0x00, 0x00 }, + { 0x47, 0x00, 0x00, 0x00, 0x00 }, + { 0x46, 0x00, 0x00, 0x00, 0x00 } +}; +TX_WAVEFORM pmc4_t1_tx_waveform_sh_220ft = +{ + { 0x00, 0x45, 0x00, 0x00, 0x00 }, + { 0x0A, 0x44, 0x00, 0x00, 0x00 }, + { 0x33, 0x42, 0x00, 0x00, 0x00 }, + { 0x33, 0x41, 0x00, 0x00, 0x00 }, + { 0x33, 0x40, 0x00, 0x00, 0x00 }, + { 0x33, 0x40, 0x00, 0x00, 0x00 }, + { 0x30, 0x00, 0x00, 0x00, 0x00 }, + { 0x2F, 0x00, 0x00, 0x00, 0x00 }, + { 0x2E, 0x00, 0x00, 0x00, 0x00 }, + { 0x2D, 0x00, 0x00, 0x00, 0x00 }, + { 0x2C, 0x00, 0x00, 0x00, 0x00 }, + { 0x2B, 0x00, 0x00, 0x00, 0x00 }, + { 0x2A, 0x00, 0x00, 0x00, 0x00 }, + { 0x29, 0x00, 0x00, 0x00, 0x00 }, + { 0x19, 0x00, 0x00, 0x00, 0x00 }, + { 0x5A, 0x00, 0x00, 0x00, 0x00 }, + { 0x54, 0x00, 0x00, 0x00, 0x00 }, + { 0x50, 0x00, 0x00, 0x00, 0x00 }, + { 0x4E, 0x00, 0x00, 0x00, 0x00 }, + { 0x4C, 0x00, 0x00, 0x00, 0x00 }, + { 0x4B, 0x00, 0x00, 0x00, 0x00 }, + { 0x48, 0x00, 0x00, 0x00, 0x00 }, + { 0x48, 0x00, 0x00, 0x00, 0x00 }, + { 0x47, 0x00, 0x00, 0x00, 0x00 } +}; + + +/* Transmit Waveform Values for T1 Short Haul (220 - 330 ft.) + * unsigned char t1_tx_waveform_sh_330ft[LAST_SAMPLE-FIRST_SAMPLE+1][LAST_UI-FIRST_UI+1] = + */ +TX_WAVEFORM pmc_t1_tx_waveform_sh_330ft = +{ + { 0x00, 0x44, 0x00, 0x00, 0x00 }, + { 0x0A, 0x44, 0x00, 0x00, 0x00 }, + { 0x3F, 0x43, 0x00, 0x00, 0x00 }, + { 0x3A, 0x43, 0x00, 0x00, 0x00 }, + { 0x3A, 0x42, 0x00, 0x00, 0x00 }, + { 0x38, 0x42, 0x00, 0x00, 0x00 }, + { 0x30, 0x41, 0x00, 0x00, 0x00 }, + { 0x2F, 0x41, 0x00, 0x00, 0x00 }, + { 0x2E, 0x00, 0x00, 0x00, 0x00 }, + { 0x2D, 0x00, 0x00, 0x00, 0x00 }, + { 0x2C, 0x00, 0x00, 0x00, 0x00 }, + { 0x2B, 0x00, 0x00, 0x00, 0x00 }, + { 0x2A, 0x00, 0x00, 0x00, 0x00 }, + { 0x29, 0x00, 0x00, 0x00, 0x00 }, + { 0x23, 0x00, 0x00, 0x00, 0x00 }, + { 0x4A, 0x00, 0x00, 0x00, 0x00 }, + { 0x6C, 0x00, 0x00, 0x00, 0x00 }, + { 0x60, 0x00, 0x00, 0x00, 0x00 }, + { 0x4F, 0x00, 0x00, 0x00, 0x00 }, + { 0x4A, 0x00, 0x00, 0x00, 0x00 }, + { 0x49, 0x00, 0x00, 0x00, 0x00 }, + { 0x47, 0x00, 0x00, 0x00, 0x00 }, + { 0x47, 0x00, 0x00, 0x00, 0x00 }, + { 0x46, 0x00, 0x00, 0x00, 0x00 } +}; +TX_WAVEFORM pmc4_t1_tx_waveform_sh_330ft = +{ + { 0x00, 0x45, 0x00, 0x00, 0x00 }, + { 0x0A, 0x44, 0x00, 0x00, 0x00 }, + { 0x36, 0x43, 0x00, 0x00, 0x00 }, + { 0x36, 0x41, 0x00, 0x00, 0x00 }, + { 0x34, 0x40, 0x00, 0x00, 0x00 }, + { 0x34, 0x40, 0x00, 0x00, 0x00 }, + { 0x30, 0x00, 0x00, 0x00, 0x00 }, + { 0x2F, 0x00, 0x00, 0x00, 0x00 }, + { 0x2E, 0x00, 0x00, 0x00, 0x00 }, + { 0x2D, 0x00, 0x00, 0x00, 0x00 }, + { 0x2C, 0x00, 0x00, 0x00, 0x00 }, + { 0x2B, 0x00, 0x00, 0x00, 0x00 }, + { 0x2A, 0x00, 0x00, 0x00, 0x00 }, + { 0x29, 0x00, 0x00, 0x00, 0x00 }, + { 0x23, 0x00, 0x00, 0x00, 0x00 }, + { 0x4A, 0x00, 0x00, 0x00, 0x00 }, + { 0x60, 0x00, 0x00, 0x00, 0x00 }, + { 0x55, 0x00, 0x00, 0x00, 0x00 }, + { 0x53, 0x00, 0x00, 0x00, 0x00 }, + { 0x50, 0x00, 0x00, 0x00, 0x00 }, + { 0x4E, 0x00, 0x00, 0x00, 0x00 }, + { 0x4C, 0x00, 0x00, 0x00, 0x00 }, + { 0x48, 0x00, 0x00, 0x00, 0x00 }, + { 0x47, 0x00, 0x00, 0x00, 0x00 } +}; + + +/* Transmit Waveform Values for T1 Short Haul (330 - 440 ft.) + * unsigned char t1_tx_waveform_sh_440ft[LAST_SAMPLE-FIRST_SAMPLE+1][LAST_UI-FIRST_UI+1] = + */ +TX_WAVEFORM pmc_t1_tx_waveform_sh_440ft = +{ + { 0x00, 0x44, 0x00, 0x00, 0x00 }, + { 0x0A, 0x44, 0x00, 0x00, 0x00 }, + { 0x3F, 0x43, 0x00, 0x00, 0x00 }, + { 0x3F, 0x43, 0x00, 0x00, 0x00 }, + { 0x3F, 0x42, 0x00, 0x00, 0x00 }, + { 0x3F, 0x42, 0x00, 0x00, 0x00 }, + { 0x2F, 0x41, 0x00, 0x00, 0x00 }, + { 0x2E, 0x41, 0x00, 0x00, 0x00 }, + { 0x2D, 0x00, 0x00, 0x00, 0x00 }, + { 0x2C, 0x00, 0x00, 0x00, 0x00 }, + { 0x2B, 0x00, 0x00, 0x00, 0x00 }, + { 0x2A, 0x00, 0x00, 0x00, 0x00 }, + { 0x29, 0x00, 0x00, 0x00, 0x00 }, + { 0x28, 0x00, 0x00, 0x00, 0x00 }, + { 0x19, 0x00, 0x00, 0x00, 0x00 }, + { 0x4A, 0x00, 0x00, 0x00, 0x00 }, + { 0x7F, 0x00, 0x00, 0x00, 0x00 }, + { 0x60, 0x00, 0x00, 0x00, 0x00 }, + { 0x4F, 0x00, 0x00, 0x00, 0x00 }, + { 0x4A, 0x00, 0x00, 0x00, 0x00 }, + { 0x49, 0x00, 0x00, 0x00, 0x00 }, + { 0x47, 0x00, 0x00, 0x00, 0x00 }, + { 0x47, 0x00, 0x00, 0x00, 0x00 }, + { 0x46, 0x00, 0x00, 0x00, 0x00 } +}; +TX_WAVEFORM pmc4_t1_tx_waveform_sh_440ft = +{ + { 0x00, 0x46, 0x00, 0x00, 0x00 }, + { 0x0A, 0x45, 0x00, 0x00, 0x00 }, + { 0x3A, 0x43, 0x00, 0x00, 0x00 }, + { 0x3A, 0x41, 0x00, 0x00, 0x00 }, + { 0x37, 0x40, 0x00, 0x00, 0x00 }, + { 0x37, 0x40, 0x00, 0x00, 0x00 }, + { 0x2F, 0x00, 0x00, 0x00, 0x00 }, + { 0x2E, 0x00, 0x00, 0x00, 0x00 }, + { 0x2D, 0x00, 0x00, 0x00, 0x00 }, + { 0x2C, 0x00, 0x00, 0x00, 0x00 }, + { 0x2B, 0x00, 0x00, 0x00, 0x00 }, + { 0x2A, 0x00, 0x00, 0x00, 0x00 }, + { 0x29, 0x00, 0x00, 0x00, 0x00 }, + { 0x28, 0x00, 0x00, 0x00, 0x00 }, + { 0x19, 0x00, 0x00, 0x00, 0x00 }, + { 0x4A, 0x00, 0x00, 0x00, 0x00 }, + { 0x64, 0x00, 0x00, 0x00, 0x00 }, + { 0x57, 0x00, 0x00, 0x00, 0x00 }, + { 0x53, 0x00, 0x00, 0x00, 0x00 }, + { 0x4F, 0x00, 0x00, 0x00, 0x00 }, + { 0x4C, 0x00, 0x00, 0x00, 0x00 }, + { 0x4B, 0x00, 0x00, 0x00, 0x00 }, + { 0x48, 0x00, 0x00, 0x00, 0x00 }, + { 0x47, 0x00, 0x00, 0x00, 0x00 } +}; + + +/* Transmit Waveform Values for T1 Short Haul (440 - 550 ft.) + * unsigned char t1_tx_waveform_sh_550ft[LAST_SAMPLE-FIRST_SAMPLE+1][LAST_UI-FIRST_UI+1] = + */ +TX_WAVEFORM pmc_t1_tx_waveform_sh_550ft = +{ + { 0x00, 0x44, 0x00, 0x00, 0x00 }, + { 0x0A, 0x44, 0x00, 0x00, 0x00 }, + { 0x3F, 0x43, 0x00, 0x00, 0x00 }, + { 0x3F, 0x43, 0x00, 0x00, 0x00 }, + { 0x3F, 0x42, 0x00, 0x00, 0x00 }, + { 0x3F, 0x42, 0x00, 0x00, 0x00 }, + { 0x30, 0x41, 0x00, 0x00, 0x00 }, + { 0x2B, 0x41, 0x00, 0x00, 0x00 }, + { 0x2A, 0x00, 0x00, 0x00, 0x00 }, + { 0x29, 0x00, 0x00, 0x00, 0x00 }, + { 0x28, 0x00, 0x00, 0x00, 0x00 }, + { 0x27, 0x00, 0x00, 0x00, 0x00 }, + { 0x26, 0x00, 0x00, 0x00, 0x00 }, + { 0x26, 0x00, 0x00, 0x00, 0x00 }, + { 0x24, 0x00, 0x00, 0x00, 0x00 }, + { 0x4A, 0x00, 0x00, 0x00, 0x00 }, + { 0x7F, 0x00, 0x00, 0x00, 0x00 }, + { 0x7F, 0x00, 0x00, 0x00, 0x00 }, + { 0x4F, 0x00, 0x00, 0x00, 0x00 }, + { 0x4A, 0x00, 0x00, 0x00, 0x00 }, + { 0x49, 0x00, 0x00, 0x00, 0x00 }, + { 0x47, 0x00, 0x00, 0x00, 0x00 }, + { 0x47, 0x00, 0x00, 0x00, 0x00 }, + { 0x46, 0x00, 0x00, 0x00, 0x00 } +}; +TX_WAVEFORM pmc4_t1_tx_waveform_sh_550ft = +{ + { 0x00, 0x46, 0x00, 0x00, 0x00 }, + { 0x0A, 0x45, 0x00, 0x00, 0x00 }, + { 0x3E, 0x43, 0x00, 0x00, 0x00 }, + { 0x3E, 0x41, 0x00, 0x00, 0x00 }, + { 0x3E, 0x40, 0x00, 0x00, 0x00 }, + { 0x30, 0x40, 0x00, 0x00, 0x00 }, + { 0x30, 0x00, 0x00, 0x00, 0x00 }, + { 0x2B, 0x00, 0x00, 0x00, 0x00 }, + { 0x2A, 0x00, 0x00, 0x00, 0x00 }, + { 0x29, 0x00, 0x00, 0x00, 0x00 }, + { 0x28, 0x00, 0x00, 0x00, 0x00 }, + { 0x27, 0x00, 0x00, 0x00, 0x00 }, + { 0x26, 0x00, 0x00, 0x00, 0x00 }, + { 0x24, 0x00, 0x00, 0x00, 0x00 }, + { 0x19, 0x00, 0x00, 0x00, 0x00 }, + { 0x4A, 0x00, 0x00, 0x00, 0x00 }, + { 0x78, 0x00, 0x00, 0x00, 0x00 }, + { 0x57, 0x00, 0x00, 0x00, 0x00 }, + { 0x53, 0x00, 0x00, 0x00, 0x00 }, + { 0x4F, 0x00, 0x00, 0x00, 0x00 }, + { 0x4C, 0x00, 0x00, 0x00, 0x00 }, + { 0x4B, 0x00, 0x00, 0x00, 0x00 }, + { 0x48, 0x00, 0x00, 0x00, 0x00 }, + { 0x47, 0x00, 0x00, 0x00, 0x00 } +}; + + +/* Transmit Waveform Values for T1 Short Haul (550 - 660 ft.) + * unsigned char t1_tx_waveform_sh_660ft[LAST_SAMPLE-FIRST_SAMPLE+1][LAST_UI-FIRST_UI+1] = + */ +TX_WAVEFORM pmc_t1_tx_waveform_sh_660ft = +{ + { 0x00, 0x44, 0x00, 0x00, 0x00 }, + { 0x0A, 0x44, 0x00, 0x00, 0x00 }, + { 0x3F, 0x43, 0x00, 0x00, 0x00 }, + { 0x3F, 0x43, 0x00, 0x00, 0x00 }, + { 0x3F, 0x42, 0x00, 0x00, 0x00 }, + { 0x3F, 0x42, 0x00, 0x00, 0x00 }, + { 0x3F, 0x41, 0x00, 0x00, 0x00 }, + { 0x30, 0x41, 0x00, 0x00, 0x00 }, + { 0x2A, 0x00, 0x00, 0x00, 0x00 }, + { 0x29, 0x00, 0x00, 0x00, 0x00 }, + { 0x28, 0x00, 0x00, 0x00, 0x00 }, + { 0x27, 0x00, 0x00, 0x00, 0x00 }, + { 0x26, 0x00, 0x00, 0x00, 0x00 }, + { 0x25, 0x00, 0x00, 0x00, 0x00 }, + { 0x24, 0x00, 0x00, 0x00, 0x00 }, + { 0x4A, 0x00, 0x00, 0x00, 0x00 }, + { 0x7F, 0x00, 0x00, 0x00, 0x00 }, + { 0x7F, 0x00, 0x00, 0x00, 0x00 }, + { 0x5F, 0x00, 0x00, 0x00, 0x00 }, + { 0x50, 0x00, 0x00, 0x00, 0x00 }, + { 0x49, 0x00, 0x00, 0x00, 0x00 }, + { 0x47, 0x00, 0x00, 0x00, 0x00 }, + { 0x47, 0x00, 0x00, 0x00, 0x00 }, + { 0x46, 0x00, 0x00, 0x00, 0x00 } +}; +TX_WAVEFORM pmc4_t1_tx_waveform_sh_660ft = +{ + { 0x00, 0x46, 0x00, 0x00, 0x00 }, + { 0x0A, 0x45, 0x00, 0x00, 0x00 }, + { 0x3F, 0x43, 0x00, 0x00, 0x00 }, + { 0x3F, 0x41, 0x00, 0x00, 0x00 }, + { 0x3F, 0x40, 0x00, 0x00, 0x00 }, + { 0x3F, 0x40, 0x00, 0x00, 0x00 }, + { 0x2E, 0x00, 0x00, 0x00, 0x00 }, + { 0x2E, 0x00, 0x00, 0x00, 0x00 }, + { 0x2A, 0x00, 0x00, 0x00, 0x00 }, + { 0x29, 0x00, 0x00, 0x00, 0x00 }, + { 0x28, 0x00, 0x00, 0x00, 0x00 }, + { 0x27, 0x00, 0x00, 0x00, 0x00 }, + { 0x26, 0x00, 0x00, 0x00, 0x00 }, + { 0x25, 0x00, 0x00, 0x00, 0x00 }, + { 0x24, 0x00, 0x00, 0x00, 0x00 }, + { 0x4A, 0x00, 0x00, 0x00, 0x00 }, + { 0x7F, 0x00, 0x00, 0x00, 0x00 }, + { 0x63, 0x00, 0x00, 0x00, 0x00 }, + { 0x53, 0x00, 0x00, 0x00, 0x00 }, + { 0x51, 0x00, 0x00, 0x00, 0x00 }, + { 0x4C, 0x00, 0x00, 0x00, 0x00 }, + { 0x4B, 0x00, 0x00, 0x00, 0x00 }, + { 0x48, 0x00, 0x00, 0x00, 0x00 }, + { 0x47, 0x00, 0x00, 0x00, 0x00 } +}; + + + +/* Transmit Waveform Values for E1 120 Ohm + * unsigned char e1_tx_waveform_120[LAST_SAMPLE-FIRST_SAMPLE+1][LAST_UI-FIRST_UI+1] = + */ +TX_WAVEFORM pmc_e1_tx_waveform_120 = +{ + { 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x0A, 0x00, 0x00, 0x00, 0x00 }, + { 0x3F, 0x00, 0x00, 0x00, 0x00 }, + { 0x3F, 0x00, 0x00, 0x00, 0x00 }, + { 0x39, 0x00, 0x00, 0x00, 0x00 }, + { 0x38, 0x00, 0x00, 0x00, 0x00 }, + { 0x36, 0x00, 0x00, 0x00, 0x00 }, + { 0x36, 0x00, 0x00, 0x00, 0x00 }, + { 0x35, 0x00, 0x00, 0x00, 0x00 }, + { 0x35, 0x00, 0x00, 0x00, 0x00 }, + { 0x35, 0x00, 0x00, 0x00, 0x00 }, + { 0x35, 0x00, 0x00, 0x00, 0x00 }, + { 0x35, 0x00, 0x00, 0x00, 0x00 }, + { 0x35, 0x00, 0x00, 0x00, 0x00 }, + { 0x2D, 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 } +}; +TX_WAVEFORM pmc4_e1_tx_waveform_120 = +{ + { 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x0A, 0x00, 0x00, 0x00, 0x00 }, + { 0x3F, 0x00, 0x00, 0x00, 0x00 }, + { 0x3F, 0x00, 0x00, 0x00, 0x00 }, + { 0x39, 0x00, 0x00, 0x00, 0x00 }, + { 0x38, 0x00, 0x00, 0x00, 0x00 }, + { 0x36, 0x00, 0x00, 0x00, 0x00 }, + { 0x36, 0x00, 0x00, 0x00, 0x00 }, + { 0x35, 0x00, 0x00, 0x00, 0x00 }, + { 0x35, 0x00, 0x00, 0x00, 0x00 }, + { 0x35, 0x00, 0x00, 0x00, 0x00 }, + { 0x35, 0x00, 0x00, 0x00, 0x00 }, + { 0x35, 0x00, 0x00, 0x00, 0x00 }, + { 0x35, 0x00, 0x00, 0x00, 0x00 }, + { 0x2D, 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 } +}; + + +/* Transmit Waveform Values for E1 75 Ohm + * unsigned char e1_tx_waveform_75[LAST_SAMPLE-FIRST_SAMPLE+1][LAST_UI-FIRST_UI+1] = + */ +TX_WAVEFORM pmc_e1_tx_waveform_75 = +{ + { 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x0A, 0x00, 0x00, 0x00, 0x00 }, + { 0x28, 0x00, 0x00, 0x00, 0x00 }, + { 0x3A, 0x00, 0x00, 0x00, 0x00 }, + { 0x3A, 0x00, 0x00, 0x00, 0x00 }, + { 0x3A, 0x00, 0x00, 0x00, 0x00 }, + { 0x3A, 0x00, 0x00, 0x00, 0x00 }, + { 0x3A, 0x00, 0x00, 0x00, 0x00 }, + { 0x3A, 0x00, 0x00, 0x00, 0x00 }, + { 0x3A, 0x00, 0x00, 0x00, 0x00 }, + { 0x3A, 0x00, 0x00, 0x00, 0x00 }, + { 0x3A, 0x00, 0x00, 0x00, 0x00 }, + { 0x3A, 0x00, 0x00, 0x00, 0x00 }, + { 0x32, 0x00, 0x00, 0x00, 0x00 }, + { 0x14, 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 } +}; +TX_WAVEFORM pmc4_e1_tx_waveform_75 = +{ + { 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x0A, 0x00, 0x00, 0x00, 0x00 }, + { 0x3E, 0x00, 0x00, 0x00, 0x00 }, + { 0x3E, 0x00, 0x00, 0x00, 0x00 }, + { 0x3E, 0x00, 0x00, 0x00, 0x00 }, + { 0x3C, 0x00, 0x00, 0x00, 0x00 }, + { 0x3C, 0x00, 0x00, 0x00, 0x00 }, + { 0x3A, 0x00, 0x00, 0x00, 0x00 }, + { 0x3A, 0x00, 0x00, 0x00, 0x00 }, + { 0x3A, 0x00, 0x00, 0x00, 0x00 }, + { 0x3A, 0x00, 0x00, 0x00, 0x00 }, + { 0x3A, 0x00, 0x00, 0x00, 0x00 }, + { 0x3A, 0x00, 0x00, 0x00, 0x00 }, + { 0x35, 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 } +}; + + +RLPS_EQUALIZER_RAM pmc_t1_rlps_ram_table[] = +{ + { 0x03, 0xFE, 0x18, 0x40 }, /* 0d */ + { 0x03, 0xF6, 0x18, 0x40 }, /* 1d */ + { 0x03, 0xEE, 0x18, 0x40 }, /* 2d */ + { 0x03, 0xE6, 0x18, 0x40 }, /* 3d */ + { 0x03, 0xDE, 0x18, 0x40 }, /* 4d */ + { 0x03, 0xD6, 0x18, 0x40 }, /* 5d */ + { 0x03, 0xD6, 0x18, 0x40 }, /* 6d */ + { 0x03, 0xD6, 0x18, 0x40 }, /* 7d */ + { 0x03, 0xCE, 0x18, 0x40 }, /* 8d */ + { 0x03, 0xCE, 0x18, 0x40 }, /* 9d */ + { 0x03, 0xCE, 0x18, 0x40 }, /* 10d */ + { 0x03, 0xCE, 0x18, 0x40 }, /* 11d */ + { 0x03, 0xC6, 0x18, 0x40 }, /* 12d */ + { 0x03, 0xC6, 0x18, 0x40 }, /* 13d */ + { 0x03, 0xC6, 0x18, 0x40 }, /* 14d */ + { 0x0B, 0xBE, 0x18, 0x40 }, /* 15d */ + { 0x0B, 0xBE, 0x18, 0x40 }, /* 16d */ + { 0x0B, 0xBE, 0x18, 0x40 }, /* 17d */ + { 0x0B, 0xBE, 0x18, 0x40 }, /* 18d */ + { 0x0B, 0xB6, 0x18, 0x40 }, /* 19d */ + { 0x0B, 0xB6, 0x18, 0x40 }, /* 20d */ + { 0x0B, 0xB6, 0x18, 0x40 }, /* 21d */ + { 0x0B, 0xB6, 0x18, 0x40 }, /* 22d */ + { 0x13, 0xAE, 0x18, 0x38 }, /* 23d */ + { 0x13, 0xAE, 0x18, 0x3C }, /* 24d */ + { 0x13, 0xAE, 0x18, 0x40 }, /* 25d */ + { 0x13, 0xAE, 0x18, 0x40 }, /* 26d */ + { 0x13, 0xAE, 0x18, 0x40 }, /* 27d */ + { 0x13, 0xAE, 0x18, 0x40 }, /* 28d */ + { 0x1B, 0xB6, 0x18, 0xB8 }, /* 29d */ + { 0x1B, 0xAE, 0x18, 0xB8 }, /* 30d */ + { 0x1B, 0xAE, 0x18, 0xBC }, /* 31d */ + { 0x1B, 0xAE, 0x18, 0xC0 }, /* 32d */ + { 0x1B, 0xAE, 0x18, 0xC0 }, /* 33d */ + { 0x23, 0xA6, 0x18, 0xC0 }, /* 34d */ + { 0x23, 0xA6, 0x18, 0xC0 }, /* 35d */ + { 0x23, 0xA6, 0x18, 0xC0 }, /* 36d */ + { 0x23, 0xA6, 0x18, 0xC0 }, /* 37d */ + { 0x23, 0xA6, 0x18, 0xC0 }, /* 38d */ + { 0x23, 0x9E, 0x18, 0xC0 }, /* 39d */ + { 0x23, 0x9E, 0x18, 0xC0 }, /* 40d */ + { 0x23, 0x9E, 0x18, 0xC0 }, /* 41d */ + { 0x23, 0x9E, 0x18, 0xC0 }, /* 42d */ + { 0x23, 0x9E, 0x18, 0xC0 }, /* 43d */ + { 0x2B, 0x96, 0x18, 0xC0 }, /* 44d */ + { 0x2B, 0x96, 0x18, 0xC0 }, /* 45d */ + { 0x2B, 0x96, 0x18, 0xC0 }, /* 46d */ + { 0x33, 0x96, 0x19, 0x40 }, /* 47d */ + { 0x37, 0x96, 0x19, 0x40 }, /* 48d */ + { 0x37, 0x96, 0x19, 0x40 }, /* 49d */ + { 0x37, 0x96, 0x19, 0x40 }, /* 50d */ + { 0x3F, 0x9E, 0x19, 0xC0 }, /* 51d */ + { 0x3F, 0x9E, 0x19, 0xC0 }, /* 52d */ + { 0x3F, 0x9E, 0x19, 0xC0 }, /* 53d */ + { 0x3F, 0xA6, 0x1A, 0x40 }, /* 54d */ + { 0x3F, 0xA6, 0x1A, 0x40 }, /* 55d */ + { 0x3F, 0xA6, 0x1A, 0x40 }, /* 56d */ + { 0x3F, 0xA6, 0x1A, 0x40 }, /* 57d */ + { 0x3F, 0x96, 0x19, 0xC0 }, /* 58d */ + { 0x3F, 0x96, 0x19, 0xC0 }, /* 59d */ + { 0x3F, 0x96, 0x19, 0xC0 }, /* 60d */ + { 0x3F, 0x96, 0x19, 0xC0 }, /* 61d */ + { 0x47, 0x9E, 0x1A, 0x40 }, /* 62d */ + { 0x47, 0x9E, 0x1A, 0x40 }, /* 63d */ + { 0x47, 0x9E, 0x1A, 0x40 }, /* 64d */ + { 0x47, 0x96, 0x1A, 0x40 }, /* 65d */ + { 0x47, 0x96, 0x1A, 0x40 }, /* 66d */ + { 0x47, 0x96, 0x1A, 0x40 }, /* 67d */ + { 0x47, 0x96, 0x1A, 0x40 }, /* 68d */ + { 0x4F, 0x8E, 0x1A, 0x40 }, /* 69d */ + { 0x4F, 0x8E, 0x1A, 0x40 }, /* 70d */ + { 0x4F, 0x8E, 0x1A, 0x40 }, /* 71d */ + { 0x4F, 0x8E, 0x1A, 0x40 }, /* 72d */ + { 0x4F, 0x8E, 0x1A, 0x40 }, /* 73d */ + { 0x57, 0x86, 0x1A, 0x40 }, /* 74d */ + { 0x57, 0x86, 0x1A, 0x40 }, /* 75d */ + { 0x57, 0x86, 0x1A, 0x40 }, /* 76d */ + { 0x57, 0x86, 0x1A, 0x40 }, /* 77d */ + { 0x57, 0x86, 0x1A, 0x40 }, /* 78d */ + { 0x5F, 0x86, 0x1A, 0xC0 }, /* 79d */ + { 0x5F, 0x86, 0x1A, 0xC0 }, /* 80d */ + { 0x5F, 0x86, 0x1A, 0xC0 }, /* 81d */ + { 0x5F, 0x86, 0x1A, 0xC0 }, /* 82d */ + { 0x5F, 0x86, 0x1A, 0xC0 }, /* 83d */ + { 0x5F, 0x86, 0x1A, 0xC0 }, /* 84d */ + { 0x5F, 0x7E, 0x1A, 0xC0 }, /* 85d */ + { 0x5F, 0x7E, 0x1A, 0xC0 }, /* 86d */ + { 0x5F, 0x7E, 0x1A, 0xC0 }, /* 87d */ + { 0x5F, 0x7E, 0x1A, 0xC0 }, /* 88d */ + { 0x5F, 0x7E, 0x1A, 0xC0 }, /* 89d */ + { 0x67, 0x7E, 0x2A, 0xC0 }, /* 90d */ + { 0x67, 0x7E, 0x2A, 0xC0 }, /* 91d */ + { 0x67, 0x7E, 0x2A, 0xC0 }, /* 92d */ + { 0x67, 0x7E, 0x2A, 0xC0 }, /* 93d */ + { 0x67, 0x76, 0x2A, 0xC0 }, /* 94d */ + { 0x67, 0x76, 0x2A, 0xC0 }, /* 95d */ + { 0x67, 0x76, 0x2A, 0xC0 }, /* 96d */ + { 0x67, 0x76, 0x2A, 0xC0 }, /* 97d */ + { 0x67, 0x76, 0x2A, 0xC0 }, /* 98d */ + { 0x6F, 0x6E, 0x2A, 0xC0 }, /* 99d */ + { 0x6F, 0x6E, 0x2A, 0xC0 }, /* 100d */ + { 0x6F, 0x6E, 0x2A, 0xC0 }, /* 101d */ + { 0x6F, 0x6E, 0x2A, 0xC0 }, /* 102d */ + { 0x77, 0x6E, 0x3A, 0xC0 }, /* 103d */ + { 0x77, 0x6E, 0x3A, 0xC0 }, /* 104d */ + { 0x77, 0x6E, 0x3A, 0xC0 }, /* 105d */ + { 0x77, 0x6E, 0x3A, 0xC0 }, /* 106d */ + { 0x7F, 0x66, 0x3A, 0xC0 }, /* 107d */ + { 0x7F, 0x66, 0x3A, 0xC0 }, /* 108d */ + { 0x7F, 0x66, 0x4A, 0xC0 }, /* 109d */ + { 0x7F, 0x66, 0x4A, 0xC0 }, /* 110d */ + { 0x7F, 0x66, 0x4A, 0xC0 }, /* 111d */ + { 0x7F, 0x66, 0x4A, 0xC0 }, /* 112d */ + { 0x87, 0x66, 0x5A, 0xC0 }, /* 113d */ + { 0x87, 0x66, 0x5A, 0xC0 }, /* 114d */ + { 0x87, 0x66, 0x5A, 0xC0 }, /* 115d */ + { 0x87, 0x66, 0x5A, 0xC0 }, /* 116d */ + { 0x87, 0x66, 0x5A, 0xC0 }, /* 117d */ + { 0x87, 0x5E, 0x5A, 0xC0 }, /* 118d */ + { 0x87, 0x5E, 0x5A, 0xC0 }, /* 119d */ + { 0x87, 0x5E, 0x5A, 0xC0 }, /* 120d */ + { 0x87, 0x5E, 0x5A, 0xC0 }, /* 121d */ + { 0x87, 0x5E, 0x5A, 0xC0 }, /* 122d */ + { 0x8F, 0x5E, 0x6A, 0xC0 }, /* 123d */ + { 0x8F, 0x5E, 0x6A, 0xC0 }, /* 124d */ + { 0x8F, 0x5E, 0x6A, 0xC0 }, /* 125d */ + { 0x8F, 0x5E, 0x6A, 0xC0 }, /* 126d */ + { 0x97, 0x5E, 0x7A, 0xC0 }, /* 127d */ + { 0x97, 0x5E, 0x7A, 0xC0 }, /* 128d */ + { 0x97, 0x5E, 0x7A, 0xC0 }, /* 129d */ + { 0x97, 0x5E, 0x7A, 0xC0 }, /* 130d */ + { 0x9F, 0x5E, 0x8A, 0xC0 }, /* 131d */ + { 0x9F, 0x5E, 0x8A, 0xC0 }, /* 132d */ + { 0x9F, 0x5E, 0x8A, 0xC0 }, /* 133d */ + { 0x9F, 0x5E, 0x8A, 0xC0 }, /* 134d */ + { 0x9F, 0x5E, 0x8A, 0xC0 }, /* 135d */ + { 0xA7, 0x56, 0x9A, 0xC0 }, /* 136d */ + { 0xA7, 0x56, 0x9A, 0xC0 }, /* 137d */ + { 0xA7, 0x56, 0x9A, 0xC0 }, /* 138d */ + { 0xA7, 0x56, 0x9A, 0xC0 }, /* 139d */ + { 0xA7, 0x56, 0xAA, 0xC0 }, /* 140d */ + { 0xA7, 0x56, 0xAA, 0xC0 }, /* 141d */ + { 0xA7, 0x56, 0xAA, 0xC0 }, /* 142d */ + { 0xAF, 0x4E, 0xAA, 0xC0 }, /* 143d */ + { 0xAF, 0x4E, 0xAA, 0xC0 }, /* 144d */ + { 0xAF, 0x4E, 0xAA, 0xC0 }, /* 145d */ + { 0xAF, 0x4E, 0xAA, 0xC0 }, /* 146d */ + { 0xAF, 0x4E, 0xAA, 0xC0 }, /* 147d */ + { 0xB7, 0x46, 0xAA, 0xC0 }, /* 148d */ + { 0xB7, 0x46, 0xAA, 0xC0 }, /* 149d */ + { 0xB7, 0x46, 0xAA, 0xC0 }, /* 150d */ + { 0xB7, 0x46, 0xAA, 0xC0 }, /* 151d */ + { 0xB7, 0x46, 0xAA, 0xC0 }, /* 152d */ + { 0xB7, 0x46, 0xAA, 0xC0 }, /* 153d */ + { 0xB7, 0x46, 0xAA, 0xC0 }, /* 154d */ + { 0xB7, 0x46, 0xBA, 0xC0 }, /* 155d */ + { 0xB7, 0x46, 0xBA, 0xC0 }, /* 156d */ + { 0xB7, 0x46, 0xBA, 0xC0 }, /* 157d */ + { 0xBF, 0x4E, 0xBB, 0x40 }, /* 158d */ + { 0xBF, 0x4E, 0xBB, 0x40 }, /* 159d */ + { 0xBF, 0x4E, 0xBB, 0x40 }, /* 160d */ + { 0xBF, 0x4E, 0xBB, 0x40 }, /* 161d */ + { 0xBF, 0x4E, 0xBB, 0x40 }, /* 162d */ + { 0xBF, 0x4E, 0xBB, 0x40 }, /* 163d */ + { 0xBF, 0x4E, 0xBB, 0x40 }, /* 164d */ + { 0xBF, 0x4E, 0xBB, 0x40 }, /* 165d */ + { 0xBF, 0x4E, 0xBB, 0x40 }, /* 166d */ + { 0xBE, 0x46, 0xCB, 0x40 }, /* 167d */ + { 0xBE, 0x46, 0xCB, 0x40 }, /* 168d */ + { 0xBE, 0x46, 0xCB, 0x40 }, /* 169d */ + { 0xBE, 0x46, 0xCB, 0x40 }, /* 170d */ + { 0xBE, 0x46, 0xCB, 0x40 }, /* 171d */ + { 0xBE, 0x46, 0xCB, 0x40 }, /* 172d */ + { 0xBE, 0x46, 0xDB, 0x40 }, /* 173d */ + { 0xBE, 0x46, 0xDB, 0x40 }, /* 174d */ + { 0xBE, 0x46, 0xDB, 0x40 }, /* 175d */ + { 0xC6, 0x3E, 0xCB, 0x40 }, /* 176d */ + { 0xC6, 0x3E, 0xCB, 0x40 }, /* 177d */ + { 0xC6, 0x3E, 0xDB, 0x40 }, /* 178d */ + { 0xC6, 0x3E, 0xDB, 0x40 }, /* 179d */ + { 0xC6, 0x3E, 0xDB, 0x40 }, /* 180d */ + { 0xC6, 0x44, 0xDB, 0x40 }, /* 181d */ + { 0xC6, 0x44, 0xDB, 0x40 }, /* 182d */ + { 0xC6, 0x44, 0xDB, 0x40 }, /* 183d */ + { 0xC6, 0x44, 0xDB, 0x40 }, /* 184d */ + { 0xC6, 0x3C, 0xDB, 0x40 }, /* 185d */ + { 0xC6, 0x3C, 0xDB, 0x40 }, /* 186d */ + { 0xC6, 0x3C, 0xDB, 0x40 }, /* 187d */ + { 0xC6, 0x3C, 0xDB, 0x40 }, /* 188d */ + { 0xD6, 0x34, 0xDB, 0x40 }, /* 189d */ + { 0xD6, 0x34, 0xDB, 0x40 }, /* 190d */ + { 0xD6, 0x34, 0xDB, 0x40 }, /* 191d */ + { 0xD6, 0x34, 0xDB, 0x40 }, /* 192d */ + { 0xD6, 0x34, 0xDB, 0x40 }, /* 193d */ + { 0xDE, 0x2C, 0xDB, 0x3C }, /* 194d */ + { 0xDE, 0x2C, 0xDB, 0x3C }, /* 195d */ + { 0xDE, 0x2C, 0xDB, 0x3C }, /* 196d */ + { 0xE6, 0x2C, 0xDB, 0x40 }, /* 197d */ + { 0xE6, 0x2C, 0xDB, 0x40 }, /* 198d */ + { 0xE6, 0x2C, 0xDB, 0x40 }, /* 199d */ + { 0xE6, 0x2C, 0xDB, 0x40 }, /* 200d */ + { 0xE6, 0x2C, 0xDB, 0x40 }, /* 201d */ + { 0xE6, 0x2C, 0xEB, 0x40 }, /* 202d */ + { 0xE6, 0x2C, 0xEB, 0x40 }, /* 203d */ + { 0xE6, 0x2C, 0xEB, 0x40 }, /* 204d */ + { 0xEE, 0x2C, 0xFB, 0x40 }, /* 205d */ + { 0xEE, 0x2C, 0xFB, 0x40 }, /* 206d */ + { 0xEE, 0x2C, 0xFB, 0x40 }, /* 207d */ + { 0xEE, 0x2D, 0x0B, 0x40 }, /* 208d */ + { 0xEE, 0x2D, 0x0B, 0x40 }, /* 209d */ + { 0xEE, 0x2D, 0x0B, 0x40 }, /* 210d */ + { 0xEE, 0x2D, 0x0B, 0x40 }, /* 211d */ + { 0xEE, 0x2D, 0x0B, 0x40 }, /* 212d */ + { 0xF5, 0x25, 0x0B, 0x38 }, /* 213d */ + { 0xF5, 0x25, 0x0B, 0x3C }, /* 214d */ + { 0xF5, 0x25, 0x0B, 0x40 }, /* 215d */ + { 0xF5, 0x25, 0x1B, 0x40 }, /* 216d */ + { 0xF5, 0x25, 0x1B, 0x40 }, /* 217d */ + { 0xF5, 0x25, 0x1B, 0x40 }, /* 218d */ + { 0xF5, 0x25, 0x1B, 0x40 }, /* 219d */ + { 0xF5, 0x25, 0x1B, 0x40 }, /* 220d */ + { 0xFD, 0x25, 0x2B, 0x40 }, /* 221d */ + { 0xFD, 0x25, 0x2B, 0x40 }, /* 222d */ + { 0xFD, 0x25, 0x2B, 0x40 }, /* 223d */ + { 0xFD, 0x25, 0x2B, 0x40 }, /* 224d */ + { 0xFD, 0x25, 0x27, 0x40 }, /* 225d */ + { 0xFD, 0x25, 0x27, 0x40 }, /* 226d */ + { 0xFD, 0x25, 0x27, 0x40 }, /* 227d */ + { 0xFD, 0x25, 0x23, 0x40 }, /* 228d */ + { 0xFD, 0x25, 0x23, 0x40 }, /* 229d */ + { 0xFD, 0x25, 0x23, 0x40 }, /* 230d */ + { 0xFD, 0x25, 0x33, 0x40 }, /* 231d */ + { 0xFD, 0x25, 0x33, 0x40 }, /* 232d */ + { 0xFD, 0x25, 0x33, 0x40 }, /* 233d */ + { 0xFD, 0x25, 0x33, 0x40 }, /* 234d */ + { 0xFD, 0x25, 0x33, 0x40 }, /* 235d */ + { 0xFD, 0x25, 0x33, 0x40 }, /* 236d */ + { 0xFC, 0x25, 0x33, 0x40 }, /* 237d */ + { 0xFC, 0x25, 0x33, 0x40 }, /* 238d */ + { 0xFC, 0x25, 0x43, 0x40 }, /* 239d */ + { 0xFC, 0x25, 0x43, 0x40 }, /* 240d */ + { 0xFC, 0x25, 0x43, 0x40 }, /* 241d */ + { 0xFC, 0x25, 0x43, 0x44 }, /* 242d */ + { 0xFC, 0x25, 0x43, 0x48 }, /* 243d */ + { 0xFC, 0x25, 0x43, 0x4C }, /* 244d */ + { 0xFC, 0x25, 0x43, 0xBC }, /* 245d */ + { 0xFC, 0x25, 0x43, 0xC0 }, /* 246d */ + { 0xFC, 0x25, 0x43, 0xC0 }, /* 247d */ + { 0xFC, 0x23, 0x43, 0xC0 }, /* 248d */ + { 0xFC, 0x23, 0x43, 0xC0 }, /* 249d */ + { 0xFC, 0x23, 0x43, 0xC0 }, /* 250d */ + { 0xFC, 0x21, 0x43, 0xC0 }, /* 251d */ + { 0xFC, 0x21, 0x43, 0xC0 }, /* 252d */ + { 0xFC, 0x21, 0x53, 0xC0 }, /* 253d */ + { 0xFC, 0x21, 0x53, 0xC0 }, /* 254d */ + { 0xFC, 0x21, 0x53, 0xC0 } /* 255d */ +}; +RLPS_EQUALIZER_RAM pmc4_t1_rlps_ram_table[] = +{ + { 0x03, 0xFE, 0x18, 0x40 }, /* 0d */ + { 0x03, 0xFE, 0x18, 0x40 }, /* 1d */ + { 0x03, 0xF6, 0x18, 0x40 }, /* 2d */ + { 0x03, 0xF6, 0x18, 0x40 }, /* 3d */ + { 0x03, 0xEE, 0x18, 0x40 }, /* 4d */ + { 0x03, 0xEE, 0x18, 0x40 }, /* 5d */ + { 0x03, 0xE6, 0x18, 0x40 }, /* 6d */ + { 0x03, 0xE6, 0x18, 0x40 }, /* 7d */ + { 0x03, 0xDE, 0x18, 0x40 }, /* 8d */ + { 0x0B, 0xDE, 0x18, 0x40 }, /* 9d */ + { 0x0B, 0xD6, 0x18, 0x40 }, /* 10d */ + { 0x0B, 0xD6, 0x18, 0x40 }, /* 11d */ + { 0x0B, 0xCE, 0x18, 0x40 }, /* 12d */ + { 0x0B, 0xCE, 0x18, 0x40 }, /* 13d */ + { 0x0B, 0xC6, 0x18, 0x40 }, /* 14d */ + { 0x0B, 0xC6, 0x18, 0x40 }, /* 15d */ + { 0x0B, 0xBE, 0x18, 0x40 }, /* 16d */ + { 0x0B, 0xBE, 0x18, 0x40 }, /* 17d */ + { 0x0B, 0xB6, 0x18, 0x40 }, /* 18d */ + { 0x0B, 0xB6, 0x18, 0x40 }, /* 19d */ + { 0x0B, 0xAE, 0x18, 0x40 }, /* 20d */ + { 0x0B, 0xAE, 0x18, 0x40 }, /* 21d */ + { 0x13, 0xAE, 0x18, 0x40 }, /* 22d */ + { 0x13, 0xAE, 0x18, 0x40 }, /* 23d */ + { 0x13, 0xA6, 0x18, 0x40 }, /* 24d */ + { 0x13, 0xA6, 0x28, 0x40 }, /* 25d */ + { 0x13, 0xA6, 0x28, 0x40 }, /* 26d */ + { 0x13, 0xA6, 0x28, 0x40 }, /* 27d */ + { 0x1B, 0xA6, 0x28, 0x40 }, /* 28d */ + { 0x1B, 0xA6, 0x28, 0x40 }, /* 29d */ + { 0x1B, 0x9E, 0x28, 0x40 }, /* 30d */ + { 0x1B, 0x9E, 0x38, 0x40 }, /* 31d */ + { 0x1B, 0x9E, 0x38, 0x40 }, /* 32d */ + { 0x1B, 0x9E, 0x38, 0x40 }, /* 33d */ + { 0x23, 0x96, 0x38, 0x40 }, /* 34d */ + { 0x23, 0x96, 0x38, 0x40 }, /* 35d */ + { 0x23, 0x96, 0x38, 0x40 }, /* 36d */ + { 0x23, 0x96, 0x48, 0x40 }, /* 37d */ + { 0x23, 0x96, 0x48, 0x40 }, /* 38d */ + { 0x23, 0x96, 0x48, 0x40 }, /* 39d */ + { 0x23, 0x96, 0x58, 0x40 }, /* 40d */ + { 0x23, 0x96, 0x58, 0x40 }, /* 41d */ + { 0x23, 0x96, 0x58, 0x40 }, /* 42d */ + { 0x2B, 0x96, 0x38, 0xC0 }, /* 43d */ + { 0x2B, 0x96, 0x38, 0xC0 }, /* 44d */ + { 0x2B, 0x96, 0x38, 0xC0 }, /* 45d */ + { 0x33, 0x8E, 0x38, 0xC0 }, /* 46d */ + { 0x33, 0x8E, 0x38, 0xC0 }, /* 47d */ + { 0x33, 0x8E, 0x38, 0xC0 }, /* 48d */ + { 0x37, 0x8E, 0x48, 0xC0 }, /* 49d */ + { 0x37, 0x8E, 0x48, 0xC0 }, /* 50d */ + { 0x37, 0x86, 0x48, 0xC0 }, /* 51d */ + { 0x37, 0x86, 0x48, 0xC0 }, /* 52d */ + { 0x37, 0x86, 0x58, 0xC0 }, /* 53d */ + { 0x37, 0x86, 0x58, 0xC0 }, /* 54d */ + { 0x3F, 0x86, 0x54, 0xC0 }, /* 55d */ + { 0x3F, 0x86, 0x54, 0xC0 }, /* 56d */ + { 0x3F, 0x7E, 0x54, 0xC0 }, /* 57d */ + { 0x47, 0x7E, 0x54, 0xC0 }, /* 58d */ + { 0x47, 0x7E, 0x54, 0xC0 }, /* 59d */ + { 0x47, 0x76, 0x54, 0xC0 }, /* 60d */ + { 0x47, 0x76, 0x64, 0xC0 }, /* 61d */ + { 0x47, 0x76, 0x64, 0xC0 }, /* 62d */ + { 0x47, 0x76, 0x64, 0xC0 }, /* 63d */ + { 0x47, 0x76, 0x74, 0xC0 }, /* 64d */ + { 0x47, 0x76, 0x74, 0xC0 }, /* 65d */ + { 0x47, 0x76, 0x74, 0xC0 }, /* 66d */ + { 0x47, 0x76, 0x74, 0xC0 }, /* 67d */ + { 0x47, 0x76, 0x74, 0xC0 }, /* 68d */ + { 0x47, 0x76, 0x74, 0xC0 }, /* 69d */ + { 0x4F, 0x76, 0x65, 0x40 }, /* 70d */ + { 0x4F, 0x76, 0x65, 0x40 }, /* 71d */ + { 0x4F, 0x76, 0x65, 0x40 }, /* 72d */ + { 0x57, 0x76, 0x75, 0x40 }, /* 73d */ + { 0x57, 0x76, 0x75, 0x40 }, /* 74d */ + { 0x5F, 0x6E, 0x75, 0x40 }, /* 75d */ + { 0x5F, 0x6E, 0x75, 0x40 }, /* 76d */ + { 0x67, 0x6E, 0x85, 0x40 }, /* 77d */ + { 0x67, 0x6E, 0x85, 0x40 }, /* 78d */ + { 0x67, 0x6E, 0x85, 0x40 }, /* 79d */ + { 0x67, 0x6E, 0x95, 0x40 }, /* 80d */ + { 0x67, 0x6E, 0x95, 0x40 }, /* 81d */ + { 0x67, 0x6E, 0x95, 0x40 }, /* 82d */ + { 0x67, 0x66, 0x95, 0x40 }, /* 83d */ + { 0x67, 0x66, 0x95, 0x40 }, /* 84d */ + { 0x67, 0x66, 0xA5, 0x40 }, /* 85d */ + { 0x67, 0x66, 0xA5, 0x40 }, /* 86d */ + { 0x67, 0x5E, 0x95, 0x40 }, /* 87d */ + { 0x67, 0x5E, 0x95, 0x40 }, /* 88d */ + { 0x77, 0x5E, 0x75, 0xC0 }, /* 89d */ + { 0x77, 0x5E, 0x75, 0xC0 }, /* 90d */ + { 0x77, 0x5E, 0x85, 0xC0 }, /* 91d */ + { 0x77, 0x5E, 0x85, 0xC0 }, /* 92d */ + { 0x77, 0x5E, 0x95, 0xC0 }, /* 93d */ + { 0x77, 0x5E, 0x95, 0xC0 }, /* 94d */ + { 0x77, 0x5E, 0xA5, 0xC0 }, /* 95d */ + { 0x77, 0x5E, 0xA5, 0xC0 }, /* 96d */ + { 0x77, 0x5E, 0xB5, 0xC0 }, /* 97d */ + { 0x7F, 0x5E, 0xB5, 0xC0 }, /* 98d */ + { 0x7F, 0x5E, 0xC5, 0xC0 }, /* 99d */ + { 0x7F, 0x5E, 0xC5, 0xC0 }, /* 100d */ + { 0x7F, 0x5C, 0xA9, 0xC0 }, /* 101d */ + { 0x7F, 0x5C, 0xA9, 0xC0 }, /* 102d */ + { 0x7F, 0x5C, 0xA9, 0xC0 }, /* 103d */ + { 0x7F, 0x5C, 0xB9, 0xC0 }, /* 104d */ + { 0x7F, 0x5C, 0xB9, 0xC0 }, /* 105d */ + { 0x7F, 0x5C, 0xB9, 0xC0 }, /* 106d */ + { 0x7F, 0x5C, 0xA5, 0xC0 }, /* 107d */ + { 0x7F, 0x5C, 0xA5, 0xC0 }, /* 108d */ + { 0x7F, 0x5C, 0xA5, 0xC0 }, /* 109d */ + { 0x7F, 0x5C, 0xB5, 0xC0 }, /* 110d */ + { 0x7F, 0x54, 0xA5, 0xC0 }, /* 111d */ + { 0x7F, 0x54, 0xB5, 0xC0 }, /* 112d */ + { 0x7F, 0x54, 0xC5, 0xC0 }, /* 113d */ + { 0x7F, 0x54, 0xC5, 0xC0 }, /* 114d */ + { 0x7F, 0x54, 0xC5, 0xC0 }, /* 115d */ + { 0x7F, 0x54, 0xB1, 0xC0 }, /* 116d */ + { 0x7F, 0x54, 0xB1, 0xC0 }, /* 117d */ + { 0x7F, 0x54, 0xB1, 0xC0 }, /* 118d */ + { 0x7F, 0x54, 0xB1, 0xC0 }, /* 119d */ + { 0x7F, 0x54, 0xB1, 0xC0 }, /* 120d */ + { 0x86, 0x54, 0xD1, 0xC0 }, /* 121d */ + { 0x86, 0x54, 0xD1, 0xC0 }, /* 122d */ + { 0x86, 0x54, 0xD1, 0xC0 }, /* 123d */ + { 0x86, 0x54, 0xD1, 0xC0 }, /* 124d */ + { 0x86, 0x54, 0xD1, 0xC0 }, /* 125d */ + { 0x86, 0x4C, 0xC1, 0xC0 }, /* 126d */ + { 0x86, 0x4C, 0xC1, 0xC0 }, /* 127d */ + { 0x86, 0x4C, 0xD1, 0xC0 }, /* 128d */ + { 0x86, 0x4C, 0xD1, 0xC0 }, /* 129d */ + { 0x86, 0x4C, 0xD1, 0xC0 }, /* 130d */ + { 0x8E, 0x4C, 0xB2, 0x40 }, /* 131d */ + { 0x8E, 0x4C, 0xB2, 0x40 }, /* 132d */ + { 0x8E, 0x4C, 0xB2, 0x40 }, /* 133d */ + { 0x8E, 0x4C, 0xB2, 0x40 }, /* 134d */ + { 0x8E, 0x4C, 0xB2, 0x40 }, /* 135d */ + { 0x8E, 0x4C, 0xB2, 0x40 }, /* 136d */ + { 0x96, 0x4C, 0xC2, 0x40 }, /* 137d */ + { 0x96, 0x4C, 0xC2, 0x40 }, /* 138d */ + { 0x96, 0x4C, 0xC2, 0x40 }, /* 139d */ + { 0x9E, 0x4C, 0xD2, 0x40 }, /* 140d */ + { 0x9E, 0x4C, 0xD2, 0x40 }, /* 141d */ + { 0x9E, 0x4C, 0xD2, 0x40 }, /* 142d */ + { 0xA6, 0x4C, 0xD2, 0x40 }, /* 143d */ + { 0xA6, 0x4C, 0xD2, 0x40 }, /* 144d */ + { 0xA6, 0x4C, 0xD2, 0x40 }, /* 145d */ + { 0xA6, 0x4C, 0xE2, 0x40 }, /* 146d */ + { 0xA6, 0x4C, 0xE2, 0x40 }, /* 147d */ + { 0xA6, 0x4C, 0xE2, 0x40 }, /* 148d */ + { 0xA6, 0x4C, 0xF2, 0x40 }, /* 149d */ + { 0xA6, 0x4C, 0xF2, 0x40 }, /* 150d */ + { 0xA6, 0x4C, 0xF2, 0x40 }, /* 151d */ + { 0xA6, 0x4C, 0xF2, 0x40 }, /* 152d */ + { 0xA6, 0x4C, 0xF2, 0x40 }, /* 153d */ + { 0xA6, 0x4C, 0xF2, 0x40 }, /* 154d */ + { 0xB6, 0x4C, 0xE2, 0xC0 }, /* 155d */ + { 0xB6, 0x4C, 0xE2, 0xC0 }, /* 156d */ + { 0xB6, 0x4C, 0xE2, 0xC0 }, /* 157d */ + { 0xBE, 0x4C, 0xF2, 0xC0 }, /* 158d */ + { 0xBE, 0x4C, 0xF2, 0xC0 }, /* 159d */ + { 0xBE, 0x4C, 0xF2, 0xC0 }, /* 160d */ + { 0xBE, 0x4D, 0x02, 0xC0 }, /* 161d */ + { 0xBE, 0x4D, 0x02, 0xC0 }, /* 162d */ + { 0xBE, 0x4D, 0x02, 0xC0 }, /* 163d */ + { 0xBE, 0x4D, 0x12, 0xC0 }, /* 164d */ + { 0xBE, 0x4D, 0x12, 0xC0 }, /* 165d */ + { 0xBE, 0x4D, 0x12, 0xC0 }, /* 166d */ + { 0xC6, 0x4D, 0x12, 0xC0 }, /* 167d */ + { 0xC6, 0x4D, 0x12, 0xC0 }, /* 168d */ + { 0xC6, 0x4D, 0x12, 0xC0 }, /* 169d */ + { 0xC6, 0x4D, 0x12, 0xC0 }, /* 170d */ + { 0xC6, 0x4D, 0x12, 0xC0 }, /* 171d */ + { 0xC6, 0x4D, 0x12, 0xC0 }, /* 172d */ + { 0xCE, 0x4D, 0x22, 0xC0 }, /* 173d */ + { 0xCE, 0x4D, 0x22, 0xC0 }, /* 174d */ + { 0xCE, 0x4D, 0x22, 0xC0 }, /* 175d */ + { 0xCE, 0x4D, 0x22, 0xC0 }, /* 176d */ + { 0xCE, 0x4D, 0x22, 0xC0 }, /* 177d */ + { 0xCE, 0x4D, 0x22, 0xC0 }, /* 178d */ + { 0xCE, 0x4D, 0x22, 0xC0 }, /* 179d */ + { 0xCE, 0x4D, 0x22, 0xC0 }, /* 180d */ + { 0xCE, 0x4D, 0x22, 0xC0 }, /* 181d */ + { 0xCE, 0x4D, 0x32, 0xC0 }, /* 182d */ + { 0xCE, 0x4D, 0x32, 0xC0 }, /* 183d */ + { 0xCE, 0x4D, 0x32, 0xC0 }, /* 184d */ + { 0xCD, 0x4D, 0x22, 0xC0 }, /* 185d */ + { 0xCD, 0x4D, 0x22, 0xC0 }, /* 186d */ + { 0xCD, 0x4D, 0x22, 0xC0 }, /* 187d */ + { 0xD5, 0x4C, 0xE3, 0x40 }, /* 188d */ + { 0xD5, 0x4C, 0xE3, 0x40 }, /* 189d */ + { 0xD5, 0x4C, 0xF3, 0x40 }, /* 190d */ + { 0xD5, 0x4C, 0xF3, 0x40 }, /* 191d */ + { 0xD5, 0x4D, 0x03, 0x40 }, /* 192d */ + { 0xD5, 0x4D, 0x03, 0x40 }, /* 193d */ + { 0xD5, 0x4D, 0x13, 0x40 }, /* 194d */ + { 0xD5, 0x4D, 0x13, 0x40 }, /* 195d */ + { 0xD5, 0x4D, 0x23, 0x40 }, /* 196d */ + { 0xD5, 0x4D, 0x23, 0x40 }, /* 197d */ + { 0xD5, 0x4D, 0x33, 0x40 }, /* 198d */ + { 0xD5, 0x4D, 0x33, 0x40 }, /* 199d */ + { 0xDD, 0x45, 0x13, 0x40 }, /* 200d */ + { 0xDD, 0x45, 0x13, 0x40 }, /* 201d */ + { 0xDD, 0x45, 0x13, 0x40 }, /* 202d */ + { 0xDD, 0x45, 0x23, 0x40 }, /* 203d */ + { 0xDD, 0x45, 0x23, 0x40 }, /* 204d */ + { 0xDD, 0x45, 0x23, 0x40 }, /* 205d */ + { 0xDD, 0x45, 0x33, 0x40 }, /* 206d */ + { 0xDD, 0x45, 0x33, 0x40 }, /* 207d */ + { 0xDD, 0x45, 0x33, 0x40 }, /* 208d */ + { 0xE5, 0x3D, 0x23, 0x40 }, /* 209d */ + { 0xE5, 0x3D, 0x23, 0x40 }, /* 210d */ + { 0xE5, 0x3D, 0x23, 0x40 }, /* 211d */ + { 0xE5, 0x3D, 0x33, 0x40 }, /* 212d */ + { 0xE5, 0x3D, 0x33, 0x40 }, /* 213d */ + { 0xE5, 0x3D, 0x33, 0x40 }, /* 214d */ + { 0xE5, 0x3D, 0x43, 0x40 }, /* 215d */ + { 0xE5, 0x3D, 0x43, 0x40 }, /* 216d */ + { 0xE5, 0x3D, 0x43, 0x40 }, /* 217d */ + { 0xE5, 0x3D, 0x53, 0x40 }, /* 218d */ + { 0xE5, 0x3D, 0x53, 0x40 }, /* 219d */ + { 0xE5, 0x3D, 0x53, 0x40 }, /* 220d */ + { 0xEC, 0x35, 0x23, 0x40 }, /* 221d */ + { 0xEC, 0x35, 0x33, 0x40 }, /* 222d */ + { 0xEC, 0x35, 0x33, 0x40 }, /* 223d */ + { 0xEC, 0x35, 0x43, 0x40 }, /* 224d */ + { 0xEC, 0x35, 0x43, 0x40 }, /* 225d */ + { 0xEC, 0x35, 0x43, 0x40 }, /* 226d */ + { 0xEC, 0x35, 0x53, 0x40 }, /* 227d */ + { 0xEC, 0x35, 0x53, 0x40 }, /* 228d */ + { 0xEC, 0x35, 0x53, 0x40 }, /* 229d */ + { 0xEC, 0x35, 0x63, 0x40 }, /* 230d */ + { 0xEC, 0x35, 0x63, 0x40 }, /* 231d */ + { 0xEC, 0x35, 0x63, 0x40 }, /* 232d */ + { 0xEC, 0x35, 0x73, 0x40 }, /* 233d */ + { 0xEC, 0x35, 0x73, 0x40 }, /* 234d */ + { 0xEC, 0x35, 0x73, 0x40 }, /* 235d */ + { 0xEC, 0x2D, 0x53, 0x40 }, /* 236d */ + { 0xEC, 0x2D, 0x53, 0x40 }, /* 237d */ + { 0xEC, 0x2D, 0x53, 0x40 }, /* 238d */ + { 0xF4, 0x2D, 0x23, 0xC0 }, /* 239d */ + { 0xF4, 0x2D, 0x23, 0xC0 }, /* 240d */ + { 0xF4, 0x2D, 0x33, 0xC0 }, /* 241d */ + { 0xFC, 0x2D, 0x33, 0xC0 }, /* 242d */ + { 0xFC, 0x2D, 0x43, 0xC0 }, /* 243d */ + { 0xFC, 0x2D, 0x43, 0xC0 }, /* 244d */ + { 0xFC, 0x25, 0x43, 0xC0 }, /* 245d */ + { 0xFC, 0x25, 0x43, 0xC0 }, /* 246d */ + { 0xFC, 0x25, 0x43, 0xC0 }, /* 247d */ + { 0xFC, 0x25, 0x43, 0xC0 }, /* 248d */ + { 0xFC, 0x1D, 0x43, 0xC0 }, /* 249d */ + { 0xFC, 0x1D, 0x43, 0xC0 }, /* 250d */ + { 0xFC, 0x1D, 0x43, 0xC0 }, /* 251d */ + { 0xFC, 0x1D, 0x43, 0xC0 }, /* 252d */ + { 0xFC, 0x1D, 0x43, 0xC0 }, /* 253d */ + { 0xFC, 0x1D, 0x43, 0xC0 }, /* 254d */ + { 0xFC, 0x1D, 0x43, 0xC0 } /* 255d */ +}; + +RLPS_EQUALIZER_RAM pmc_t1_rlps_perf_mode_ram_table[] = +{ + { 0x03, 0xFE, 0x18, 0x40 }, + { 0x03, 0xFE, 0x18, 0x40 }, + { 0x03, 0xFE, 0x18, 0x40 }, + { 0x03, 0xFE, 0x18, 0x40 }, + { 0x03, 0xFE, 0x18, 0x40 }, + { 0x03, 0xFE, 0x18, 0x40 }, + { 0x03, 0xFE, 0x18, 0x40 }, + { 0x03, 0xFE, 0x18, 0x40 }, + { 0x03, 0xF6, 0x18, 0x40 }, + { 0x03, 0xF6, 0x18, 0x40 }, + { 0x03, 0xF6, 0x18, 0x40 }, + { 0x03, 0xF6, 0x18, 0x40 }, + { 0x03, 0xF6, 0x18, 0x40 }, + { 0x03, 0xF6, 0x18, 0x40 }, + { 0x03, 0xF6, 0x18, 0x40 }, + { 0x03, 0xF6, 0x18, 0x40 }, + { 0x03, 0xEE, 0x18, 0x40 }, + { 0x03, 0xEE, 0x18, 0x40 }, + { 0x03, 0xEE, 0x18, 0x40 }, + { 0x03, 0xEE, 0x18, 0x40 }, + { 0x03, 0xEE, 0x18, 0x40 }, + { 0x03, 0xEE, 0x18, 0x40 }, + { 0x03, 0xEE, 0x18, 0x40 }, + { 0x03, 0xEE, 0x18, 0x40 }, + { 0x03, 0xE6, 0x18, 0x40 }, + { 0x03, 0xE6, 0x18, 0x40 }, + { 0x03, 0xE6, 0x18, 0x40 }, + { 0x03, 0xE6, 0x18, 0x40 }, + { 0x03, 0xE6, 0x18, 0x40 }, + { 0x03, 0xE6, 0x18, 0x40 }, + { 0x03, 0xE6, 0x18, 0x40 }, + { 0x03, 0xE6, 0x18, 0x40 }, + { 0x03, 0xDE, 0x18, 0x40 }, + { 0x03, 0xDE, 0x18, 0x40 }, + { 0x03, 0xDE, 0x18, 0x40 }, + { 0x03, 0xDE, 0x18, 0x40 }, + { 0x03, 0xDE, 0x18, 0x40 }, + { 0x03, 0xDE, 0x18, 0x40 }, + { 0x03, 0xDE, 0x18, 0x40 }, + { 0x03, 0xDE, 0x18, 0x40 }, + { 0x03, 0xD6, 0x18, 0x40 }, + { 0x03, 0xD6, 0x18, 0x40 }, + { 0x03, 0xD6, 0x18, 0x40 }, + { 0x03, 0xD6, 0x18, 0x40 }, + { 0x03, 0xD6, 0x18, 0x40 }, + { 0x03, 0xD6, 0x18, 0x40 }, + { 0x03, 0xD6, 0x18, 0x40 }, + { 0x03, 0xD6, 0x18, 0x40 }, + { 0x03, 0xCE, 0x18, 0x40 }, + { 0x03, 0xCE, 0x18, 0x40 }, + { 0x03, 0xCE, 0x18, 0x40 }, + { 0x03, 0xCE, 0x18, 0x40 }, + { 0x03, 0xCE, 0x18, 0x40 }, + { 0x03, 0xCE, 0x18, 0x40 }, + { 0x03, 0xCE, 0x18, 0x40 }, + { 0x03, 0xCE, 0x18, 0x40 }, + { 0x03, 0xC6, 0x18, 0x40 }, + { 0x03, 0xC6, 0x18, 0x40 }, + { 0x03, 0xC6, 0x18, 0x40 }, + { 0x03, 0xC6, 0x18, 0x40 }, + { 0x03, 0xC6, 0x18, 0x40 }, + { 0x03, 0xC6, 0x18, 0x40 }, + { 0x03, 0xC6, 0x18, 0x40 }, + { 0x03, 0xC6, 0x18, 0x40 }, + { 0x03, 0xBE, 0x18, 0x40 }, + { 0x03, 0xBE, 0x18, 0x40 }, + { 0x03, 0xBE, 0x18, 0x40 }, + { 0x03, 0xBE, 0x18, 0x40 }, + { 0x03, 0xBE, 0x18, 0x40 }, + { 0x03, 0xBE, 0x18, 0x40 }, + { 0x03, 0xBE, 0x18, 0x40 }, + { 0x03, 0xBE, 0x18, 0x40 }, + { 0x03, 0xB6, 0x18, 0x40 }, + { 0x03, 0xB6, 0x18, 0x40 }, + { 0x03, 0xB6, 0x18, 0x40 }, + { 0x03, 0xB6, 0x18, 0x40 }, + { 0x03, 0xB6, 0x18, 0x40 }, + { 0x03, 0xB6, 0x18, 0x40 }, + { 0x03, 0xB6, 0x18, 0x40 }, + { 0x03, 0xB6, 0x18, 0x40 }, + { 0x03, 0xA6, 0x18, 0x40 }, + { 0x03, 0xA6, 0x18, 0x40 }, + { 0x03, 0xA6, 0x18, 0x40 }, + { 0x03, 0xA6, 0x18, 0x40 }, + { 0x03, 0xA6, 0x18, 0x40 }, + { 0x03, 0xA6, 0x18, 0x40 }, + { 0x03, 0xA6, 0x18, 0x40 }, + { 0x03, 0xA6, 0x18, 0x40 }, + { 0x03, 0x9E, 0x18, 0x40 }, + { 0x03, 0x9E, 0x18, 0x40 }, + { 0x03, 0x9E, 0x18, 0x40 }, + { 0x03, 0x9E, 0x18, 0x40 }, + { 0x03, 0x9E, 0x18, 0x40 }, + { 0x03, 0x9E, 0x18, 0x40 }, + { 0x03, 0x9E, 0x18, 0x40 }, + { 0x03, 0x9E, 0x18, 0x40 }, + { 0x03, 0x96, 0x18, 0x40 }, + { 0x03, 0x96, 0x18, 0x40 }, + { 0x03, 0x96, 0x18, 0x40 }, + { 0x03, 0x96, 0x18, 0x40 }, + { 0x03, 0x96, 0x18, 0x40 }, + { 0x03, 0x96, 0x18, 0x40 }, + { 0x03, 0x96, 0x18, 0x40 }, + { 0x03, 0x96, 0x18, 0x40 }, + { 0x03, 0x8E, 0x18, 0x40 }, + { 0x03, 0x8E, 0x18, 0x40 }, + { 0x03, 0x8E, 0x18, 0x40 }, + { 0x03, 0x8E, 0x18, 0x40 }, + { 0x03, 0x8E, 0x18, 0x40 }, + { 0x03, 0x8E, 0x18, 0x40 }, + { 0x03, 0x8E, 0x18, 0x40 }, + { 0x03, 0x8E, 0x18, 0x40 }, + { 0x03, 0x86, 0x18, 0x40 }, + { 0x03, 0x86, 0x18, 0x40 }, + { 0x03, 0x86, 0x18, 0x40 }, + { 0x03, 0x86, 0x18, 0x40 }, + { 0x03, 0x86, 0x18, 0x40 }, + { 0x03, 0x86, 0x18, 0x40 }, + { 0x03, 0x86, 0x18, 0x40 }, + { 0x03, 0x86, 0x18, 0x40 }, + { 0x03, 0x7E, 0x18, 0x40 }, + { 0x03, 0x7E, 0x18, 0x40 }, + { 0x03, 0x7E, 0x18, 0x40 }, + { 0x03, 0x7E, 0x18, 0x40 }, + { 0x03, 0x7E, 0x18, 0x40 }, + { 0x03, 0x7E, 0x18, 0x40 }, + { 0x03, 0x7E, 0x18, 0x40 }, + { 0x03, 0x7E, 0x18, 0x40 }, + { 0x03, 0x76, 0x18, 0x40 }, + { 0x03, 0x76, 0x18, 0x40 }, + { 0x03, 0x76, 0x18, 0x40 }, + { 0x03, 0x76, 0x18, 0x40 }, + { 0x03, 0x76, 0x18, 0x40 }, + { 0x03, 0x76, 0x18, 0x40 }, + { 0x03, 0x76, 0x18, 0x40 }, + { 0x03, 0x76, 0x18, 0x40 }, + { 0x03, 0x6E, 0x18, 0x40 }, + { 0x03, 0x6E, 0x18, 0x40 }, + { 0x03, 0x6E, 0x18, 0x40 }, + { 0x03, 0x6E, 0x18, 0x40 }, + { 0x03, 0x6E, 0x18, 0x40 }, + { 0x03, 0x6E, 0x18, 0x40 }, + { 0x03, 0x6E, 0x18, 0x40 }, + { 0x03, 0x6E, 0x18, 0x40 }, + { 0x03, 0x66, 0x18, 0x40 }, + { 0x03, 0x66, 0x18, 0x40 }, + { 0x03, 0x66, 0x18, 0x40 }, + { 0x03, 0x66, 0x18, 0x40 }, + { 0x03, 0x66, 0x18, 0x40 }, + { 0x03, 0x66, 0x18, 0x40 }, + { 0x03, 0x66, 0x18, 0x40 }, + { 0x03, 0x66, 0x18, 0x40 }, + { 0x03, 0x5E, 0x18, 0x40 }, + { 0x03, 0x5E, 0x18, 0x40 }, + { 0x03, 0x5E, 0x18, 0x40 }, + { 0x03, 0x5E, 0x18, 0x40 }, + { 0x03, 0x5E, 0x18, 0x40 }, + { 0x03, 0x5E, 0x18, 0x40 }, + { 0x03, 0x5E, 0x18, 0x40 }, + { 0x03, 0x5E, 0x18, 0x40 }, + { 0x03, 0x56, 0x18, 0x40 }, + { 0x03, 0x56, 0x18, 0x40 }, + { 0x03, 0x56, 0x18, 0x40 }, + { 0x03, 0x56, 0x18, 0x40 }, + { 0x03, 0x56, 0x18, 0x40 }, + { 0x03, 0x56, 0x18, 0x40 }, + { 0x03, 0x56, 0x18, 0x40 }, + { 0x03, 0x56, 0x18, 0x40 }, + { 0x03, 0x4E, 0x18, 0x40 }, + { 0x03, 0x4E, 0x18, 0x40 }, + { 0x03, 0x4E, 0x18, 0x40 }, + { 0x03, 0x4E, 0x18, 0x40 }, + { 0x03, 0x4E, 0x18, 0x40 }, + { 0x03, 0x4E, 0x18, 0x40 }, + { 0x03, 0x4E, 0x18, 0x40 }, + { 0x03, 0x4E, 0x18, 0x40 }, + { 0x03, 0x46, 0x18, 0x40 }, + { 0x03, 0x46, 0x18, 0x40 }, + { 0x03, 0x46, 0x18, 0x40 }, + { 0x03, 0x46, 0x18, 0x40 }, + { 0x03, 0x46, 0x18, 0x40 }, + { 0x03, 0x46, 0x18, 0x40 }, + { 0x03, 0x46, 0x18, 0x40 }, + { 0x03, 0x46, 0x18, 0x40 }, + { 0x03, 0x3E, 0x18, 0x40 }, + { 0x03, 0x3E, 0x18, 0x40 }, + { 0x03, 0x3E, 0x18, 0x40 }, + { 0x03, 0x3E, 0x18, 0x40 }, + { 0x03, 0x3E, 0x18, 0x40 }, + { 0x03, 0x3E, 0x18, 0x40 }, + { 0x03, 0x3E, 0x18, 0x40 }, + { 0x03, 0x3E, 0x18, 0x40 }, + { 0x03, 0x36, 0x18, 0x40 }, + { 0x03, 0x36, 0x18, 0x40 }, + { 0x03, 0x36, 0x18, 0x40 }, + { 0x03, 0x36, 0x18, 0x40 }, + { 0x03, 0x36, 0x18, 0x40 }, + { 0x03, 0x36, 0x18, 0x40 }, + { 0x03, 0x36, 0x18, 0x40 }, + { 0x03, 0x36, 0x18, 0x40 }, + { 0x03, 0x2E, 0x18, 0x40 }, + { 0x03, 0x2E, 0x18, 0x40 }, + { 0x03, 0x2E, 0x18, 0x40 }, + { 0x03, 0x2E, 0x18, 0x40 }, + { 0x03, 0x2E, 0x18, 0x40 }, + { 0x03, 0x2E, 0x18, 0x40 }, + { 0x03, 0x2E, 0x18, 0x40 }, + { 0x03, 0x2E, 0x18, 0x40 }, + { 0x03, 0x26, 0x18, 0x40 }, + { 0x03, 0x26, 0x18, 0x40 }, + { 0x03, 0x26, 0x18, 0x40 }, + { 0x03, 0x26, 0x18, 0x40 }, + { 0x03, 0x26, 0x18, 0x40 }, + { 0x03, 0x26, 0x18, 0x40 }, + { 0x03, 0x26, 0x18, 0x40 }, + { 0x03, 0x26, 0x18, 0x40 }, + { 0x03, 0x1E, 0x18, 0x40 }, + { 0x03, 0x1E, 0x18, 0x40 }, + { 0x03, 0x1E, 0x18, 0x40 }, + { 0x03, 0x1E, 0x18, 0x40 }, + { 0x03, 0x1E, 0x18, 0x40 }, + { 0x03, 0x1E, 0x18, 0x40 }, + { 0x03, 0x1E, 0x18, 0x40 }, + { 0x03, 0x1E, 0x18, 0x40 }, + { 0x03, 0x16, 0x18, 0x40 }, + { 0x03, 0x16, 0x18, 0x40 }, + { 0x03, 0x16, 0x18, 0x40 }, + { 0x03, 0x16, 0x18, 0x40 }, + { 0x03, 0x16, 0x18, 0x40 }, + { 0x03, 0x16, 0x18, 0x40 }, + { 0x03, 0x16, 0x18, 0x40 }, + { 0x03, 0x16, 0x18, 0x40 }, + { 0x03, 0x0E, 0x18, 0x40 }, + { 0x03, 0x0E, 0x18, 0x40 }, + { 0x03, 0x0E, 0x18, 0x40 }, + { 0x03, 0x0E, 0x18, 0x40 }, + { 0x03, 0x0E, 0x18, 0x40 }, + { 0x03, 0x0E, 0x18, 0x40 }, + { 0x03, 0x0E, 0x18, 0x40 }, + { 0x03, 0x0E, 0x18, 0x40 }, + { 0x03, 0x0E, 0x18, 0x40 }, + { 0x03, 0x06, 0x18, 0x40 }, + { 0x03, 0x06, 0x18, 0x40 }, + { 0x03, 0x06, 0x18, 0x40 }, + { 0x03, 0x06, 0x18, 0x40 }, + { 0x03, 0x06, 0x18, 0x40 }, + { 0x03, 0x06, 0x18, 0x40 }, + { 0x03, 0x06, 0x18, 0x40 }, + { 0x03, 0x06, 0x18, 0x40 }, + { 0x03, 0x06, 0x18, 0x40 }, + { 0x03, 0x06, 0x18, 0x40 }, + { 0x03, 0x06, 0x18, 0x40 }, + { 0x03, 0x06, 0x18, 0x40 }, + { 0x03, 0x06, 0x18, 0x40 }, + { 0x03, 0x06, 0x18, 0x40 }, + { 0x03, 0x06, 0x18, 0x40 } +}; + +RLPS_EQUALIZER_RAM pmc_e1_rlps_ram_table[] = +{ + { 0x07, 0xDE, 0x18, 0x2C }, + { 0x07, 0xDE, 0x18, 0x2C }, + { 0x07, 0xD6, 0x18, 0x2C }, + { 0x07, 0xD6, 0x18, 0x2C }, + { 0x07, 0xD6, 0x18, 0x2C }, + { 0x07, 0xCE, 0x18, 0x2C }, + { 0x07, 0xCE, 0x18, 0x2C }, + { 0x07, 0xCE, 0x18, 0x2C }, + { 0x07, 0xC6, 0x18, 0x2C }, + { 0x07, 0xC6, 0x18, 0x2C }, + { 0x07, 0xC6, 0x18, 0x2C }, + { 0x07, 0xBE, 0x18, 0x2C }, + { 0x07, 0xBE, 0x18, 0x2C }, + { 0x07, 0xBE, 0x18, 0x2C }, + { 0x07, 0xBE, 0x18, 0x2C }, + { 0x07, 0xBE, 0x18, 0x2C }, + { 0x07, 0xB6, 0x18, 0x2C }, + { 0x07, 0xB6, 0x18, 0x2C }, + { 0x07, 0xB6, 0x18, 0x2C }, + { 0x07, 0xB6, 0x18, 0x2C }, + { 0x07, 0xB6, 0x18, 0x2C }, + { 0x07, 0xAE, 0x18, 0x2C }, + { 0x07, 0xAE, 0x18, 0x2C }, + { 0x07, 0xAE, 0x18, 0x2C }, + { 0x07, 0xAE, 0x18, 0x2C }, + { 0x07, 0xAE, 0x18, 0x2C }, + { 0x07, 0xB6, 0x18, 0xAC }, + { 0x07, 0xAE, 0x18, 0xAC }, + { 0x07, 0xAE, 0x18, 0xAC }, + { 0x07, 0xAE, 0x18, 0xAC }, + { 0x07, 0xAE, 0x18, 0xAC }, + { 0x07, 0xA6, 0x18, 0xAC }, + { 0x07, 0xA6, 0x18, 0xAC }, + { 0x07, 0xA6, 0x18, 0xAC }, + { 0x07, 0xA6, 0x18, 0xAC }, + { 0x07, 0x9E, 0x18, 0xAC }, + { 0x07, 0xA6, 0x19, 0x2C }, + { 0x07, 0xA6, 0x19, 0x2C }, + { 0x07, 0xA6, 0x19, 0x2C }, + { 0x0F, 0xA6, 0x19, 0x2C }, + { 0x0F, 0xA6, 0x19, 0x2C }, + { 0x0F, 0x9E, 0x19, 0x2C }, + { 0x0F, 0x9E, 0x19, 0x2C }, + { 0x0F, 0x9E, 0x19, 0x2C }, + { 0x17, 0x9E, 0x19, 0x2C }, + { 0x17, 0xA6, 0x19, 0xAC }, + { 0x17, 0x9E, 0x19, 0xAC }, + { 0x17, 0x9E, 0x19, 0xAC }, + { 0x17, 0x96, 0x19, 0xAC }, + { 0x1F, 0x96, 0x19, 0xAC }, + { 0x1F, 0x96, 0x19, 0xAC }, + { 0x1F, 0x8E, 0x19, 0xAC }, + { 0x1F, 0x8E, 0x19, 0xAC }, + { 0x1F, 0x8E, 0x19, 0xAC }, + { 0x27, 0x8E, 0x19, 0xAC }, + { 0x27, 0x8E, 0x1A, 0x2C }, + { 0x27, 0x8E, 0x1A, 0x2C }, + { 0x27, 0x8E, 0x1A, 0x2C }, + { 0x27, 0x8E, 0x1A, 0x2C }, + { 0x2F, 0x86, 0x1A, 0x2C }, + { 0x2F, 0x86, 0x1A, 0x2C }, + { 0x2F, 0x86, 0x1A, 0x2C }, + { 0x2F, 0x7E, 0x1A, 0x2C }, + { 0x2F, 0x7E, 0x1A, 0x2C }, + { 0x2F, 0x7E, 0x1A, 0x2C }, + { 0x37, 0x7E, 0x1A, 0x2C }, + { 0x37, 0x7E, 0x1A, 0xAC }, + { 0x37, 0x7E, 0x1A, 0xAC }, + { 0x37, 0x7E, 0x1A, 0xAC }, + { 0x37, 0x7E, 0x1A, 0xAC }, + { 0x3F, 0x7E, 0x2A, 0xAC }, + { 0x3F, 0x7E, 0x2A, 0xAC }, + { 0x3F, 0x76, 0x2A, 0xAC }, + { 0x3F, 0x86, 0x2B, 0x2C }, + { 0x3F, 0x7E, 0x2B, 0x2C }, + { 0x47, 0x7E, 0x2B, 0x2C }, + { 0x47, 0x7E, 0x2F, 0x2C }, + { 0x47, 0x7E, 0x2F, 0x2C }, + { 0x47, 0x7E, 0x2F, 0x2C }, + { 0x47, 0x76, 0x2F, 0x2C }, + { 0x4F, 0x76, 0x2F, 0x2C }, + { 0x4F, 0x76, 0x2F, 0x2C }, + { 0x4F, 0x6E, 0x2F, 0x2C }, + { 0x4F, 0x6E, 0x2F, 0x2C }, + { 0x4F, 0x6E, 0x2F, 0x2C }, + { 0x57, 0x6E, 0x2F, 0x2C }, + { 0x57, 0x6E, 0x2F, 0x2C }, + { 0x57, 0x6E, 0x3F, 0x2C }, + { 0x57, 0x6E, 0x3F, 0x2C }, + { 0x57, 0x6E, 0x3F, 0x2C }, + { 0x5F, 0x6E, 0x3F, 0x2C }, + { 0x5F, 0x6E, 0x4F, 0x2C }, + { 0x5F, 0x6E, 0x4F, 0x2C }, + { 0x5F, 0x6E, 0x4F, 0x2C }, + { 0x5F, 0x66, 0x4F, 0x2C }, + { 0x67, 0x66, 0x4F, 0x2C }, + { 0x67, 0x66, 0x4F, 0x2C }, + { 0x67, 0x5E, 0x4F, 0x2C }, + { 0x67, 0x5E, 0x4F, 0x2C }, + { 0x67, 0x66, 0x4F, 0x2C }, + { 0x67, 0x66, 0x4F, 0x2C }, + { 0x67, 0x66, 0x5F, 0x2C }, + { 0x6F, 0x6E, 0x5F, 0x2C }, + { 0x6F, 0x6E, 0x6F, 0x2C }, + { 0x6F, 0x6E, 0x6F, 0x2C }, + { 0x6F, 0x6E, 0x7F, 0x2C }, + { 0x6F, 0x6E, 0x7F, 0x2C }, + { 0x6F, 0x6E, 0x7F, 0x2C }, + { 0x77, 0x66, 0x7F, 0x2C }, + { 0x77, 0x66, 0x7F, 0x2C }, + { 0x77, 0x5E, 0x6F, 0x2C }, + { 0x77, 0x5E, 0x7F, 0x2C }, + { 0x77, 0x5E, 0x7F, 0x2C }, + { 0x7F, 0x5E, 0x7F, 0x2C }, + { 0x7F, 0x5E, 0x8F, 0x2C }, + { 0x7F, 0x5E, 0x8F, 0x2C }, + { 0x7F, 0x5E, 0x8F, 0x2C }, + { 0x87, 0x56, 0x8F, 0x2C }, + { 0x87, 0x56, 0x8F, 0x2C }, + { 0x87, 0x56, 0x8F, 0x2C }, + { 0x87, 0x4E, 0x8F, 0x2C }, + { 0x87, 0x4E, 0x8F, 0x2C }, + { 0x87, 0x4E, 0x8F, 0x2C }, + { 0x8F, 0x4E, 0x9F, 0x2C }, + { 0x8F, 0x4E, 0x9F, 0x2C }, + { 0x8F, 0x4E, 0xAF, 0x2C }, + { 0x8F, 0x4E, 0xAF, 0x2C }, + { 0x8F, 0x4E, 0xAF, 0x2C }, + { 0x97, 0x4E, 0xAF, 0x2C }, + { 0x97, 0x4E, 0xAF, 0x2C }, + { 0x97, 0x4E, 0xAB, 0x2C }, + { 0x97, 0x4E, 0xAB, 0x2C }, + { 0x97, 0x4E, 0xAB, 0x2C }, + { 0x9F, 0x4E, 0xAB, 0x2C }, + { 0x9F, 0x4E, 0xBB, 0x2C }, + { 0x9F, 0x4E, 0xBB, 0x2C }, + { 0x9F, 0x4E, 0xBB, 0x2C }, + { 0x9F, 0x4E, 0xCB, 0x2C }, + { 0xA7, 0x4E, 0xCB, 0x2C }, + { 0xA7, 0x4E, 0xCB, 0x2C }, + { 0xA7, 0x46, 0xCB, 0x2C }, + { 0xA7, 0x46, 0xCB, 0x2C }, + { 0xA7, 0x46, 0xCB, 0x2C }, + { 0xA7, 0x46, 0xDB, 0x2C }, + { 0xAF, 0x46, 0xDB, 0x2C }, + { 0xAF, 0x46, 0xEB, 0x2C }, + { 0xAF, 0x46, 0xEB, 0x2C }, + { 0xAF, 0x4E, 0xEB, 0x2C }, + { 0xAE, 0x4E, 0xEB, 0x2C }, + { 0xAE, 0x4E, 0xEB, 0x2C }, + { 0xB5, 0x46, 0xFB, 0x2C }, + { 0xB5, 0x54, 0xFB, 0x2C }, + { 0xB5, 0x4C, 0xFB, 0x2C }, + { 0xB5, 0x54, 0xFB, 0x2C }, + { 0xB5, 0x54, 0xFB, 0x2C }, + { 0xBD, 0x54, 0xFB, 0x2C }, + { 0xBD, 0x4C, 0xFB, 0x2C }, + { 0xBD, 0x4C, 0xFB, 0x2C }, + { 0xBD, 0x4C, 0xFB, 0x2C }, + { 0xBD, 0x44, 0xEB, 0x2C }, + { 0xC5, 0x44, 0xFB, 0x2C }, + { 0xC5, 0x44, 0xFB, 0x2C }, + { 0xC5, 0x44, 0xFB, 0x2C }, + { 0xC5, 0x45, 0x0B, 0x2C }, + { 0xC5, 0x45, 0x0B, 0x2C }, + { 0xC5, 0x45, 0x0B, 0x2C }, + { 0xCD, 0x45, 0x0B, 0x2C }, + { 0xCD, 0x45, 0x0B, 0x2C }, + { 0xCD, 0x3D, 0x0B, 0x2C }, + { 0xCD, 0x3D, 0x0B, 0x2C }, + { 0xCD, 0x3D, 0x0B, 0x2C }, + { 0xD5, 0x3D, 0x0B, 0x2C }, + { 0xD5, 0x3D, 0x0B, 0x2C }, + { 0xD5, 0x3D, 0x1B, 0x2C }, + { 0xD5, 0x3D, 0x1B, 0x2C }, + { 0xD5, 0x3D, 0x1B, 0x2C }, + { 0xDD, 0x3D, 0x1B, 0x2C }, + { 0xDD, 0x3D, 0x1B, 0x2C }, + { 0xDD, 0x35, 0x1B, 0x2C }, + { 0xDD, 0x35, 0x1B, 0x2C }, + { 0xDD, 0x35, 0x1B, 0x2C }, + { 0xE5, 0x35, 0x1B, 0x2C }, + { 0xE5, 0x35, 0x1B, 0x2C }, + { 0xE5, 0x2D, 0x1B, 0x2C }, + { 0xE5, 0x2D, 0x1B, 0x2C }, + { 0xE5, 0x2D, 0x3B, 0x2C }, + { 0xED, 0x2D, 0x4B, 0x2C }, + { 0xED, 0x2D, 0x1B, 0xA8 }, + { 0xED, 0x2D, 0x1B, 0xAC }, + { 0xED, 0x2D, 0x17, 0xAC }, + { 0xED, 0x2D, 0x17, 0xAC }, + { 0xED, 0x2D, 0x27, 0xAC }, + { 0xF5, 0x2D, 0x27, 0xAC }, + { 0xF5, 0x2D, 0x27, 0xAC }, + { 0xF5, 0x2D, 0x2B, 0xAC }, + { 0xF5, 0x2D, 0x2B, 0xAC }, + { 0xF5, 0x2D, 0x2B, 0xAC }, + { 0xFD, 0x2D, 0x2B, 0xAC }, + { 0xFD, 0x2B, 0x2B, 0xAC }, + { 0xFD, 0x2B, 0x2B, 0xAC }, + { 0xFD, 0x2B, 0x2B, 0xAC }, + { 0xFD, 0x2B, 0x2B, 0xAC }, + { 0xFD, 0x23, 0x2B, 0xAC }, + { 0xFD, 0x23, 0x2B, 0xAC }, + { 0xFD, 0x23, 0x2B, 0xAC }, + { 0xFD, 0x21, 0x2B, 0xAC }, + { 0xFD, 0x21, 0x2B, 0xAC }, + { 0xFD, 0x29, 0x2B, 0xAC }, + { 0xFD, 0x29, 0x2B, 0xAC }, + { 0xFD, 0x29, 0x27, 0xAC }, + { 0xFD, 0x29, 0x37, 0xAC }, + { 0xFD, 0x29, 0x23, 0xAC }, + { 0xFD, 0x29, 0x23, 0xAC }, + { 0xFD, 0x29, 0x23, 0xAC }, + { 0xFD, 0x29, 0x23, 0xAC }, + { 0xFD, 0x21, 0x23, 0xAC }, + { 0xFD, 0x21, 0x23, 0xAC }, + { 0xFD, 0x21, 0x23, 0xAC }, + { 0xFD, 0x21, 0x33, 0xAC }, + { 0xFD, 0x21, 0x33, 0xAC }, + { 0xFD, 0x21, 0x33, 0xAC }, + { 0xFD, 0x21, 0x43, 0xAC }, + { 0xFD, 0x21, 0x43, 0xAC }, + { 0xFD, 0x21, 0x43, 0xAC }, + { 0xFC, 0x21, 0x43, 0xAC }, + { 0xFC, 0x21, 0x43, 0xAC }, + { 0xFC, 0x19, 0x43, 0xAC }, + { 0xFC, 0x19, 0x43, 0xAC }, + { 0xFC, 0x19, 0x43, 0xAC }, + { 0xFC, 0x19, 0x43, 0xAC }, + { 0xFC, 0x19, 0x53, 0xAC }, + { 0xFC, 0x19, 0x53, 0xAC }, + { 0xFC, 0x19, 0x53, 0xAC }, + { 0xFC, 0x19, 0x53, 0xAC }, + { 0xFC, 0x19, 0x63, 0xAC }, + { 0xFC, 0x19, 0x63, 0xAC }, + { 0xFC, 0x19, 0x63, 0xAC }, + { 0xFC, 0x19, 0x73, 0xAC }, + { 0xFC, 0x19, 0x73, 0xAC }, + { 0xFC, 0x19, 0x73, 0xAC }, + { 0xFC, 0x19, 0x73, 0xAC }, + { 0xFC, 0x19, 0x73, 0xAC }, + { 0xFC, 0x19, 0x83, 0xAC }, + { 0xFC, 0x19, 0x83, 0xAC }, + { 0xFC, 0x19, 0x83, 0xAC }, + { 0xFC, 0x19, 0x83, 0xAC }, + { 0xFC, 0x19, 0x83, 0xAC }, + { 0xFC, 0x19, 0x93, 0xAC }, + { 0xFC, 0x19, 0x93, 0xAC }, + { 0xFC, 0x19, 0x93, 0xAC }, + { 0xFC, 0x19, 0xA3, 0xAC }, + { 0xFC, 0x19, 0xA3, 0xAC }, + { 0xFC, 0x19, 0xB3, 0xAC }, + { 0xFC, 0x19, 0xB3, 0xAC }, + { 0xFC, 0x19, 0xB3, 0xAC }, + { 0xFC, 0x19, 0xB3, 0xAC } +}; +RLPS_EQUALIZER_RAM pmc4_e1_rlps_ram_table[] = +{ + { 0x0F, 0xD6, 0x1C, 0x2C }, /* 0d */ + { 0x0F, 0xD6, 0x1C, 0x2C }, /* 1d */ + { 0x0F, 0xD6, 0x2C, 0x2C }, /* 2d */ + { 0x0F, 0xD6, 0x2C, 0x2C }, /* 3d */ + { 0x0F, 0xD6, 0x3C, 0x2C }, /* 4d */ + { 0x0F, 0xD6, 0x3C, 0x2C }, /* 5d */ + { 0x0F, 0xCE, 0x3C, 0x2C }, /* 6d */ + { 0x0F, 0xCE, 0x3C, 0x2C }, /* 7d */ + { 0x0F, 0xCE, 0x3C, 0x2C }, /* 8d */ + { 0x17, 0xCE, 0x3C, 0x2C }, /* 9d */ + { 0x17, 0xCE, 0x3C, 0x2C }, /* 10d */ + { 0x17, 0xCE, 0x4C, 0x2C }, /* 11d */ + { 0x17, 0xCE, 0x4C, 0x2C }, /* 12d */ + { 0x17, 0xCE, 0x4C, 0x2C }, /* 13d */ + { 0x17, 0xCE, 0x4C, 0x2C }, /* 14d */ + { 0x17, 0xCE, 0x4C, 0x2C }, /* 15d */ + { 0x17, 0xCE, 0x4C, 0x2C }, /* 16d */ + { 0x1F, 0xC6, 0x4C, 0x2C }, /* 17d */ + { 0x1F, 0xC6, 0x4C, 0x2C }, /* 18d */ + { 0x1F, 0xC6, 0x4C, 0x2C }, /* 19d */ + { 0x1F, 0xC6, 0x4C, 0x2C }, /* 20d */ + { 0x1F, 0xC6, 0x4C, 0x2C }, /* 21d */ + { 0x1F, 0xC6, 0x5C, 0x2C }, /* 22d */ + { 0x1F, 0xC6, 0x5C, 0x2C }, /* 23d */ + { 0x1F, 0xC6, 0x5C, 0x2C }, /* 24d */ + { 0x1F, 0xC6, 0x5C, 0x2C }, /* 25d */ + { 0x27, 0xC6, 0x5C, 0x2C }, /* 26d */ + { 0x27, 0xC6, 0x5C, 0x2C }, /* 27d */ + { 0x27, 0xC6, 0x7C, 0x32 }, /* 28d */ + { 0x27, 0xC6, 0x8C, 0x32 }, /* 29d */ + { 0x27, 0xC6, 0x9C, 0x32 }, /* 30d */ + { 0x27, 0xC6, 0xAC, 0x32 }, /* 31d */ + { 0x27, 0xC6, 0xBC, 0x32 }, /* 32d */ + { 0x27, 0xC6, 0xCC, 0x32 }, /* 33d */ + { 0x2F, 0xC6, 0xDC, 0x32 }, /* 34d */ + { 0x2F, 0xC6, 0xEC, 0x32 }, /* 35d */ + { 0x2F, 0xC7, 0x0C, 0x32 }, /* 36d */ + { 0x2F, 0xC7, 0x2C, 0x32 }, /* 37d */ + { 0x2F, 0xBC, 0x68, 0x32 }, /* 38d */ + { 0x2F, 0xBC, 0x68, 0x2C }, /* 39d */ + { 0x2F, 0xB4, 0x68, 0x2C }, /* 40d */ + { 0x2F, 0xB4, 0x68, 0x2C }, /* 41d */ + { 0x37, 0xB4, 0x68, 0x2C }, /* 42d */ + { 0x37, 0xB4, 0x78, 0x2C }, /* 43d */ + { 0x37, 0xB4, 0x78, 0x2C }, /* 44d */ + { 0x37, 0xB4, 0x78, 0x2C }, /* 45d */ + { 0x37, 0xB4, 0x78, 0x2C }, /* 46d */ + { 0x37, 0xB4, 0x78, 0x2C }, /* 47d */ + { 0x37, 0xB4, 0x78, 0x2C }, /* 48d */ + { 0x37, 0xAC, 0x78, 0x2C }, /* 49d */ + { 0x37, 0xAC, 0x78, 0x2C }, /* 50d */ + { 0x3F, 0xAC, 0x78, 0x2C }, /* 51d */ + { 0x3F, 0xAC, 0x78, 0x2C }, /* 52d */ + { 0x3F, 0xAC, 0x78, 0x2C }, /* 53d */ + { 0x3F, 0xAC, 0x78, 0x2C }, /* 54d */ + { 0x3F, 0xAC, 0x78, 0x2C }, /* 55d */ + { 0x3F, 0xAC, 0x78, 0x2C }, /* 56d */ + { 0x3F, 0xAC, 0x78, 0x2C }, /* 57d */ + { 0x3F, 0xAC, 0x78, 0x2C }, /* 58d */ + { 0x47, 0xAC, 0x78, 0x2C }, /* 59d */ + { 0x47, 0xAC, 0x88, 0x2C }, /* 60d */ + { 0x47, 0xAC, 0x88, 0x2C }, /* 61d */ + { 0x47, 0xAC, 0x98, 0x2C }, /* 62d */ + { 0x47, 0xAC, 0x98, 0x2C }, /* 63d */ + { 0x47, 0xAC, 0x68, 0xAC }, /* 64d */ + { 0x47, 0xAC, 0x68, 0xAC }, /* 65d */ + { 0x47, 0xAC, 0x78, 0xAC }, /* 66d */ + { 0x4F, 0xAC, 0x78, 0xAC }, /* 67d */ + { 0x4F, 0xA4, 0x88, 0xAC }, /* 68d */ + { 0x4F, 0xA4, 0x88, 0xAC }, /* 69d */ + { 0x4F, 0xA4, 0x98, 0xAC }, /* 70d */ + { 0x4F, 0x9C, 0x98, 0xAC }, /* 71d */ + { 0x4F, 0x9C, 0x98, 0xAC }, /* 72d */ + { 0x4F, 0x9C, 0x98, 0xAC }, /* 73d */ + { 0x4F, 0x9C, 0x98, 0xAC }, /* 74d */ + { 0x4F, 0x9C, 0xA8, 0xAC }, /* 75d */ + { 0x57, 0x9C, 0xA8, 0xAC }, /* 76d */ + { 0x57, 0x9C, 0xA8, 0xAC }, /* 77d */ + { 0x57, 0x9C, 0xA8, 0xAC }, /* 78d */ + { 0x57, 0x9C, 0xA8, 0xAC }, /* 79d */ + { 0x57, 0x9C, 0xA8, 0xAC }, /* 80d */ + { 0x57, 0x9C, 0xA8, 0xAC }, /* 81d */ + { 0x57, 0x94, 0xA8, 0xAC }, /* 82d */ + { 0x57, 0x94, 0xA8, 0xAC }, /* 83d */ + { 0x5F, 0x94, 0xA8, 0xAC }, /* 84d */ + { 0x5F, 0x94, 0xA8, 0xAC }, /* 85d */ + { 0x5F, 0x94, 0xB8, 0xAC }, /* 86d */ + { 0x5F, 0x94, 0xB8, 0xAC }, /* 87d */ + { 0x5F, 0x94, 0xB8, 0xAC }, /* 88d */ + { 0x5F, 0x94, 0xB8, 0xAC }, /* 89d */ + { 0x5F, 0x94, 0xB8, 0xAC }, /* 90d */ + { 0x5F, 0x94, 0xB8, 0xAC }, /* 91d */ + { 0x67, 0x94, 0xB8, 0xAC }, /* 92d */ + { 0x67, 0x8C, 0xB8, 0xAC }, /* 93d */ + { 0x67, 0x8C, 0xB8, 0xAC }, /* 94d */ + { 0x67, 0x8C, 0xB8, 0xAC }, /* 95d */ + { 0x67, 0x8C, 0x99, 0x2C }, /* 96d */ + { 0x67, 0x8C, 0x99, 0x2C }, /* 97d */ + { 0x67, 0x8C, 0x99, 0x2C }, /* 98d */ + { 0x67, 0x8C, 0xA9, 0x2C }, /* 99d */ + { 0x67, 0x8C, 0xA9, 0x2C }, /* 100d */ + { 0x6F, 0x8C, 0xB9, 0x2C }, /* 101d */ + { 0x6F, 0x8C, 0xB9, 0x2C }, /* 102d */ + { 0x6F, 0x8C, 0xC9, 0x2C }, /* 103d */ + { 0x6F, 0x84, 0xC9, 0x2C }, /* 104d */ + { 0x6F, 0x84, 0xC9, 0x2C }, /* 105d */ + { 0x6F, 0x84, 0xE9, 0x2C }, /* 106d */ + { 0x6F, 0x85, 0x09, 0x2C }, /* 107d */ + { 0x6F, 0x85, 0x29, 0x2C }, /* 108d */ + { 0x77, 0x85, 0x09, 0x2C }, /* 109d */ + { 0x77, 0x84, 0xF5, 0x22 }, /* 110d */ + { 0x77, 0x84, 0xF5, 0x22 }, /* 111d */ + { 0x77, 0x84, 0xD5, 0xAC }, /* 112d */ + { 0x77, 0x84, 0xD5, 0xAC }, /* 113d */ + { 0x77, 0x7C, 0xD5, 0xAC }, /* 114d */ + { 0x77, 0x7C, 0xE5, 0xAC }, /* 115d */ + { 0x77, 0x7C, 0xF5, 0xAC }, /* 116d */ + { 0x77, 0x7D, 0x05, 0xAC }, /* 117d */ + { 0x7F, 0x7D, 0x15, 0xAC }, /* 118d */ + { 0x7F, 0x7D, 0x25, 0xAC }, /* 119d */ + { 0x7F, 0x72, 0xE5, 0xAC }, /* 120d */ + { 0x7F, 0x72, 0xE5, 0xAC }, /* 121d */ + { 0x7F, 0x72, 0xE5, 0xAC }, /* 122d */ + { 0x7F, 0x72, 0xE5, 0xAC }, /* 123d */ + { 0x7F, 0x72, 0xE5, 0xAC }, /* 124d */ + { 0x7F, 0x72, 0xE5, 0xAC }, /* 125d */ + { 0x87, 0x73, 0x05, 0xAC }, /* 126d */ + { 0x87, 0x73, 0x05, 0xAC }, /* 127d */ + { 0x87, 0x73, 0x05, 0xAC }, /* 128d */ + { 0x86, 0x72, 0xF6, 0x2C }, /* 129d */ + { 0x86, 0x72, 0xF6, 0x2C }, /* 130d */ + { 0x86, 0x72, 0xF6, 0x2C }, /* 131d */ + { 0x86, 0x72, 0xF6, 0x2C }, /* 132d */ + { 0x86, 0x72, 0xF6, 0x2C }, /* 133d */ + { 0x8E, 0x72, 0xF6, 0x2C }, /* 134d */ + { 0x8E, 0x72, 0xF6, 0x2C }, /* 135d */ + { 0x8E, 0x6A, 0xF6, 0x2C }, /* 136d */ + { 0x8E, 0x6A, 0xF6, 0x2C }, /* 137d */ + { 0x8E, 0x6A, 0xF6, 0x2C }, /* 138d */ + { 0x8E, 0x6B, 0x06, 0x2C }, /* 139d */ + { 0x8E, 0x6B, 0x06, 0x2C }, /* 140d */ + { 0x8E, 0x6B, 0x06, 0x2C }, /* 141d */ + { 0x8E, 0x6B, 0x06, 0x2C }, /* 142d */ + { 0x96, 0x6B, 0x06, 0x2C }, /* 143d */ + { 0x96, 0x6B, 0x06, 0xAC }, /* 144d */ + { 0x95, 0x6B, 0x06, 0xAC }, /* 145d */ + { 0x95, 0x6B, 0x06, 0xAC }, /* 146d */ + { 0x95, 0x63, 0x06, 0xAC }, /* 147d */ + { 0x95, 0x63, 0x06, 0xAC }, /* 148d */ + { 0x95, 0x63, 0x06, 0xAC }, /* 149d */ + { 0x95, 0x63, 0x16, 0xAC }, /* 150d */ + { 0x9D, 0x63, 0x16, 0xAC }, /* 151d */ + { 0x9D, 0x63, 0x16, 0xAC }, /* 152d */ + { 0x9D, 0x63, 0x16, 0xAC }, /* 153d */ + { 0x9D, 0x63, 0x16, 0xAC }, /* 154d */ + { 0x9D, 0x63, 0x16, 0xAC }, /* 155d */ + { 0x9D, 0x5B, 0x16, 0xAC }, /* 156d */ + { 0x9D, 0x5B, 0x16, 0xAC }, /* 157d */ + { 0x9D, 0x5B, 0x26, 0xAC }, /* 158d */ + { 0xA5, 0x5B, 0x26, 0xAC }, /* 159d */ + { 0xA5, 0x5A, 0xF7, 0x2C }, /* 160d */ + { 0xA5, 0x5A, 0xF7, 0x2C }, /* 161d */ + { 0xA5, 0x5B, 0x07, 0x2C }, /* 162d */ + { 0xA5, 0x5B, 0x07, 0x2C }, /* 163d */ + { 0xA5, 0x5B, 0x17, 0x2C }, /* 164d */ + { 0xA5, 0x5B, 0x17, 0x2C }, /* 165d */ + { 0xA5, 0x5B, 0x27, 0x2C }, /* 166d */ + { 0xA5, 0x5B, 0x27, 0x2C }, /* 167d */ + { 0xAD, 0x5B, 0x27, 0x2C }, /* 168d */ + { 0xAD, 0x53, 0x27, 0x2C }, /* 169d */ + { 0xAD, 0x53, 0x27, 0x2C }, /* 170d */ + { 0xAD, 0x53, 0x37, 0x2C }, /* 171d */ + { 0xAD, 0x53, 0x37, 0x2C }, /* 172d */ + { 0xAD, 0x53, 0x37, 0x2C }, /* 173d */ + { 0xAD, 0x53, 0x37, 0x2C }, /* 174d */ + { 0xAD, 0x53, 0x37, 0x2C }, /* 175d */ + { 0xB5, 0x53, 0x37, 0x2C }, /* 176d */ + { 0xB5, 0x53, 0x33, 0x2C }, /* 177d */ + { 0xB5, 0x53, 0x33, 0x2C }, /* 178d */ + { 0xB5, 0x53, 0x33, 0x2C }, /* 179d */ + { 0xB5, 0x53, 0x43, 0x2C }, /* 180d */ + { 0xB5, 0x53, 0x43, 0x2C }, /* 181d */ + { 0xB5, 0x53, 0x43, 0x2C }, /* 182d */ + { 0xB5, 0x49, 0x03, 0x2C }, /* 183d */ + { 0xBD, 0x49, 0x03, 0x2C }, /* 184d */ + { 0xBD, 0x49, 0x13, 0x2C }, /* 185d */ + { 0xBD, 0x49, 0x23, 0x2C }, /* 186d */ + { 0xBD, 0x49, 0x33, 0x2C }, /* 187d */ + { 0xBD, 0x49, 0x33, 0x2C }, /* 188d */ + { 0xBD, 0x49, 0x33, 0x2C }, /* 189d */ + { 0xBD, 0x49, 0x33, 0x2C }, /* 190d */ + { 0xBD, 0x49, 0x33, 0x2C }, /* 191d */ + { 0xBD, 0x49, 0x33, 0x2C }, /* 192d */ + { 0xC5, 0x49, 0x33, 0x2C }, /* 193d */ + { 0xC5, 0x49, 0x43, 0x2C }, /* 194d */ + { 0xC5, 0x49, 0x43, 0x2C }, /* 195d */ + { 0xC5, 0x49, 0x53, 0x2C }, /* 196d */ + { 0xC5, 0x41, 0x53, 0x2C }, /* 197d */ + { 0xC5, 0x41, 0x53, 0x2C }, /* 198d */ + { 0xC5, 0x41, 0x53, 0x2C }, /* 199d */ + { 0xC5, 0x41, 0x53, 0x2C }, /* 200d */ + { 0xCD, 0x39, 0x53, 0x2C }, /* 201d */ + { 0xCD, 0x39, 0x53, 0x2C }, /* 202d */ + { 0xCD, 0x39, 0x63, 0x2C }, /* 203d */ + { 0xCD, 0x39, 0x63, 0x2C }, /* 204d */ + { 0xCC, 0x39, 0x63, 0x2C }, /* 205d */ + { 0xCC, 0x39, 0x63, 0x2C }, /* 206d */ + { 0xCC, 0x39, 0x63, 0xAC }, /* 207d */ + { 0xCC, 0x39, 0x63, 0xAC }, /* 208d */ + { 0xCC, 0x39, 0x63, 0xAC }, /* 209d */ + { 0xD4, 0x39, 0x63, 0xAC }, /* 210d */ + { 0xD4, 0x39, 0x63, 0xAC }, /* 211d */ + { 0xD4, 0x31, 0x63, 0xAC }, /* 212d */ + { 0xD4, 0x31, 0x63, 0xAC }, /* 213d */ + { 0xD4, 0x31, 0x73, 0xAC }, /* 214d */ + { 0xD4, 0x31, 0x73, 0xAC }, /* 215d */ + { 0xD4, 0x31, 0x73, 0xAC }, /* 216d */ + { 0xD4, 0x31, 0x73, 0xAC }, /* 217d */ + { 0xDC, 0x31, 0x73, 0xAC }, /* 218d */ + { 0xDC, 0x31, 0x73, 0xAC }, /* 219d */ + { 0xDC, 0x31, 0x73, 0xAC }, /* 220d */ + { 0xDC, 0x31, 0x73, 0xAC }, /* 221d */ + { 0xDC, 0x31, 0x73, 0xAC }, /* 222d */ + { 0xDC, 0x29, 0x73, 0xAC }, /* 223d */ + { 0xDC, 0x29, 0x73, 0xAC }, /* 224d */ + { 0xDC, 0x29, 0x83, 0xAC }, /* 225d */ + { 0xE4, 0x29, 0x83, 0xAC }, /* 226d */ + { 0xE4, 0x29, 0x83, 0xAC }, /* 227d */ + { 0xE4, 0x29, 0x83, 0xAC }, /* 228d */ + { 0xE4, 0x29, 0x83, 0xAC }, /* 229d */ + { 0xE4, 0x29, 0x83, 0xAC }, /* 230d */ + { 0xE4, 0x29, 0x83, 0xAC }, /* 231d */ + { 0xE4, 0x29, 0x83, 0xAC }, /* 232d */ + { 0xE4, 0x29, 0x83, 0xAC }, /* 233d */ + { 0xE4, 0x21, 0x83, 0xAC }, /* 234d */ + { 0xEC, 0x21, 0x93, 0xAC }, /* 235d */ + { 0xEC, 0x21, 0x93, 0xAC }, /* 236d */ + { 0xEC, 0x21, 0x93, 0xAC }, /* 237d */ + { 0xEC, 0x21, 0x93, 0xAC }, /* 238d */ + { 0xEC, 0x21, 0x93, 0xAC }, /* 239d */ + { 0xEC, 0x21, 0x93, 0xAC }, /* 240d */ + { 0xEC, 0x21, 0x93, 0xAC }, /* 241d */ + { 0xEC, 0x21, 0x93, 0xAC }, /* 242d */ + { 0xF4, 0x21, 0x93, 0xAC }, /* 243d */ + { 0xF4, 0x21, 0x93, 0xAC }, /* 244d */ + { 0xF4, 0x19, 0x93, 0xAC }, /* 245d */ + { 0xF4, 0x19, 0xA3, 0xAC }, /* 246d */ + { 0xF4, 0x19, 0xA3, 0xAC }, /* 247d */ + { 0xF4, 0x19, 0xA3, 0xAC }, /* 248d */ + { 0xF4, 0x19, 0xA3, 0xAC }, /* 249d */ + { 0xF4, 0x19, 0xA3, 0xAC }, /* 250d */ + { 0xFC, 0x19, 0xA3, 0xAC }, /* 251d */ + { 0xFC, 0x19, 0xA3, 0xAC }, /* 252d */ + { 0xFC, 0x19, 0xA3, 0xAC }, /* 253d */ + { 0xFC, 0x19, 0xA3, 0xAC }, /* 254d */ + { 0xFC, 0x19, 0xA3, 0xAC } /* 255d */ +}; + + +/****************************************************************************** +* FUNCTION PROTOTYPES +******************************************************************************/ +static int sdla_te_global_config(void* pfe); +static int sdla_te_global_unconfig(void* pfe); +static int sdla_te_config(void* pfe); +static int sdla_te_unconfig(void* pfe); +static void ClearTemplate(sdla_fe_t* fe); +static unsigned char PrgTransmitTemplate(sdla_fe_t* fe); +static void InitLineReceiver(sdla_fe_t* fe, RLPS_EQUALIZER_RAM* rlps_table); + +static void ClearTPSCReg(sdla_fe_t* fe); +static void ClearRPSCReg(sdla_fe_t* fe); + +static int WriteTPSCReg(sdla_fe_t*, int reg, int channel, unsigned char value); +static unsigned char ReadTPSCReg(sdla_fe_t* fe, int reg, int channel); + +static int WriteRPSCReg(sdla_fe_t*, int reg, int channel, unsigned char value); +static unsigned char ReadRPSCReg(sdla_fe_t* fe, int reg, int channel); + +#if 0 +static int WriteSIGXReg(sdla_fe_t*, int reg, int channel, unsigned char value); +#endif +static unsigned char ReadSIGXReg(sdla_fe_t* fe, int reg, int channel); + +#if 0 +static void sdla_channels(void*, unsigned long); +#endif +static void DisableAllChannels(sdla_fe_t* fe); +static void EnableAllChannels(sdla_fe_t* fe); +static int DisableTxChannel(sdla_fe_t* fe, int channel); +static int DisableRxChannel(sdla_fe_t* fe, int channel); +static int EnableTxChannel(sdla_fe_t* fe, int channel); +static int EnableRxChannel(sdla_fe_t* fe, int channel); + +static int sdla_te_post_config(sdla_fe_t* fe); + +static void sdla_te_set_intr(sdla_fe_t* fe); +static void sdla_te_clear_intr(sdla_fe_t* fe); +static void sdla_te_tx_intr(sdla_fe_t*); +static void sdla_te_rx_intr(sdla_fe_t*); +static void sdla_t1_rx_intr(sdla_fe_t*); +static void sdla_e1_rx_intr(sdla_fe_t*); + +static int sdla_te_intr(sdla_fe_t *); +static int sdla_te_check_intr(sdla_fe_t *); +static int sdla_te_polling(sdla_fe_t*); +static int sdla_te_udp(sdla_fe_t*, void*, unsigned char*); +static void sdla_te_set_status(sdla_fe_t*, unsigned long); +static int sdla_te_get_snmp_data(sdla_fe_t* fe, void* pdev, void* data); +static int sdla_te_set_lbmode(sdla_fe_t*, unsigned char, unsigned char); + +static void sdla_te_enable_timer(sdla_fe_t*, unsigned char, unsigned long); + +static int sdla_te_linelb(sdla_fe_t*, unsigned char); +static int sdla_te_paylb(sdla_fe_t*, unsigned char); +static int sdla_te_ddlb(sdla_fe_t*, unsigned char); +static int sdla_te_lb(sdla_fe_t*, unsigned char); +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) +static void sdla_te_timer(void*); +#elif defined(__WINDOWS__) +static void sdla_te_timer(IN PKDPC,void*,void*,void*); +#else +static void sdla_te_timer(unsigned long); +#endif +static int sdla_te_check_rbsbits(sdla_fe_t*, int, unsigned int, int); +static unsigned char sdla_te_read_rbsbits(sdla_fe_t*, int, int); +static int sdla_te_set_rbsbits(sdla_fe_t*, int, unsigned char); +static int sdla_te_rbs_report(sdla_fe_t* fe); +static int sdla_te_rbs_print(sdla_fe_t* fe, int); + +#if 0 +static void sdla_te_abcd_update(sdla_fe_t* fe); +#endif + +static int sdla_te_pmon(sdla_fe_t *fe, int); +static int sdla_te_flush_pmon(sdla_fe_t *fe); +static unsigned int sdla_te_read_alarms(sdla_fe_t *fe, int action); +static int sdla_te_print_alarms(sdla_fe_t* fe, unsigned int); +static char* sdla_te_print_channels(sdla_fe_t* fe); +static int sdla_te_set_alarms(sdla_fe_t* pfe, unsigned int); +static int sdla_te_clear_alarms(sdla_fe_t* pfe, unsigned long); +static int sdla_te_sigctrl(sdla_fe_t*, int); + +static int sdla_te_update_alarm_info(sdla_fe_t*, struct seq_file*, int*); +static int sdla_te_update_pmon_info(sdla_fe_t*, struct seq_file*, int*); + +static int sdla_te_led_ctrl(sdla_fe_t *fe, int mode); +/****************************************************************************** +* FUNCTION DEFINITIONS +******************************************************************************/ +/****************************************************************************** + * sdla_te3_get_fe_status() + * + * Description: + * Arguments: + * Returns: + ****************************************************************************** + */ +static char* sdla_te_get_fe_media_string(void) +{ + return ("S514/AFT T1/E1"); +} + +/****************************************************************************** + * sdla_te3_get_fe_status() + * + * Description: + * Arguments: + * Returns: + ****************************************************************************** + */ +static unsigned char sdla_te_get_fe_media(sdla_fe_t *fe) +{ + return fe->fe_cfg.media; +} + +/****************************************************************************** + * sdla_te3_get_fe_status() + * + * Description: + * Arguments: + * Returns: + ****************************************************************************** + */ +static int sdla_te_get_fe_status(sdla_fe_t *fe, unsigned char *status) +{ + *status = fe->fe_status; + return 0; +} + +/* + ****************************************************************************** + * ClearTemplate() + * + * Description: + * Arguments: None. + * Returns: None. + ****************************************************************************** + */ +static void ClearTemplate(sdla_fe_t* fe) +{ + int i = 0, j = 0; + unsigned char indirect_addr = 0x00; + + for(i = FIRST_UI; i <= LAST_UI; i++) { + for(j = FIRST_SAMPLE; j <= LAST_SAMPLE; j++) { + indirect_addr = (j << 3) | i; + /* Set up the indirect address */ + WRITE_REG(REG_XLPG_WAVEFORM_ADDR, indirect_addr); + WRITE_REG(REG_XLPG_WAVEFORM_DATA, 0x00); + } + } +} + +/* + ****************************************************************************** + * PrgTransmitTemplate() + * + * Description: + * Arguments: None. + * Returns: None. + ****************************************************************************** + */ +static unsigned char PrgTransmitTemplate(sdla_fe_t* fe) +{ + int i = 0, j = 0; + unsigned char indirect_addr = 0x00, xlpg_scale = 0x00; + TX_WAVEFORM* tx_waveform = NULL; + + if (IS_T1_FEMEDIA(fe)) { + switch(WAN_TE1_LBO(fe)) { + case WAN_T1_LBO_0_DB: + if (fe->fe_chip_id == CHIP_ID_COMET_QUAD){ + tx_waveform = &pmc4_t1_tx_waveform_lh_0db; + /* ALEX Jan 24, 2005 + ** XLPG scale value is change to 0x0D + ** (certification). Original value is 0x0C. */ + xlpg_scale = 0x0D; + }else{ + tx_waveform = &pmc_t1_tx_waveform_lh_0db; + xlpg_scale = 0x0C; + } + break; + case WAN_T1_LBO_75_DB: + if (fe->fe_chip_id == CHIP_ID_COMET_QUAD){ + tx_waveform = &pmc4_t1_tx_waveform_lh_75db; + xlpg_scale = 0x08; + }else{ + tx_waveform = &pmc_t1_tx_waveform_lh_75db; + xlpg_scale = 0x07; + } + break; + case WAN_T1_LBO_15_DB: + if (fe->fe_chip_id == CHIP_ID_COMET_QUAD){ + tx_waveform = &pmc4_t1_tx_waveform_lh_15db; + }else{ + tx_waveform = &pmc4_t1_tx_waveform_lh_15db; + } + xlpg_scale = 0x03; + break; + case WAN_T1_LBO_225_DB: + if (fe->fe_chip_id == CHIP_ID_COMET_QUAD){ + tx_waveform = &pmc4_t1_tx_waveform_lh_225db; + }else{ + tx_waveform = &pmc_t1_tx_waveform_lh_225db; + } + xlpg_scale = 0x02; + break; + case WAN_T1_0_110: + if (fe->fe_chip_id == CHIP_ID_COMET_QUAD){ + tx_waveform = &pmc4_t1_tx_waveform_sh_110ft; + xlpg_scale = 0x0D; + }else{ + tx_waveform = &pmc_t1_tx_waveform_sh_110ft; + xlpg_scale = 0x0C; + } + break; + case WAN_T1_110_220: + if (fe->fe_chip_id == CHIP_ID_COMET_QUAD){ + tx_waveform = &pmc4_t1_tx_waveform_sh_220ft; + xlpg_scale = 0x11; + }else{ + tx_waveform = &pmc_t1_tx_waveform_sh_220ft; + xlpg_scale = 0x10; + } + break; + case WAN_T1_220_330: + if (fe->fe_chip_id == CHIP_ID_COMET_QUAD){ + tx_waveform = &pmc4_t1_tx_waveform_sh_330ft; + xlpg_scale = 0x12; + }else{ + tx_waveform = &pmc_t1_tx_waveform_sh_330ft; + xlpg_scale = 0x11; + } + break; + case WAN_T1_330_440: + if (fe->fe_chip_id == CHIP_ID_COMET_QUAD){ + tx_waveform = &pmc4_t1_tx_waveform_sh_440ft; + xlpg_scale = 0x13; + }else{ + tx_waveform = &pmc_t1_tx_waveform_sh_440ft; + xlpg_scale = 0x12; + } + break; + case WAN_T1_440_550: + if (fe->fe_chip_id == CHIP_ID_COMET_QUAD){ + tx_waveform = &pmc4_t1_tx_waveform_sh_550ft; + xlpg_scale = 0x15; + }else{ + tx_waveform = &pmc_t1_tx_waveform_sh_550ft; + xlpg_scale = 0x14; + } + break; + case WAN_T1_550_660: + if (fe->fe_chip_id == CHIP_ID_COMET_QUAD){ + tx_waveform = &pmc4_t1_tx_waveform_sh_660ft; + }else{ + tx_waveform = &pmc_t1_tx_waveform_sh_660ft; + } + xlpg_scale = 0x15; + break; + default: + /* Use 0DB as a default value */ + if (fe->fe_chip_id == CHIP_ID_COMET_QUAD){ + tx_waveform = &pmc4_t1_tx_waveform_lh_0db; + xlpg_scale = 0x0D; + }else{ + tx_waveform = &pmc_t1_tx_waveform_lh_0db; + xlpg_scale = 0x0C; + } + break; + } + } else { + if (fe->fe_chip_id == CHIP_ID_COMET_QUAD){ + tx_waveform = &pmc4_e1_tx_waveform_120; + }else{ + tx_waveform = &pmc_e1_tx_waveform_120; + } + xlpg_scale = 0x0C; + /*xlpg_scale = 0x0B; */ + } + +#if 0 +/* By default, HIGHZ bit is set to 0 */ + if (fe->fe_chip_id == CHIP_ID_COMET_QUAD){ + if (IS_FE_TXTRISTATE(fe)){ + WRITE_REG(REG_XLPG_LINE_CFG, BIT_XLPG_LINE_CFG_HIGHZ); + }else{ + WRITE_REG(REG_XLPG_LINE_CFG, + xlpg_scale | BIT_XLPG_LINE_CFG_HIGHZ); + } + } +#endif + for(i = FIRST_UI; i <= LAST_UI; i++){ + for(j = FIRST_SAMPLE; j <= LAST_SAMPLE; j++){ + indirect_addr = (j << 3) | i; + /* Set up the indirect address */ + WRITE_REG(REG_XLPG_WAVEFORM_ADDR, indirect_addr); + WRITE_REG(REG_XLPG_WAVEFORM_DATA, (*tx_waveform)[j][i]); + } + } + return xlpg_scale; +} + +/* + ****************************************************************************** + * FuseStabilizationProc() + * + * Description: Fuse stabilization procedure. + * Arguments: + * Returns: None. + ****************************************************************************** + */ +static void FuseStabilizationProc(sdla_fe_t* fe) +{ + unsigned char value; + + /* XLPG Analog Test Negative Control (0xF4) */ + if (fe->fe_chip_id == CHIP_ID_COMET_QUAD){ + WRITE_REG(REG_XLPG_INIT, 0x00); + } + WRITE_REG(REG_XLPG_TNC, 0x01); + WRITE_REG(REG_XLPG_TNC, 0x01); + value = READ_REG(REG_XLPG_TNC) & 0xFE; + WRITE_REG(REG_XLPG_TNC, value); + + /* XLPG Analog Test Positive Control (0xF5) */ + if (fe->fe_chip_id == CHIP_ID_COMET_QUAD){ + WRITE_REG(REG_XLPG_INIT, 0x00); + } + WRITE_REG(REG_XLPG_TPC, 0x01); + WRITE_REG(REG_XLPG_TPC, 0x01); + value = READ_REG(REG_XLPG_TPC) & 0xFE; + WRITE_REG(REG_XLPG_TPC, value); + + WRITE_REG(REG_XLPG_INIT, 0x01); +} + +/* + ****************************************************************************** + * InitLineReceiver() + * + * Description: + * Arguments: is_e1 - WAN_TRUE for E1 connection, WAN_FALSE for T1 connection. + * Returns: None. + ****************************************************************************** + */ +static void InitLineReceiver(sdla_fe_t* fe, RLPS_EQUALIZER_RAM* rlps_table) +{ + int ram_addr = 0x00; + + if (IS_T1_FEMEDIA(fe)){ + if (WAN_TE1_HI_MODE(fe) == WANOPT_YES){ + DEBUG_EVENT("%s: Configure for High-Impedance Mode!\n", + fe->name); + rlps_table = pmc_t1_rlps_perf_mode_ram_table; + } + } + for(ram_addr = 0; ram_addr <= 255; ram_addr++) { +/* ERRATA VVV */ + /* RLPS Equalizaton Read/WriteB Select (Reg. 0xQFD) + * Perform dummy read */ + WRITE_REG(REG_RLPS_EQ_RWB, BIT_RLPS_EQ_RWB); + /* RLPS Eqialization Indirect Address (Reg. 0xQFC) */ + WRITE_REG(REG_RLPS_EQ_ADDR, (unsigned char)ram_addr); + WP_DELAY(100); +/* ERRATA ^^^ */ + /* RLPS Equalization Indirect Data MSB (Reg. 0xQD8) */ + WRITE_REG(REG_RLPS_IND_DATA_1, rlps_table[ram_addr].byte1); + /* RLPS Equalization Indirect Data (Reg. 0xQD9) */ + WRITE_REG(REG_RLPS_IND_DATA_2, rlps_table[ram_addr].byte2); + /* RLPS Equalization Indirect Data (Reg. 0xQDA) */ + WRITE_REG(REG_RLPS_IND_DATA_3, rlps_table[ram_addr].byte3); + /* RLPS Equalization Indirect Data LSB (Reg. 0xQDB) */ + WRITE_REG(REG_RLPS_IND_DATA_4, rlps_table[ram_addr].byte4); + /* RLPS Equalizaton Read/WriteB Select (Reg. 0xQFD) */ + WRITE_REG(REG_RLPS_EQ_RWB, 0x00); + /* RLPS Eqialization Indirect Address (Reg. 0xQFC) */ + WRITE_REG(REG_RLPS_EQ_ADDR, (unsigned char)ram_addr); +/* ERRATA VVV */ + WP_DELAY(100); +/* ERRATA ^^^ */ + } +} + +/* + ****************************************************************************** + * ClearTPSCReg() + * + * Description: Clear all TPSC indirect register. + * Arguments: None. + * Returns: None + ****************************************************************************** + */ +static void ClearTPSCReg(sdla_fe_t* fe) +{ + int channel = 0; + int start_channel = 0, stop_channel = 0; + + if (IS_E1_FEMEDIA(fe)){ + start_channel = 0; + stop_channel = NUM_OF_E1_TIMESLOTS + 1; + }else{ + start_channel = 1; + stop_channel = NUM_OF_T1_CHANNELS; + } + + for(channel = start_channel; channel <= stop_channel; channel++){ + WRITE_TPSC_REG(REG_TPSC_DATA_CTRL_BYTE, channel, 0x00); + WRITE_TPSC_REG(REG_TPSC_IDLE_CODE_BYTE, channel, 0x00); + + if (IS_T1_FEMEDIA(fe)){ + if (fe->fe_cfg.cfg.te_cfg.te_rbs_ch & (1 << (channel -1))){ + WRITE_TPSC_REG(REG_TPSC_SIGNALING_BYTE, channel, + BIT_TPSC_SIGBYTE_B| + BIT_TPSC_SIGBYTE_D| + BIT_TPSC_SIGBYTE_SIGC_0 | + BIT_TPSC_SIGBYTE_SIGC_1); + + }else{ + WRITE_TPSC_REG(REG_TPSC_SIGNALING_BYTE, channel, 0x00); + } + }else{ + WRITE_TPSC_REG(REG_TPSC_E1_CTRL_BYTE, channel, 0x00); + } + + /* Do not initialize Signalling Bits + ** WRITE_TPSC_REG(REG_TPSC_SIGNALING_BYTE, channel, 0x00); */ + } + return; +} + +/* + ****************************************************************************** + * ClearRPSCReg() + * + * Description: Clear all RPSC indirect register. + * Arguments: None. + * Returns: None + ****************************************************************************** + */ +static void ClearRPSCReg(sdla_fe_t* fe) +{ + int channel = 0; + int start_channel = 0, stop_channel = 0; + + if (IS_E1_FEMEDIA(fe)){ + start_channel = 0; + stop_channel = NUM_OF_E1_TIMESLOTS + 1; + }else{ + start_channel = 1; + stop_channel = NUM_OF_T1_CHANNELS; + } + + for(channel = start_channel; channel <= stop_channel; channel++){ + WRITE_RPSC_REG(REG_RPSC_DATA_CTRL_BYTE, channel, 0x00); + WRITE_RPSC_REG(REG_RPSC_DATA_COND_BYTE, channel, 0x00); + WRITE_RPSC_REG(REG_RPSC_SIGBYTE, channel, 0x00); + } + return; +} + +/* + ****************************************************************************** + * WriteTPSCReg() + * + * Description: Write value to TPSC indirect register. + * Arguments: reg - Offset in TPSC indirect space. + * value - New PMC register value. + * Returns: None + ****************************************************************************** + */ +static int +WriteTPSCReg(sdla_fe_t* fe, int reg, int channel, unsigned char value) +{ + unsigned char temp = 0x00; + int i = 0, busy_flag = 0; + int err = WAN_FALSE; + + reg += channel; + /* Set IND bit to 1 in TPSC to enable indirect access to TPSC register */ + WRITE_REG(REG_TPSC_CFG, BIT_TPSC_IND); + busy_flag = 1; + for(i = 0; i < MAX_BUSY_READ; i++) { + temp = READ_REG(REG_TPSC_MICRO_ACCESS_STATUS); + if ((temp & BIT_TPSC_BUSY) == 0x0){ + busy_flag = 0; + break; + } + } + if (busy_flag == 1){ + DEBUG_EVENT("%s: Failed to write value to TPSC Reg=%02x, val=%02x!\n", + fe->name, reg, value); + goto write_tpsc_done; + } + + WRITE_REG(REG_TPSC_CHANNEL_INDIRECT_DATA_BUFFER, (unsigned char)value); + WRITE_REG(REG_TPSC_CHANNEL_INDIRECT_ADDRESS_CONTROL, (unsigned char)(reg & 0x7F)); + + for(i = 0; i < MAX_BUSY_READ; i++) { + temp = READ_REG(REG_TPSC_MICRO_ACCESS_STATUS); + if ((temp & BIT_TPSC_BUSY) == 0x0){ + err = WAN_TRUE; + goto write_tpsc_done; + } + } + DEBUG_EVENT("%s: Failed to write value to TPSC Reg=%02x, val=%02x.\n", + fe->name, reg, value); +write_tpsc_done: + /* Set PCCE bit to 1 in TPSC to enable modifing the TPSC register */ + WRITE_REG(REG_TPSC_CFG, BIT_TPSC_IND | BIT_TPSC_PCCE); + return err; +} + +/* + ****************************************************************************** + * ReadTPSCReg() + * + * Description: Read value from TPSC indirect register. + * Arguments: reg - Offset in TPSC indirect space. + * Returns: Returns register value. + ****************************************************************************** + */ +static unsigned char ReadTPSCReg(sdla_fe_t* fe, int reg, int channel) +{ + unsigned char tmp = 0x00, value = 0x00; + int i = 0, busy_flag = 0; + + reg += channel; + /* Set IND bit to 1 in TPSC to enable indirect access to TPSC register */ + WRITE_REG(REG_TPSC_CFG, BIT_TPSC_IND); + busy_flag = 1; + for(i = 0; i < MAX_BUSY_READ; i++) { + tmp = READ_REG(REG_TPSC_MICRO_ACCESS_STATUS); + if ((tmp & BIT_TPSC_BUSY) == 0x0){ + busy_flag = 0; + break; + } + } + if (busy_flag == 1){ + DEBUG_EVENT("%s: Failed to read value to TPSC Reg=%02x!\n", + fe->name, reg); + goto read_tpsc_done; + } + + WRITE_REG(REG_TPSC_CHANNEL_INDIRECT_ADDRESS_CONTROL, + (unsigned char)(reg | 0x80)); + + for(i = 0; i < MAX_BUSY_READ; i++) { + tmp = READ_REG(REG_TPSC_MICRO_ACCESS_STATUS); + if ((tmp & BIT_TPSC_BUSY) == 0x0){ + value = READ_REG(REG_TPSC_CHANNEL_INDIRECT_DATA_BUFFER); + goto read_tpsc_done; + } + } + DEBUG_EVENT("%s: Failed to read value to TPSC Reg=%02x.\n", + fe->name, reg); +read_tpsc_done: + /* Set PCCE bit to 1 in TPSC to enable modifing the TPSC register */ + WRITE_REG(REG_TPSC_CFG, BIT_TPSC_IND | BIT_TPSC_PCCE); + return value; +} + +/* + ****************************************************************************** + * WriteRPSCReg() + * + * Description: Write value to RPSC indirect register. + * Arguments: reg - Offset in RPSC indirect space. + * value - New PMC register value. + * Returns: None + ****************************************************************************** + */ +static int +WriteRPSCReg(sdla_fe_t* fe, int reg, int channel, unsigned char value) +{ + unsigned char temp = 0x00; + int i = 0, busy_flag = 0; + int err = WAN_FALSE; + + reg += channel; + /* Set IND bit to 1 in RPSC to enable indirect access to RPSC register*/ + WRITE_REG(REG_RPSC_CFG, BIT_RPSC_IND); + busy_flag = 1; + for(i = 0; i < MAX_BUSY_READ; i++) { + temp = READ_REG(REG_RPSC_MICRO_ACCESS_STATUS); + if ((temp & BIT_RPSC_BUSY) == 0x0){ + busy_flag = 0; + break; + } + } + if (busy_flag == 1){ + DEBUG_EVENT("%s: Failed to write value to RPSC Reg=%02x, val=%02x!\n", + fe->name, reg, value); + goto write_rpsc_done; + } + + WRITE_REG(REG_RPSC_CHANNEL_INDIRECT_DATA_BUFFER, (unsigned char)value); + WRITE_REG(REG_RPSC_CHANNEL_INDIRECT_ADDRESS_CONTROL, (unsigned char)(reg & 0x7F)); + + for(i = 0; i < MAX_BUSY_READ; i++) { + temp = READ_REG(REG_RPSC_MICRO_ACCESS_STATUS); + if ((temp & BIT_RPSC_BUSY) == 0x0){ + err = WAN_TRUE; + goto write_rpsc_done; + } + } + DEBUG_EVENT("%s: Failed to write value to RPSC Reg=%02x, val=%02x.\n", + fe->name, reg, value); +write_rpsc_done: + /* Set PCCE bit to 1 in RPSC to enable modifing the RPSC register */ + WRITE_REG(REG_RPSC_CFG, BIT_RPSC_IND | BIT_RPSC_PCCE); + return err; +} + +/* + ****************************************************************************** + * ReadRPSCReg() + * + * Description: Read value from RPSC indirect register. + * Arguments: reg - Offset in RPSC indirect space. + * Returns: Returns register value. + ****************************************************************************** + */ +static unsigned char ReadRPSCReg(sdla_fe_t* fe, int reg, int channel) +{ + unsigned char tmp = 0x00, value = 0x00; + int i = 0, busy_flag = 0; + + reg += channel; + /* Set IND bit to 1 in RPSC to enable indirect access to RPSC register*/ + WRITE_REG(REG_RPSC_CFG, BIT_RPSC_IND); + busy_flag = 1; + for(i = 0; i < MAX_BUSY_READ; i++) { + tmp = READ_REG(REG_RPSC_MICRO_ACCESS_STATUS); + if ((tmp & BIT_RPSC_BUSY) == 0x0){ + busy_flag = 0; + break; + } + } + if (busy_flag == 1){ + DEBUG_EVENT("%s: Failed to read value to RPSC Reg=%02x!\n", + fe->name, reg); + goto read_rpsc_done; + } + + WRITE_REG(REG_RPSC_CHANNEL_INDIRECT_ADDRESS_CONTROL, + (unsigned char)(reg | 0x80)); + + for(i = 0; i < MAX_BUSY_READ; i++) { + tmp = READ_REG(REG_RPSC_MICRO_ACCESS_STATUS); + if ((tmp & BIT_RPSC_BUSY) == 0x0){ + value = READ_REG(REG_RPSC_CHANNEL_INDIRECT_DATA_BUFFER); + goto read_rpsc_done; + } + } + DEBUG_EVENT("%s: Failed to read value to RPSC Reg=%02x.\n", + fe->name, reg); +read_rpsc_done: + /* Set PCCE bit to 1 in RPSC to enable modifing the RPSC register */ + WRITE_REG(REG_RPSC_CFG, BIT_RPSC_IND | BIT_RPSC_PCCE); + return value; +} + +/* + ****************************************************************************** + * WriteSIGXReg() + * + * Description: Write value from SIGX indirect register. + * Arguments: reg - Offset in SIGX indirect space. + * value - New PMC register value. + * Returns: Returns register value. + ****************************************************************************** + */ +#if 0 +static int WriteSIGXReg(sdla_fe_t* fe, int reg, int channel, unsigned char value) +{ + unsigned char temp = 0x00; + int i = 0, busy_flag = 0; + int err = WAN_FALSE; + + reg += (IS_T1_FEMEDIA(fe) ? (channel - 1) : channel); + temp = READ_REG(REG_SIGX_CFG); + WRITE_REG(REG_SIGX_CFG, (temp | BIT_SIGX_IND) & ~(BIT_SIGX_PCCE|BIT_SIGX_COSS)); + + busy_flag = 1; + for(i = 0; i < MAX_BUSY_READ; i++) { + temp = READ_REG(REG_SIGX_TIMESLOT_IND_STATUS); + if ((temp & BIT_SIGX_BUSY) == 0x0){ + busy_flag = 0; + break; + } + } + if (busy_flag == 1){ + DEBUG_EVENT("%s: Failed to write value to RPSC Reg=%02x, val=%02x!\n", + fe->name, reg, value); + goto write_sigx_done; + } + + WRITE_REG(REG_SIGX_TIMESLOT_IND_DATA_BUFFER, (unsigned char)value); + WRITE_REG(REG_SIGX_TIMESLOT_IND_ACCESS, (unsigned char)(reg & 0x7F)); + + for(i = 0; i < MAX_BUSY_READ; i++) { + temp = READ_REG(REG_SIGX_TIMESLOT_IND_STATUS); + if ((temp & BIT_SIGX_BUSY) == 0x0){ + err = WAN_TRUE; + goto write_sigx_done; + } + } + DEBUG_EVENT("%s: Failed to write value to RPSC Reg=%02x, val=%02x.\n", + fe->name, reg, value); +write_sigx_done: + /* Set PCCE bit to 1 in SIGX to enable modifing the SIGX register */ + temp = READ_REG(REG_SIGX_CFG); + WRITE_REG(REG_SIGX_CFG, temp | BIT_SIGX_PCCE); + return err; +} +#endif + +/* + ****************************************************************************** + * ReadSIGXReg() + * + * Description: Read value from SIGX indirect register. + * Arguments: reg - Offset in SIGX indirect space. + * Returns: Returns register value. + ****************************************************************************** + */ +static unsigned char ReadSIGXReg(sdla_fe_t* fe, int reg, int channel) +{ + unsigned char sigx_cfg = 0x00, tmp = 0x00, value = 0x00; + int offset, i = 0, busy_flag = 0; + + if (IS_E1_FEMEDIA(fe)){ + if (channel == 0 || channel == 16){ + return 0; + } + offset = (channel > 16) ? channel - 16 : channel; + }else{ + offset = (channel > 16) ? channel - 17 : channel - 1; + } + reg += offset; + + /* Enable indirect access to SIGX registers */ + sigx_cfg = READ_REG(REG_SIGX_CFG); + WRITE_REG(REG_SIGX_CFG, READ_REG(REG_SIGX_CFG) & ~BIT_SIGX_COSS); + + /* Set IND bit to 1 in SIGX Configuration Register to enable + * indirect access to SIGX register*/ + WRITE_REG(REG_SIGX_CFG, READ_REG(REG_SIGX_CFG) | BIT_SIGX_IND); + + busy_flag = 1; + for(i = 0; i < MAX_BUSY_READ; i++) { + tmp = READ_REG(REG_SIGX_TIMESLOT_IND_STATUS); + if ((tmp & BIT_SIGX_BUSY) == 0x0){ + busy_flag = 0; + break; + } + } + if (busy_flag == 1){ + DEBUG_EVENT("%s: Failed to read value from SIGX Reg=%02x!\n", + fe->name, reg); + goto read_sigx_done; + } + + WRITE_REG(REG_SIGX_TIMESLOT_IND_ACCESS, + (unsigned char)(reg | BIT_SIGX_TS_IND_ACCESS_READ)); + + for(i = 0; i < MAX_BUSY_READ; i++) { + tmp = READ_REG(REG_SIGX_TIMESLOT_IND_STATUS); + if ((tmp & BIT_SIGX_BUSY) == 0x0){ + value = READ_REG(REG_SIGX_TIMESLOT_IND_DATA_BUFFER); + goto read_sigx_done; + } + } + DEBUG_EVENT("%s: Failed to read value from SIGX Reg=%02x.\n", + fe->name, reg); +read_sigx_done: +#if 0 + tmp = READ_REG(REG_SIGX_CFG); + WRITE_REG(REG_SIGX_CFG, (tmp | BIT_SIGX_PCCE)); +#endif +#if 0 + tmp = READ_REG(REG_SIGX_CFG); + WRITE_REG(REG_SIGX_CFG, tmp & ~BIT_SIGX_IND); + tmp = READ_REG(REG_SIGX_CFG); + /* Disable indirect access to SIGX registers */ + WRITE_REG(REG_SIGX_CFG, tmp | BIT_SIGX_COSS); +#endif + WRITE_REG(REG_SIGX_CFG, sigx_cfg); + return value; +} + + +/* + ****************************************************************************** + * DisableAllChannels() + * + * Description: + * Arguments: + * Returns: + ****************************************************************************** + */ +static void DisableAllChannels(sdla_fe_t* fe) +{ + int i = 0; + + if (IS_E1_FEMEDIA(fe)) { + DisableTxChannel(fe, E1_FRAMING_TIMESLOT); + DisableRxChannel(fe, E1_FRAMING_TIMESLOT); + for(i = 1; i <= NUM_OF_E1_TIMESLOTS; i++){ + DisableTxChannel(fe, i); + DisableRxChannel(fe, i); + } + }else{ + for(i = 1; i <= NUM_OF_T1_CHANNELS; i++){ + DisableTxChannel(fe, i); + DisableRxChannel(fe, i); + } + } +} + +/* + ****************************************************************************** + * EnableAllChannels() + * + * Description: + * Arguments: + * Returns: + ****************************************************************************** + */ +static void EnableAllChannels(sdla_fe_t* fe) +{ + int i = 0; + + if (IS_E1_FEMEDIA(fe)) { + int first_ts = + (WAN_FE_FRAME(fe) == WAN_FR_UNFRAMED) ? 0 : 1; + + DisableTxChannel(fe, E1_FRAMING_TIMESLOT); + DisableRxChannel(fe, E1_FRAMING_TIMESLOT); + for(i = first_ts; i <= NUM_OF_E1_TIMESLOTS; i++){ + EnableTxChannel(fe, i); + EnableRxChannel(fe, i); + } + }else{ + for(i = 1; i <= NUM_OF_T1_CHANNELS; i++){ + EnableTxChannel(fe, i); + EnableRxChannel(fe, i); + } + } +} + +/* + ****************************************************************************** + * EnableTxChannel() + * + * Description: + * Arguments: + * Returns: + ****************************************************************************** + */ +static int EnableTxChannel(sdla_fe_t* fe, int channel) +{ + + if (WAN_FE_LCODE(fe) == WAN_LCODE_AMI){ + /* ZCs=1 AMI*/ + WRITE_TPSC_REG(REG_TPSC_DATA_CTRL_BYTE, channel, + (((READ_TPSC_REG(REG_TPSC_DATA_CTRL_BYTE, channel) & MASK_TPSC_DATA_CTRL_BYTE) & + ~BIT_TPSC_DATA_CTRL_BYTE_IDLE_DS0) | BIT_TPSC_DATA_CTRL_BYTE_ZCS1)); + }else{ + WRITE_TPSC_REG(REG_TPSC_DATA_CTRL_BYTE, channel, + ((READ_TPSC_REG(REG_TPSC_DATA_CTRL_BYTE, channel) & MASK_TPSC_DATA_CTRL_BYTE) & + ~(BIT_TPSC_DATA_CTRL_BYTE_IDLE_DS0 | BIT_TPSC_DATA_CTRL_BYTE_ZCS1 | BIT_TPSC_DATA_CTRL_BYTE_ZCS0))); + } + + if (IS_E1_FEMEDIA(fe)){ + /* Set SUBS=DS[0]=DS[1]=0x0 - no change to PCM timeslot data */ + WRITE_TPSC_REG(REG_TPSC_E1_CTRL_BYTE, channel, + (READ_TPSC_REG(REG_TPSC_E1_CTRL_BYTE, channel) & + ~(BIT_TPSC_E1_CTRL_BYTE_SUBS | BIT_TPSC_E1_CTRL_BYTE_DS0 | BIT_TPSC_E1_CTRL_BYTE_DS1))); + }else{ + if (fe->fe_cfg.cfg.te_cfg.te_rbs_ch & (1 << (channel -1))){ + WRITE_TPSC_REG(REG_TPSC_SIGNALING_BYTE, channel, + BIT_TPSC_SIGBYTE_B| + BIT_TPSC_SIGBYTE_D| + BIT_TPSC_SIGBYTE_SIGC_0 | + BIT_TPSC_SIGBYTE_SIGC_1); + }else{ + WRITE_TPSC_REG(REG_TPSC_SIGNALING_BYTE, channel, 0x00); + } + /* Do not initialize Signalling Bits + ** WRITE_TPSC_REG(REG_TPSC_SIGNALING_BYTE, channel, 0x00); */ + } + + /* Erase contents of IDLE code byte */ + WRITE_TPSC_REG(REG_TPSC_IDLE_CODE_BYTE, channel, 0x00); + + return 0; +} +/* + ****************************************************************************** + * EnableRxChannel() + * + * Description: + * Arguments: + * Returns: + ****************************************************************************** + */ +static int EnableRxChannel(sdla_fe_t* fe, int channel) +{ + + /* Set DTRPC bit to 0 in RPSC */ + WRITE_RPSC_REG(REG_RPSC_DATA_CTRL_BYTE, channel, + ((READ_RPSC_REG(REG_RPSC_DATA_CTRL_BYTE, channel) & MASK_RPSC_DATA_CTRL_BYTE) & + ~BIT_RPSC_DATA_CTRL_BYTE_DTRKC)); + + return 0; +} + +/* + ****************************************************************************** + * DisableTxChannel() + * + * Description: + * Arguments: + * Returns: + ****************************************************************************** + */ +static int DisableTxChannel(sdla_fe_t* fe, int channel) +{ + + /* Set IDLE_DS0 to 1 for an IDLE code byte will insert and + * BTCLK will suppressed + */ + WRITE_TPSC_REG(REG_RPSC_DATA_CTRL_BYTE, channel, + ((READ_TPSC_REG(REG_TPSC_DATA_CTRL_BYTE, channel) & MASK_TPSC_DATA_CTRL_BYTE) | + BIT_TPSC_DATA_CTRL_BYTE_IDLE_DS0)); + if (IS_E1_FEMEDIA(fe)){ + /* Set SUBS=1, DS0=0 - data substitution on - IDLE code replaces BTPCM timeslot data */ + WRITE_TPSC_REG(REG_TPSC_E1_CTRL_BYTE, channel, + ((READ_TPSC_REG(REG_TPSC_E1_CTRL_BYTE, channel) & ~BIT_TPSC_E1_CTRL_BYTE_DS0) | + BIT_TPSC_E1_CTRL_BYTE_SUBS)); + }else{ + if (fe->fe_cfg.cfg.te_cfg.te_rbs_ch & (1 << (channel -1))){ + WRITE_TPSC_REG(REG_TPSC_SIGNALING_BYTE, channel, + BIT_TPSC_SIGBYTE_B| + BIT_TPSC_SIGBYTE_D| + BIT_TPSC_SIGBYTE_SIGC_0 | + BIT_TPSC_SIGBYTE_SIGC_1); + }else{ + WRITE_TPSC_REG(REG_TPSC_SIGNALING_BYTE, channel, 0x00); + } + /* Do not initialize Signalling Bits + ** WRITE_TPSC_REG(REG_TPSC_SIGNALING_BYTE, channel, 0x00); */ + } + /* Erase contents of IDLE code byte */ + WRITE_TPSC_REG(REG_TPSC_IDLE_CODE_BYTE, channel, 0x55); + return 0; +} + +/* + ****************************************************************************** + * DisableRxChannel() + * + * Description: + * Arguments: + * Returns: + ****************************************************************************** + */ +static int DisableRxChannel(sdla_fe_t* fe, int channel) +{ + /* Set DTRPC bit to 1 in RPSC to hold low for the duration of the channel */ + WRITE_RPSC_REG(REG_RPSC_DATA_CTRL_BYTE, channel, + ((READ_RPSC_REG(REG_RPSC_DATA_CTRL_BYTE, channel) & MASK_RPSC_DATA_CTRL_BYTE) | + BIT_RPSC_DATA_CTRL_BYTE_DTRKC)); + + return 0; +} + +/* + ****************************************************************************** + * sdla_te_copycfg() + * + * Description: Copy T1/E1 configuration to card structure. + * Arguments: + * Returns: + ****************************************************************************** + */ +int sdla_te_default_cfg(void* pfe, void* pfe_cfg, int media) +{ + sdla_fe_cfg_t *fe_cfg = (sdla_fe_cfg_t*)pfe_cfg; + + /* Fill with the default values */ + switch(media){ + case WAN_MEDIA_E1: + fe_cfg->media = WAN_MEDIA_E1; + fe_cfg->lcode = WAN_LCODE_HDB3; + fe_cfg->frame = WAN_FR_NCRC4; + fe_cfg->cfg.te_cfg.lbo = WAN_E1_120; + fe_cfg->cfg.te_cfg.te_clock = WAN_NORMAL_CLK; + fe_cfg->cfg.te_cfg.active_ch = ENABLE_ALL_CHANNELS; + break; + case WAN_MEDIA_T1: + fe_cfg->media = WAN_MEDIA_T1; + fe_cfg->lcode = WAN_LCODE_B8ZS; + fe_cfg->frame = WAN_FR_ESF; + fe_cfg->cfg.te_cfg.lbo = WAN_T1_LBO_0_DB; + fe_cfg->cfg.te_cfg.te_clock = WAN_NORMAL_CLK; + fe_cfg->cfg.te_cfg.active_ch = ENABLE_ALL_CHANNELS; + fe_cfg->cfg.te_cfg.high_impedance_mode = WANOPT_NO; + break; + default: + return -EINVAL; + } + + return 0; +} + +/* + ****************************************************************************** + * sdla_te_iface_init() + * + * Description: Inialize Front-End interface functions. + * Arguments: + * Returns: + ****************************************************************************** + */ +int sdla_te_iface_init(void *pfe_iface) +{ + sdla_fe_iface_t *fe_iface = (sdla_fe_iface_t*)pfe_iface; + + fe_iface->global_config = &sdla_te_global_config; + fe_iface->global_unconfig = &sdla_te_global_unconfig; + fe_iface->config = &sdla_te_config; + fe_iface->unconfig = &sdla_te_unconfig; + fe_iface->isr = &sdla_te_intr; + fe_iface->check_isr = &sdla_te_check_intr; + fe_iface->polling = &sdla_te_polling; + fe_iface->process_udp = &sdla_te_udp; + fe_iface->print_fe_alarm = &sdla_te_print_alarms; + fe_iface->print_fe_act_channels = &sdla_te_print_channels; + fe_iface->set_fe_alarm = &sdla_te_set_alarms; + fe_iface->set_fe_sigctrl = &sdla_te_sigctrl; + fe_iface->read_alarm = &sdla_te_read_alarms; + fe_iface->read_pmon = &sdla_te_pmon; + fe_iface->flush_pmon = &sdla_te_flush_pmon; + fe_iface->get_fe_status = &sdla_te_get_fe_status; + fe_iface->get_fe_media = &sdla_te_get_fe_media; + fe_iface->set_fe_lbmode = &sdla_te_set_lbmode; + fe_iface->get_fe_media_string = &sdla_te_get_fe_media_string; + fe_iface->update_alarm_info = &sdla_te_update_alarm_info; + fe_iface->update_pmon_info = &sdla_te_update_pmon_info; + fe_iface->led_ctrl = &sdla_te_led_ctrl; + fe_iface->check_rbsbits = &sdla_te_check_rbsbits; + fe_iface->read_rbsbits = &sdla_te_read_rbsbits; + fe_iface->set_rbsbits = &sdla_te_set_rbsbits; + fe_iface->report_rbsbits = &sdla_te_rbs_report; +#if !defined(CONFIG_PRODUCT_WANPIPE_GENERIC) + fe_iface->get_snmp_data = &sdla_te_get_snmp_data; +#endif + fe_iface->post_config = &sdla_te_post_config; + +#if defined(__WINDOWS__) + /* (Windows only) Can't execute poll timer from interrupt level */ + fe_iface->enable_timer = &sdla_te_enable_timer; +#endif + + return 0; +} + +/* + ****************************************************************************** + * sdla_te_copycfg() + * + * Description: Copy T1/E1 configuration to card structure. + * Arguments: + * Returns: + ****************************************************************************** + */ +int sdla_te_copycfg(void* pfe, void* pfe_cfg) +{ + sdla_fe_t *fe = (sdla_fe_t*)pfe; + sdla_fe_cfg_t *fe_cfg = (sdla_fe_cfg_t*)pfe_cfg; + + if (fe_cfg){ + memcpy(&fe->fe_cfg, fe_cfg, sizeof(sdla_fe_cfg_t)); + }else{ + /* Fill with the default values */ + sdla_te_default_cfg(fe, &fe->fe_cfg, WAN_MEDIA_T1); + } + return 0; +} + + +/* + ****************************************************************************** + * sdla_te_global_config() + * + * Description: Global configuration for Sangoma TE1 PMC board. + * Note: These register should be program only once for AFT-QUAD + * cards. + * Arguments: + * Returns: WANTRUE - TE1 configred successfully, otherwise WAN_FALSE. + ****************************************************************************** + */ +static int sdla_te_global_config(void* pfe) +{ + sdla_fe_t *fe = (sdla_fe_t*)pfe; + unsigned char value = 0x00; + + DEBUG_TE1("%s: %s Global Front End configuration\n", + fe->name, FE_MEDIA_DECODE(fe)); + /* 1. Initiate software reset of the COMET */ + /* Set RESET=1 to place COMET into RESET (Reg. 0xE) */ + WRITE_REG_LINE(0, REG_RESET, BIT_RESET); + /* Set RESET=0, disable software reset. (Reg. 0xE) + * COMET in default mode. */ + WRITE_REG_LINE(0, REG_RESET, 0x0/*~BIT_RESET*/); + + /* Program PMC for T1/E1 mode (Reg 0x00) */ + if (IS_E1_FEMEDIA(fe)){ + value = BIT_GLOBAL_PIO_OE | BIT_GLOBAL_E1; + }else{ + value = BIT_GLOBAL_PIO_OE; + } + WRITE_REG_LINE(0, REG_GLOBAL_CFG, value); + + /* Set system clock and XCLK (Reg 0xD6) */ + if (IS_T1_FEMEDIA(fe)){ + WRITE_REG_LINE(0, REG_CSU_CFG, BIT_CSU_MODE0); + /* WRITE_REG(REG_CSU_CFG, + * BIT_CSU_MODE2 | + * BIT_CSU_MODE1 | + * BIT_CSU_MODE0); */ + }else{ + WRITE_REG_LINE(0, REG_CSU_CFG, 0x00); + } + + /* 10 Jan 2004 + ** This delay let PMC make proper RESET. */ + WP_DELAY(1000); + + return 0; +} + +/* + ****************************************************************************** + * sdla_pmc4351_te_config() + * + * Description: Configure Sangoma S5147/S5148/A101/A102 TE1 board + * Arguments: + * Returns: WANTRUE - TE1 configred successfully, otherwise WAN_FALSE. + ****************************************************************************** + */ +static int sdla_pmc4351_te_config(sdla_fe_t *fe, u16 adapter_type) +{ + unsigned char value = 0x00; + + /* Execute global chip configuration */ + sdla_te_global_config(fe); + + /* 2.Setup the XLPG(Transmit pulse template) to clear the pulse + ** template */ + ClearTemplate(fe); + fe->te_param.xlpg_scale = PrgTransmitTemplate(fe); + + /* Global Configuration (Reg 0x00) */ + value = READ_REG(REG_GLOBAL_CFG); + if (IS_E1_FEMEDIA(fe)){ + if (adapter_type & A101_ADPTR_TE1_MASK){ + value |= BIT_GLOBAL_TRKEN; + } + }else{ + if (adapter_type & A101_ADPTR_TE1_MASK){ + value |= BIT_GLOBAL_TRKEN; + } + } + WRITE_REG(REG_GLOBAL_CFG, value); + + /* XLPG Line Driver Configuration (Reg. 0xF0) */ + if (IS_FE_TXTRISTATE(fe)){ + DEBUG_EVENT("%s: Disable Transmitter (tx tri-state mode)!\n", + fe->name); + WRITE_REG(REG_XLPG_LINE_CFG, BIT_XLPG_LINE_CFG_HIGHZ); + }else{ + WRITE_REG(REG_XLPG_LINE_CFG, fe->te_param.xlpg_scale); + } + + /* CDRC Configuration (Reg. 0x10) */ + if (WAN_FE_LCODE(fe) == WAN_LCODE_AMI){ + WRITE_REG(REG_CDRC_CFG, BIT_CDRC_CFG_AMI); + }else{ + WRITE_REG(REG_CDRC_CFG, 0x00); + } + + if (IS_E1_FEMEDIA(fe)) { + /* RX-ELST Configuration (Reg. 0x1C) */ + WRITE_REG(REG_RX_ELST_CFG, BIT_RX_ELST_IR | BIT_RX_ELST_OR); + /* TX-ELST Configuration (Reg. 0x20) */ + WRITE_REG(REG_TX_ELST_CFG, BIT_TX_ELST_IR | BIT_RX_ELST_OR); + }else{ + /* RX-ELST Configuration (Reg. 0x1C) */ + WRITE_REG(REG_RX_ELST_CFG, 0x00); + /* TX-ELST Configuration (Reg. 0x20) */ + WRITE_REG(REG_TX_ELST_CFG, 0x00); + } + + if (IS_E1_FEMEDIA(fe)){ + /* E1-TRAN Configuration (Reg. 0x80) */ + value = 0x00; + if (WAN_FE_LCODE(fe) == WAN_LCODE_AMI){ + value |= BIT_E1_TRAN_AMI; + } + if (WAN_FE_FRAME(fe) == WAN_FR_CRC4){ + value |= BIT_E1_TRAN_GENCRC; + }else if (WAN_FE_FRAME(fe) == WAN_FR_UNFRAMED){ + value |= BIT_E1_TRAN_FDIS; + } + if (WAN_TE1_SIG_MODE(fe) == WAN_TE1_SIG_CAS){ + value |= (BIT_E1_TRAN_SIGEN|BIT_E1_TRAN_DLEN); + } + WRITE_REG(REG_E1_TRAN_CFG, value); + + /* E1-FRMR Frame Alignment Options (Reg 0x90) */ + value = 0x00; + if (WAN_FE_FRAME(fe) == WAN_FR_CRC4){ + value |= (BIT_E1_FRMR_CRCEN | + BIT_E1_FRMR_REFCRCEN); + } + if (WAN_TE1_SIG_MODE(fe) == WAN_TE1_SIG_CCS){ + value |= BIT_E1_FRMR_CASDIS; + } + WRITE_REG(REG_E1_FRMR_CFG, value); + + }else{ + /* T1-XBAS Configuration (Reg 0x54) */ + value = 0x00; + if (WAN_FE_LCODE(fe) == WAN_LCODE_B8ZS){ + value |= BIT_T1_XBAS_B8ZS; + }else{ + value |= BIT_T1_XBAS_ZCS0; + } + if (WAN_FE_FRAME(fe) == WAN_FR_ESF){ + value |= BIT_T1_XBAS_ESF; + } + if (IS_J1_FEMEDIA(fe)){ + value |= BIT_T1_XBAS_JPN; + } + WRITE_REG(REG_T1_XBAS_CFG, value); + + /* T1-FRMR Configuration (Reg. 0x48) */ + value = 0x00; + if (WAN_FE_FRAME(fe) == WAN_FR_ESF){ + value = BIT_T1_FRMR_ESF | BIT_T1_FRMR_ESFFA; + } + if (IS_J1_FEMEDIA(fe)){ + value |= BIT_T1_FRMR_JPN; + } + WRITE_REG(REG_T1_FRMR_CFG, value); + + /* T1 ALMI Configuration (Reg. 0x60) */ + value = 0x00; + if (WAN_FE_FRAME(fe) == WAN_FR_ESF){ + value = BIT_T1_ALMI_CFG_ESF; + } + WRITE_REG(REG_T1_ALMI_CFG, value); + } + + /* SIGX Configuration Register (Reg. 0x50) */ + value = 0x00; + if (IS_E1_FEMEDIA(fe)){ + WRITE_REG(REG_SIGX_CFG, value); + }else{ + if (WAN_FE_FRAME(fe) == WAN_FR_ESF){ + value |= BIT_SIGX_ESF; + } + WRITE_REG(REG_SIGX_CFG, value); + } + + /* BTIF Configuration (Reg. 0x40) */ + value = 0x00; + if (IS_E1_FEMEDIA(fe)){ + value |= BIT_BTIF_RATE0; + } + if (!(adapter_type & A101_ADPTR_TE1_MASK)){ + if (WAN_FE_LCODE(fe) == WAN_LCODE_AMI){ + value |= BIT_BTIF_NXDS0_0; + } + } + if (WAN_FE_FRAME(fe) != WAN_FR_UNFRAMED){ + value |= BIT_BTIF_NXDS0_1; + } + if (adapter_type & A101_ADPTR_TE1_MASK){ + value |= (BIT_BTIF_CMODE | BIT_BTIF_DE | BIT_BTIF_FE); + } + WRITE_REG(REG_BTIF_CFG, value); + + /* BTIF_Frame Pulse Configuration (Reg. 0x41) */ + WRITE_REG(REG_BTIF_FR_PULSE_CFG, BIT_BTIF_FPMODE); + + /* BRIF Configuration (Reg. 0x30) */ + value = 0x00; + if (IS_E1_FEMEDIA(fe)){ + value |= BIT_BRIF_RATE0; + } + if (!(adapter_type & A101_ADPTR_TE1_MASK)){ + if (WAN_FE_LCODE(fe) == WAN_LCODE_AMI){ + value |= BIT_BRIF_NXDS0_0; + } + } + if (WAN_FE_FRAME(fe) != WAN_FR_UNFRAMED){ + value |= BIT_BRIF_NXDS0_1; + } + if (adapter_type & A101_ADPTR_TE1_MASK){ + value |= BIT_BRIF_CMODE; + } + WRITE_REG(REG_BRIF_CFG, value); + + /* BRIF Frame Pulse Configuration (Reg. 0x31) */ + value = 0x00; + if (adapter_type & A101_ADPTR_TE1_MASK){ + value |= BIT_BRIF_FPMODE; + } + WRITE_REG(REG_BRIF_FR_PULSE_CFG, value); + + /* BRIF Parity/F-bit Configuration (Reg. 0x32) */ + WRITE_REG(REG_BRIF_DATA_CFG, BIT_BRIF_DATA_TRI_0); + + /* Transmit Timing Options (Reg 0x06) */ + if (WAN_TE1_CLK(fe) == WAN_NORMAL_CLK){ + WRITE_REG(REG_TX_TIMING_OPT, + BIT_TX_PLLREF1 | + BIT_TX_TXELSTBYP); + }else{ + WRITE_REG(REG_TX_TIMING_OPT, + BIT_TX_PLLREF1 | + BIT_TX_PLLREF0 | + BIT_TX_TXELSTBYP); + } + + /* RLPS Configuration and Status (Reg 0xF8) */ + WRITE_REG(REG_RLPS_CFG_STATUS, + BIT_RLPS_CFG_STATUS_LONGE | + BIT_RLPS_CFG_STATUS_SQUELCHE); + + /* RLPS ALOS Detection/Clearance Thresholds (Reg 0xF9) */ + /* NC: Aug 20 2003: + * Set the correct ALSO Detection/Clearance tresholds + * for T1/E1 lines, to get rid of false ALOS alarms. + * + * Original incorrect value set was 0x00, for both T1/E1 */ + if (IS_E1_FEMEDIA(fe)){ + WRITE_REG(REG_RLPS_ALOS_DET_CLR_THR, + BIT_RLPS_ALOS_DET_THR_2| + BIT_RLPS_ALOS_DET_THR_1| + BIT_RLPS_ALOS_DET_THR_0); + }else{ + WRITE_REG(REG_RLPS_ALOS_DET_CLR_THR, + BIT_RLPS_ALOS_CLR_THR_2| + BIT_RLPS_ALOS_CLR_THR_0| + BIT_RLPS_ALOS_DET_THR_2| + BIT_RLPS_ALOS_DET_THR_0); + } + + /* RLPS ALOS Detection period (Reg 0xFA) */ + WRITE_REG(REG_RLPS_ALOS_DET_PER, BIT_RLPS_ALOS_DET_PER_0); + + /* RLPS ALOS Clearance period (Reg 0xFB) */ + WRITE_REG(REG_RLPS_ALOS_CLR_PER, BIT_RLPS_ALOS_CLR_PER_0); + + /* RLPS Equalizatopn Indirect Address (Reg. 0xFC) */ + /* ERRATA WRITE_REG(REG_RLPS_EQ_ADDR, 0x00); */ + + /* RLPS Equalization Read/WriteB Select (Reg 0xFD) */ + /* ERRATA WRITE_REG(REG_RLPS_EQ_RWB, BIT_RLPS_EQ_RWB); */ + + /* RLPS Equalizer Loop Status and Control (Reg 0xFE) */ + WRITE_REG(REG_RLPS_EQ_STATUS, 0x00); + + /* RLPS Equalizer Configuration (Reg 0xFF) */ + WRITE_REG(REG_RLPS_EQ_CFG, + BIT_RLPS_EQ_RESERVED | + BIT_RLPS_EQ_FREQ_1 | + BIT_RLPS_EQ_FREQ_0); + + /* TJAT Configuration (Reg 0x1B) */ + WRITE_REG(REG_TJAT_CFG, BIT_TJAT_CENT); + + /* RJAT Configuration (Reg 0x17) */ + WRITE_REG(REG_RJAT_CFG, BIT_RJAT_CENT); + + /* Receive Options (Reg 0x02) */ + if (WAN_FE_FRAME(fe) == WAN_FR_UNFRAMED){ + WRITE_REG(REG_RECEIVE_OPT, BIT_RECEIVE_OPT_UNF); + }else{ + WRITE_REG(REG_RECEIVE_OPT, 0x00); + } + + if (IS_E1_FEMEDIA(fe)){ + WRITE_REG(REG_E1_TRAN_NATB_CODESEL, + BIT_E1_TRAN_NATB_CODESEL_Sa4); + WRITE_REG(REG_E1_TRAN_NATB_CODE, 0xFF); + + WRITE_REG(REG_E1_TRAN_NATB_CODESEL, + BIT_E1_TRAN_NATB_CODESEL_Sa5); + WRITE_REG(REG_E1_TRAN_NATB_CODE, 0xFF); + + WRITE_REG(REG_E1_TRAN_NATB_CODESEL, + BIT_E1_TRAN_NATB_CODESEL_Sa6); + WRITE_REG(REG_E1_TRAN_NATB_CODE, 0xFF); + + WRITE_REG(REG_E1_TRAN_NATB_CODESEL, + BIT_E1_TRAN_NATB_CODESEL_Sa7); + WRITE_REG(REG_E1_TRAN_NATB_CODE, 0xFF); + + WRITE_REG(REG_E1_TRAN_NATB_CODESEL, + BIT_E1_TRAN_NATB_CODESEL_Sa8); + WRITE_REG(REG_E1_TRAN_NATB_CODE, 0xFF); + } + + /* XLPG Configuration #1 (Reg 0xF4) */ + /* 13 Jan 2005 WRITE_REG(REG_XLPG_TNC, BIT_XLPG_TNC_1); */ + + /* XLPG Configuration #2 (Reg 0xF5) */ + /* 13 Jan 2005 WRITE_REG(REG_XLPG_TPC, BIT_XLPG_TPC_1); */ + + /* RLPS Equalizer Voltage Reference (Reg 0xDC) */ + if (IS_E1_FEMEDIA(fe)){ + WRITE_REG(REG_EQ_VREF, 0x34); + }else{ + WRITE_REG(REG_EQ_VREF, 0x2C); + } + WRITE_REG(REG_RLPS_FUSE_CTRL_STAT, 0x00); + + /* ERRATA WRITE_REG(REG_RLPS_FUSE_CTRL_STAT, 0x00);*/ + + /* Call fuse stabilization procedure */ + FuseStabilizationProc(fe); + + /* Program Transmit pulse */ + InitLineReceiver(fe, + (IS_E1_FEMEDIA(fe) ? + pmc_e1_rlps_ram_table: + pmc_t1_rlps_ram_table)); + + return 0; +} + +/* + ****************************************************************************** + * sdla_pmc4354_te_config() + * + * Description: Configure Sangoma A104 TE1 board + * Arguments: + * Returns: WANTRUE - TE1 configred successfully, otherwise WAN_FALSE. + ****************************************************************************** + */ +static int sdla_pmc4354_te_config(sdla_fe_t *fe, u16 adapter_type) +{ + unsigned char value = 0x00; + + if (WAN_FE_FRAME(fe) == WAN_FR_UNFRAMED){ + DEBUG_EVENT("%s: ERROR: AFT-QUAD doesn't support UNFRAMED mode!\n", + fe->name); + return -EINVAL; + } + + /* Global Configuration (Reg 0xQ00) */ + value = READ_REG(REG_GLOBAL_CFG); + if (IS_E1_FEMEDIA(fe)){ + value |= BIT_GLOBAL_TRKEN; + }else{ + value |= BIT_GLOBAL_TRKEN; + } + WRITE_REG(REG_GLOBAL_CFG, value); + + + /* CDRC Configuration (Reg. 0xQ10) */ + if (WAN_FE_LCODE(fe) == WAN_LCODE_AMI){ + WRITE_REG(REG_CDRC_CFG, BIT_CDRC_CFG_AMI); + }else{ + WRITE_REG(REG_CDRC_CFG, 0x00); + } + + if (IS_E1_FEMEDIA(fe)) { + /* RX-ELST Configuration (Reg. 0xQ1C) */ + WRITE_REG(REG_RX_ELST_CFG, BIT_RX_ELST_IR | BIT_RX_ELST_OR); + /* TX-ELST Configuration (Reg. 0xQ20) */ + WRITE_REG(REG_TX_ELST_CFG, BIT_TX_ELST_IR | BIT_RX_ELST_OR); + }else{ + /* RX-ELST Configuration (Reg. 0xQ1C) */ + WRITE_REG(REG_RX_ELST_CFG, 0x00); + /* TX-ELST Configuration (Reg. 0xQ20) */ + WRITE_REG(REG_TX_ELST_CFG, 0x00); + } + + if (IS_E1_FEMEDIA(fe)){ + /* E1-TRAN Configuration (Reg. 0xQ80) */ + value = 0x00; + if (WAN_FE_LCODE(fe) == WAN_LCODE_AMI){ + value |= BIT_E1_TRAN_AMI; + } + if (WAN_FE_FRAME(fe) == WAN_FR_CRC4){ + value |= BIT_E1_TRAN_GENCRC; + }else if (WAN_FE_FRAME(fe) == WAN_FR_UNFRAMED){ + value |= BIT_E1_TRAN_FDIS; + } + if (WAN_TE1_SIG_MODE(fe) == WAN_TE1_SIG_CAS){ + value |= (BIT_E1_TRAN_SIGEN|BIT_E1_TRAN_DLEN); + } + WRITE_REG(REG_E1_TRAN_CFG, value); + + /* E1-FRMR Frame Alignment Options (Reg 0xQ90) */ + value = 0x00; + if (WAN_FE_FRAME(fe) == WAN_FR_CRC4){ + value |= (BIT_E1_FRMR_CRCEN | + BIT_E1_FRMR_REFCRCEN); + } + if (WAN_TE1_SIG_MODE(fe) == WAN_TE1_SIG_CCS){ + value |= BIT_E1_FRMR_CASDIS; + } + WRITE_REG(REG_E1_FRMR_CFG, value); + + }else{ + /* T1-XBAS Configuration (Reg 0xQ54) */ + value = 0x00; + if (WAN_FE_LCODE(fe) == WAN_LCODE_B8ZS){ + value |= BIT_T1_XBAS_B8ZS; + }else{ + value |= BIT_T1_XBAS_ZCS0; + } + if (WAN_FE_FRAME(fe) == WAN_FR_ESF){ + value |= BIT_T1_XBAS_ESF; + } + if (IS_J1_FEMEDIA(fe)){ + value |= BIT_T1_XBAS_JPN; + } + WRITE_REG(REG_T1_XBAS_CFG, value); + + /* T1-FRMR Configuration (Reg. 0xQ48) */ + value = 0x00; + if (WAN_FE_FRAME(fe) == WAN_FR_ESF){ + value = BIT_T1_FRMR_ESF | BIT_T1_FRMR_ESFFA; + } + if (IS_J1_FEMEDIA(fe)){ + value |= BIT_T1_FRMR_JPN; + } + WRITE_REG(REG_T1_FRMR_CFG, value); + + /* T1 ALMI Configuration (Reg. 0xQ60) */ + value = 0x00; + if (WAN_FE_FRAME(fe) == WAN_FR_ESF){ + value |= BIT_T1_ALMI_CFG_ESF; + } + WRITE_REG(REG_T1_ALMI_CFG, value); + } + + /* SIGX Configuration Register (Reg. 0xQ50) */ + value = 0x00; + if (IS_E1_FEMEDIA(fe)){ + WRITE_REG(REG_SIGX_CFG, value); + }else{ + if (WAN_FE_FRAME(fe) == WAN_FR_ESF){ + value |= BIT_SIGX_ESF; + } + WRITE_REG(REG_SIGX_CFG, value); + } + + /* BTIF Configuration (Reg. 0xQ40) */ + value = 0x00; + if (IS_E1_FEMEDIA(fe)){ + value |= BIT_BTIF_RATE0; + } +#if 0 + /* If AMI is selected is only can be used for VOICE. + * In this case, we need to use FULL FRAME mode (no gaps). */ + if (WAN_FE_LCODE(fe) == WAN_LCODE_AMI){ + value |= BIT_BTIF_NXDS0_0; + } +#endif + value |= BIT_BTIF_DE; + if (WAN_TE1_CLK(fe) == WAN_MASTER_CLK && + WAN_TE1_REFCLK(fe) != WAN_TE1_REFCLK_OSC){ + /* Configure Transmit clock as input (slave) */ + value |= BIT_BTIF_CMODE; + } + WRITE_REG(REG_BTIF_CFG, value); + + /* BTIF_Frame Pulse Configuration (Reg. 0xQ41) */ + if (WAN_TE1_CLK(fe) == WAN_MASTER_CLK && + WAN_TE1_REFCLK(fe) != WAN_TE1_REFCLK_OSC){ + /* Configure Transmit frame pulse as input (slave) */ + WRITE_REG(REG_BTIF_FR_PULSE_CFG, BIT_BTIF_FPMODE); + }else{ + WRITE_REG(REG_BTIF_FR_PULSE_CFG, 0x00); + } + + /* BRIF Configuration (Reg. 0xQ30) */ + value = 0x00; + if (IS_E1_FEMEDIA(fe)){ + value |= BIT_BRIF_RATE0; + } +#if 0 + /* If AMI is selected is only can be used for VOICE. + * In this case, we need to use FULL FRAME mode (no gaps). */ + if (WAN_FE_LCODE(fe) == WAN_LCODE_AMI){ + value |= BIT_BRIF_NXDS0_0; + } +#endif + value |= (BIT_BRIF_CMODE | BIT_BRIF_FE); + WRITE_REG(REG_BRIF_CFG, value); + + /* BRIF Frame Pulse Configuration (Reg. 0xQ31) */ + WRITE_REG(REG_BRIF_FR_PULSE_CFG, BIT_BRIF_FPMODE); + + /* BRIF Parity/F-bit Configuration (Reg. 0xQ32) */ + WRITE_REG(REG_BRIF_DATA_CFG, BIT_BRIF_DATA_TRI_0); + + /* Transmit Timing Options (Reg 0xQ06) */ + if (WAN_TE1_CLK(fe) == WAN_NORMAL_CLK){ + /* 1. Set TJAT FIFO output clock signal + * 2. Receive recovered clock */ + WRITE_REG(REG_TX_TIMING_OPT, + BIT_TX_PLLREF1 | + BIT_TX_TXELSTBYP); + }else{ + if (WAN_TE1_CLK(fe) == WAN_MASTER_CLK && + WAN_TE1_REFCLK(fe) != WAN_TE1_REFCLK_OSC){ + /* In this case, we should set only PLLREF0 bit + ** to 1 (firmware also been changed in order to + ** solve this problem). Nov 1, 2005 + ** WRITE_REG(REG_TX_TIMING_OPT, + ** BIT_TX_PLLREF1 | + ** BIT_TX_PLLREF0); */ + WRITE_REG(REG_TX_TIMING_OPT, BIT_TX_PLLREF0|BIT_TX_TXELSTBYP); + }else{ + /* 1. Set TJAT FIFO output clock signal + * 2. CTCLK input */ + WRITE_REG(REG_TX_TIMING_OPT, + BIT_TX_PLLREF1 | + BIT_TX_PLLREF0 | + BIT_TX_TXELSTBYP); + } + } + + /* RLPS Configuration and Status (Reg 0xQF8) */ + WRITE_REG(REG_RLPS_CFG_STATUS, + BIT_RLPS_CFG_STATUS_LONGE | + BIT_RLPS_CFG_STATUS_SQUELCHE); + + /* RLPS ALOS Detection/Clearance Thresholds (Reg 0xQF9) */ + /* NC: Aug 20 2003: + * Set the correct ALSO Detection/Clearance tresholds + * for T1/E1 lines, to get rid of false ALOS alarms. + * + * Original incorrect value set was 0x00, for both T1/E1 */ + if (IS_E1_FEMEDIA(fe)){ + WRITE_REG(REG_RLPS_ALOS_DET_CLR_THR, + BIT_RLPS_ALOS_DET_THR_2| + BIT_RLPS_ALOS_DET_THR_1| + BIT_RLPS_ALOS_DET_THR_0); + }else{ + WRITE_REG(REG_RLPS_ALOS_DET_CLR_THR, + BIT_RLPS_ALOS_CLR_THR_2| + BIT_RLPS_ALOS_CLR_THR_0| + BIT_RLPS_ALOS_DET_THR_2| + BIT_RLPS_ALOS_DET_THR_0); + } + + /* RLPS ALOS Detection period (Reg 0xQFA) */ + WRITE_REG(REG_RLPS_ALOS_DET_PER, BIT_RLPS_ALOS_DET_PER_0); + + /* RLPS ALOS Clearance period (Reg 0xQFB) */ + WRITE_REG(REG_RLPS_ALOS_CLR_PER, BIT_RLPS_ALOS_CLR_PER_0); + + /* RLPS Equalizatopn Indirect Address (Reg. 0xQFC) */ + /* ERRATA WRITE_REG(REG_RLPS_EQ_ADDR, 0x00); */ + + /* RLPS Equalization Read/WriteB Select (Reg 0xQFD) */ + /* ERRATA WRITE_REG(REG_RLPS_EQ_RWB, BIT_RLPS_EQ_RWB); */ + + /* RLPS Equalizer Loop Status and Control (Reg 0xQFE) */ + WRITE_REG(REG_RLPS_EQ_STATUS, 0x00); + + /* TJAT Configuration (Reg 0xQ1B) */ + WRITE_REG(REG_TJAT_CFG, BIT_TJAT_CENT); + + /* RJAT Configuration (Reg 0xQ17) */ + WRITE_REG(REG_RJAT_CFG, BIT_RJAT_CENT); + + /* Receive Options (Reg 0xQ02) */ + if (WAN_FE_FRAME(fe) == WAN_FR_UNFRAMED){ + WRITE_REG(REG_RECEIVE_OPT, BIT_RECEIVE_OPT_UNF); + }else{ + WRITE_REG(REG_RECEIVE_OPT, 0x00); + } + + if (IS_E1_FEMEDIA(fe)){ + WRITE_REG(REG_E1_TRAN_NATB_CODESEL, + BIT_E1_TRAN_NATB_CODESEL_Sa4); + WRITE_REG(REG_E1_TRAN_NATB_CODE, 0xFF); + + WRITE_REG(REG_E1_TRAN_NATB_CODESEL, + BIT_E1_TRAN_NATB_CODESEL_Sa5); + WRITE_REG(REG_E1_TRAN_NATB_CODE, 0xFF); + + WRITE_REG(REG_E1_TRAN_NATB_CODESEL, + BIT_E1_TRAN_NATB_CODESEL_Sa6); + WRITE_REG(REG_E1_TRAN_NATB_CODE, 0xFF); + + WRITE_REG(REG_E1_TRAN_NATB_CODESEL, + BIT_E1_TRAN_NATB_CODESEL_Sa7); + WRITE_REG(REG_E1_TRAN_NATB_CODE, 0xFF); + + WRITE_REG(REG_E1_TRAN_NATB_CODESEL, + BIT_E1_TRAN_NATB_CODESEL_Sa8); + WRITE_REG(REG_E1_TRAN_NATB_CODE, 0xFF); + } + + /* XLPG Configuration #1 (Reg 0xQF4) */ + /* 13 Jan 2005 WRITE_REG(REG_XLPG_TNC, BIT_XLPG_TNC_1); */ + WRITE_REG(REG_XLPG_TNC, BIT_XLPG_TNC_1); /* ADEBUG */ + + /* XLPG Configuration #2 (Reg 0xQF5) */ + /* 13 Jan 2005 WRITE_REG(REG_XLPG_TPC, BIT_XLPG_TPC_1); */ + WRITE_REG(REG_XLPG_TPC, BIT_XLPG_TPC_1); /* ADEBUG */ + + /* RLPS Equalizer Voltage Reference (Reg 0xQDC) */ + if (IS_E1_FEMEDIA(fe)){ + WRITE_REG(REG_EQ_VREF, 0x3D); /* ADEBUG: original 0x34 */ + }else{ + WRITE_REG(REG_EQ_VREF, 0x2C); + } + + /* ADEBUG: This register doesn't exist + * WRITE_REG(REG_RLPS_FUSE_CTRL_STAT, 0x00); */ + + /* Program Transmit pulse */ + InitLineReceiver(fe, + (IS_E1_FEMEDIA(fe) ? + pmc4_e1_rlps_ram_table: + pmc4_t1_rlps_ram_table)); + + /* RLPS Equalizer Configuration (Reg 0xQFF) */ + WRITE_REG(REG_RLPS_EQ_CFG, + BIT_RLPS_EQ_EQEN | + BIT_RLPS_EQ_RESERVED_1 | + BIT_RLPS_EQ_RESERVED_0); + + /* Program Transmit pulse template */ + fe->te_param.xlpg_scale = PrgTransmitTemplate(fe); + + /* Call fuse stabilization procedure */ + FuseStabilizationProc(fe); + + /* XLPG Line Driver Configuration (Reg. 0xQF0) */ + if (IS_FE_TXTRISTATE(fe)){ + DEBUG_EVENT("%s: Disable Transmitter (tx tri-state mode)!\n", + fe->name); + WRITE_REG(REG_XLPG_LINE_CFG, BIT_XLPG_LINE_CFG_HIGHZ); + }else{ + WRITE_REG(REG_XLPG_LINE_CFG, fe->te_param.xlpg_scale); + } + + return 0; +} + + +/* + ****************************************************************************** + * sdla_pmc4354_rlps_optim() + * + * Description: PMC4354 COMET QUAD RLPS optimization routine. + * + * Arguments: + * Returns: + ****************************************************************************** + */ +static int sdla_pmc4354_rlps_optim(sdla_fe_t *fe) +{ + /* RLPS Optimization routine */ + WRITE_REG_LINE(0, 0x4D7, 0x00); /* 01 */ + WRITE_REG_LINE(0, 0x4F1, 0x00); /* 02 */ + WRITE_REG_LINE(0, 0x5F1, 0x00); /* 03 */ + WRITE_REG_LINE(0, 0x6F1, 0x00); /* 04 */ + WRITE_REG_LINE(0, 0x7F1, 0x00); /* 05 */ + WRITE_REG_LINE(0, 0x4F9, 0x00); /* 06 */ + WRITE_REG_LINE(0, 0x5F9, 0x00); /* 07 */ + WRITE_REG_LINE(0, 0x6F9, 0x00); /* 08 */ + WRITE_REG_LINE(0, 0x7F9, 0x00); /* 09 */ + WRITE_REG_LINE(0, 0x4F9, 0x04); /* 10 */ + WRITE_REG_LINE(0, 0x4FB, 0x09); /* 11 */ + WRITE_REG_LINE(0, 0x00B, 0x20); /* 12 */ + WP_DELAY(1); + WRITE_REG_LINE(0, 0x4F9, 0x00); /* 14 */ + WRITE_REG_LINE(0, 0x00B, 0x00); /* 15 */ + WRITE_REG_LINE(0, 0x5F9, 0x04); /* 16 */ + WRITE_REG_LINE(0, 0x5FB, 0x09); /* 17 */ + WRITE_REG_LINE(0, 0x00B, 0x20); /* 18 */ + WP_DELAY(1); + WRITE_REG_LINE(0, 0x5F9, 0x00); /* 20 */ + WRITE_REG_LINE(0, 0x00B, 0x00); /* 21 */ + WRITE_REG_LINE(0, 0x6F9, 0x04); /* 22 */ + WRITE_REG_LINE(0, 0x6FB, 0x09); /* 23 */ + WRITE_REG_LINE(0, 0x00B, 0x20); /* 24 */ + WP_DELAY(1); + WRITE_REG_LINE(0, 0x6F9, 0x00); /* 26 */ + WRITE_REG_LINE(0, 0x00B, 0x00); /* 27 */ + WRITE_REG_LINE(0, 0x7F9, 0x04); /* 28 */ + WRITE_REG_LINE(0, 0x7FB, 0x09); /* 29 */ + WRITE_REG_LINE(0, 0x00B, 0x20); /* 30 */ + WP_DELAY(1); + WRITE_REG_LINE(0, 0x7F9, 0x00); /* 32 */ + WRITE_REG_LINE(0, 0x00B, 0x00); /* 33 */ + + return 0; +} + + +/* + ****************************************************************************** + * sdla_te_config() + * + * Description: Configure Sangoma T1/E1 boards + * Arguments: + * Returns: WANTRUE - TE1 configred successfully, otherwise WAN_FALSE. + ****************************************************************************** + */ +static int sdla_te_config(void* pfe) +{ + sdla_fe_t *fe = (sdla_fe_t*)pfe; + sdla_t* card = (sdla_t*)fe->card; + u16 adapter_type; + unsigned char value = 0x00; + + WAN_ASSERT(fe->write_fe_reg == NULL); + WAN_ASSERT(fe->read_fe_reg == NULL); + + /* Initial FE state */ + fe->fe_status=FE_DISCONNECTED; + + /* Revision/Chip ID (Reg. 0x0D) */ + value = READ_REG_LINE(0, REG_REVISION_CHIP_ID); + fe->fe_chip_id = value & MASK_CHIP_ID; + switch(fe->fe_chip_id){ + case CHIP_ID_COMET: + fe->fe_cfg.line_no = 0; + break; + case CHIP_ID_COMET_QUAD: + if (WAN_FE_LINENO(fe) < 0 || WAN_FE_LINENO(fe) > 3){ + DEBUG_EVENT("%s: TE Config: Invalid Port selected %d (Min=1 Max=4)\n", + fe->name, + WAN_FE_LINENO(fe)+1); + return -EINVAL; + } + break; + default: + DEBUG_EVENT("%s: ERROR: Unsupported %s CHIP (0x%02X)\n", + fe->name, + FE_MEDIA_DECODE(fe), + (fe->fe_chip_id >> 5)); + return -EINVAL; + } + + card->hw_iface.getcfg(card->hw, SDLA_ADAPTERTYPE, &adapter_type); + DEBUG_EVENT("%s: Configuring PMC %s %s Front End (Port %d)!\n", + fe->name, + DECODE_CHIPID(fe->fe_chip_id), + FE_MEDIA_DECODE(fe), + WAN_FE_LINENO(fe)+1); + + DEBUG_TE1("%s: %s Line decoding %s\n", + fe->name, + FE_MEDIA_DECODE(fe), + FE_LCODE_DECODE(fe)); + DEBUG_TE1("%s: %s Frame type %s\n", + fe->name, + FE_MEDIA_DECODE(fe), + FE_FRAME_DECODE(fe)); + if (IS_T1_FEMEDIA(fe)){ + DEBUG_TE1("%s: %s LBO %s\n", + fe->name, + FE_MEDIA_DECODE(fe), + TE_LBO_DECODE(fe)); + } + if (WAN_TE1_CLK(fe) == WAN_MASTER_CLK){ + if (WAN_TE1_REFCLK(fe) != WAN_TE1_REFCLK_OSC){ + DEBUG_TE1("%s: %s Clock mode Master (refclk from Port %d)\n", + fe->name, + FE_MEDIA_DECODE(fe), + WAN_TE1_REFCLK(fe)); + }else{ + DEBUG_TE1("%s: %s Clock mode Master (Osciliator)\n", + fe->name, + FE_MEDIA_DECODE(fe)); + } + }else{ + DEBUG_TE1("%s: %s Clock mode Normal\n", + fe->name, + FE_MEDIA_DECODE(fe)); + } + DEBUG_TE1("%s: %s robbit-signalling channels %lX\n", + fe->name, + FE_MEDIA_DECODE(fe), + fe->fe_cfg.cfg.te_cfg.te_rbs_ch); + memset(&fe->te_param, 0, sizeof(sdla_te_param_t)); + + fe->te_param.max_channels = + (IS_E1_FEMEDIA(fe)) ? NUM_OF_E1_TIMESLOTS: NUM_OF_T1_CHANNELS; + switch(fe->fe_chip_id){ + case CHIP_ID_COMET: + sdla_pmc4351_te_config(fe, adapter_type); + break; + + case CHIP_ID_COMET_QUAD: + sdla_pmc4354_te_config(fe, adapter_type); + sdla_pmc4354_rlps_optim(fe); + break; + + default: + DEBUG_EVENT("%s: ERROR: Unsupported T1/E1 CHIP (0x%02X)\n", + fe->name, (fe->fe_chip_id >> 5)); + return -EINVAL; + } + + ClearRPSCReg(fe); + ClearTPSCReg(fe); + DisableAllChannels(fe); + + if (WAN_TE1_ACTIVE_CH(fe) == ENABLE_ALL_CHANNELS){ + DEBUG_EVENT("%s: All channels enabled\n", fe->name); + EnableAllChannels(fe); + }else{ + int channel_range = (IS_T1_FEMEDIA(fe)) ? + NUM_OF_T1_CHANNELS : NUM_OF_E1_TIMESLOTS; + + int i = 0; + + for(i = 1; i <= channel_range; i++){ + if (WAN_TE1_ACTIVE_CH(fe) & (1 << (i - 1))){ + DEBUG_EVENT("%s: Enable channel %d\n", + fe->name, i); + EnableTxChannel(fe, i); + EnableRxChannel(fe, i); + } + } + } + + /* Initialize and start T1/E1 timer */ + wan_set_bit(TE_TIMER_KILL,(void*)&fe->te_param.critical); + + wan_init_timer( + &fe->te_param.timer, + sdla_te_timer, + (wan_timer_arg_t)fe); + + /* Set initial FE status to uninitialized value and let the next function + * set correct value */ + fe->fe_status = 0; + /* Read initial alarm status and then enable T1/E1 alarm interrupts */ + /* sdla_te_alarm(fe, 0); */ + + wan_clear_bit(TE_TIMER_KILL,(void*)&fe->te_param.critical); + wan_clear_bit(TE_TIMER_RUNNING,(void*)&fe->te_param.critical); + sdla_te_enable_timer(fe, TE_LINKDOWN_TIMER, INTR_TE1_TIMER); + + wan_set_bit(TE_CONFIGURED,(void*)&fe->te_param.critical); + + return 0; +} + +/* + ****************************************************************************** + * sdla_te_post_config() + * + * Description: T1/E1 post configuration. + * Arguments: + * Returns: + ****************************************************************************** + */ +static int sdla_te_post_config(sdla_fe_t* fe) +{ + unsigned char value; + + if (IS_E1_FEMEDIA(fe)){ + if (WAN_TE1_SIG_MODE(fe) == WAN_TE1_SIG_CAS){ + DEBUG_EVENT("%s: Enable E1 CAS signalling mode!\n", + fe->name); + /* E1-TRAN Configuration (Reg. 0x80) */ + value = READ_REG(REG_E1_TRAN_CFG); + value |= (BIT_E1_TRAN_SIGEN|BIT_E1_TRAN_DLEN); + WRITE_REG(REG_E1_TRAN_CFG, value); + + /* E1-FRMR Frame Alignment Options (Reg 0x90) */ + value = READ_REG(REG_E1_FRMR_CFG); + value &= ~BIT_E1_FRMR_CASDIS; + WRITE_REG(REG_E1_FRMR_CFG, value); + + }else if (WAN_TE1_SIG_MODE(fe) == WAN_TE1_SIG_CCS){ + DEBUG_EVENT("%s: Disable E1 CAS signalling mode!\n", + fe->name); + /* E1-TRAN Configuration (Reg. 0x80) */ + value = READ_REG(REG_E1_TRAN_CFG); + value &= ~(BIT_E1_TRAN_SIGEN|BIT_E1_TRAN_DLEN); + WRITE_REG(REG_E1_TRAN_CFG, value); + + /* E1-FRMR Frame Alignment Options (Reg 0x90) */ + value = READ_REG(REG_E1_FRMR_CFG); + value |= BIT_E1_FRMR_CASDIS; + WRITE_REG(REG_E1_FRMR_CFG, value); + } + } + return 0; +} + +/* + ****************************************************************************** + * sdla_te_set_intr() + * + * Description: Enable T1/E1 interrupts. + * Arguments: + * Returns: + ****************************************************************************** + */ +static void sdla_te_set_intr(sdla_fe_t* fe) +{ + + DEBUG_EVENT("%s: Enabling TE1 Interrupts \n",fe->name); + + /* Enable LOS interrupt */ + WRITE_REG(REG_CDRC_INT_EN, BIT_CDRC_INT_EN_LOSE); + +#if defined(FE_ALOS_ENABLE) + /* Enable ALOS interrupt */ + WRITE_REG(REG_RLPS_CFG_STATUS, + READ_REG(REG_RLPS_CFG_STATUS) | BIT_RLPS_CFG_STATUS_ALOSE); +#endif + if (IS_T1_FEMEDIA(fe)){ + /* Enable RBOC interrupt */ + WRITE_REG(REG_T1_RBOC_ENABLE, + BIT_T1_RBOC_ENABLE_IDLE | + BIT_T1_RBOC_ENABLE_BOCE); + /* Enable interrupt on RED, AIS, YEL alarms */ + WRITE_REG(REG_T1_ALMI_INT_EN, + BIT_T1_ALMI_INT_EN_FASTD | + BIT_T1_ALMI_INT_EN_REDE | + BIT_T1_ALMI_INT_EN_AISE | + BIT_T1_ALMI_INT_EN_YELE); + /* Enable interrupt on OOF alarm */ + /* WRITE_REG(REG_T1_FRMR_INT_EN, BIT_T1_FRMR_INT_EN_INFRE); */ + }else{ + /* Enable interrupt on RED, AIS alarms */ + WRITE_REG(REG_E1_FRMR_M_A_INT_EN, + BIT_E1_FRMR_M_A_INT_EN_REDE | + BIT_E1_FRMR_M_A_INT_EN_AISE); + /* Enable OOF Interrupt */ + /*WRITE_REG(REG_E1_FRMR_FRM_STAT_INT_EN,BIT_E1_FRMR_FRM_STAT_INT_EN_OOFE);*/ + } + /* Enable PMON interrupt */ + WRITE_REG(REG_PMON_INT_EN_STATUS, + READ_REG(REG_PMON_INT_EN_STATUS) | BIT_PMON_INT_EN_STATUS_INTE); + return; +} + +/* + ****************************************************************************** + * sdla_te_clear_intr() + * + * Description: Disable T1/E1 interrupts. + * Arguments: + * Returns: + ****************************************************************************** + */ +static void sdla_te_clear_intr(sdla_fe_t* fe) +{ + + DEBUG_EVENT("%s: Clearing TE1 Interrupts\n",fe->name); + + /* Enable LOS interrupt */ + WRITE_REG(REG_CDRC_INT_EN, + READ_REG(REG_CDRC_INT_EN) & ~BIT_CDRC_INT_EN_LOSE); + /* Enable ALOS interrupt */ + WRITE_REG(REG_RLPS_CFG_STATUS, + READ_REG(REG_RLPS_CFG_STATUS) & ~BIT_RLPS_CFG_STATUS_ALOSE); + if (IS_T1_FEMEDIA(fe)){ + /* Enable RBOC interrupt */ + WRITE_REG(REG_T1_RBOC_ENABLE, + READ_REG(REG_T1_RBOC_ENABLE) & + ~(BIT_T1_RBOC_ENABLE_IDLE | + BIT_T1_RBOC_ENABLE_BOCE)); + /* Enable interrupt on RED, AIS, YEL alarms */ + WRITE_REG(REG_T1_ALMI_INT_EN, + READ_REG(REG_T1_ALMI_INT_EN) & + ~(BIT_T1_ALMI_INT_EN_REDE | + BIT_T1_ALMI_INT_EN_AISE | + BIT_T1_ALMI_INT_EN_YELE)); + /* Enable interrupt on OOF alarm */ + /* WRITE_REG(REG_T1_FRMR_INT_EN, + * BIT_T1_FRMR_INT_EN_INFRE);*/ + }else{ + /* Enable interrupt on RED, AIS alarms */ + WRITE_REG(REG_E1_FRMR_M_A_INT_EN, + READ_REG(REG_E1_FRMR_M_A_INT_EN) & + ~(BIT_E1_FRMR_M_A_INT_EN_REDE | + BIT_E1_FRMR_M_A_INT_EN_AISE)); + /* Enable OOF Interrupt */ + /* WRITE_REG(REG_E1_FRMR_FRM_STAT_INT_EN, + * BIT_E1_FRMR_FRM_STAT_INT_EN_OOFE);*/ + } + /* Disable PMON interrupt */ + WRITE_REG(REG_PMON_INT_EN_STATUS, + READ_REG(REG_PMON_INT_EN_STATUS) & ~BIT_PMON_INT_EN_STATUS_INTE); + + return; +} + + +static int sdla_te_sigctrl(sdla_fe_t *fe, int sig_mode) +{ + int err = 0; + + if (sig_mode == WAN_TE_SIG_INTR){ + + /* Enable signaling interrupt in case if we are not + ** using polling routines for reading signaling bits + ** from PMC chip. te_signaling_config function pointer + ** is used for S514x T1/E1 card only. All new AFT + ** cards use Signaling interrupt for this + ** (Aug 5, 2004) */ + if (fe->fe_status == FE_CONNECTED){ + /* Enable SIGE and COSS */ + DEBUG_TEST("%s: Enable SIGX interrupt\n", + fe->name); + WRITE_REG(REG_SIGX_CFG, + READ_REG(REG_SIGX_CFG) & ~BIT_SIGX_COSS); + WRITE_REG(REG_SIGX_CFG, + READ_REG(REG_SIGX_CFG) | BIT_SIGX_SIGE); + }else{ + DEBUG_TEST("%s: Disable SIGX interrupt\n", + fe->name); + WRITE_REG(REG_SIGX_CFG, + READ_REG(REG_SIGX_CFG) & ~BIT_SIGX_COSS); + WRITE_REG(REG_SIGX_CFG, + READ_REG(REG_SIGX_CFG) & ~BIT_SIGX_SIGE); + } + } +#if 0 + /* Do not support RBS for the old cards */ + if (card->wandev.te_signaling_config){ + err=card->wandev.te_signaling_config(card,timeslot_map); + if (err) return err; + err=card->wandev.te_read_signaling_config(card); + if (err) return err; + } +#endif + return err; +} + +/* + ****************************************************************************** + * sdla_te_global_unconfig() + * + * Description: Global configuration for Sangoma TE1 PMC board. + * Note: These register should be program only once for AFT-QUAD + * cards. + * Arguments: + * Returns: WANTRUE - TE1 configred successfully, otherwise WAN_FALSE. + ****************************************************************************** + */ +static int sdla_te_global_unconfig(void* pfe) +{ + sdla_fe_t *fe = (sdla_fe_t*)pfe; + + DEBUG_EVENT("%s: T1/E1 Global unconfiguration!\n", fe->name); + /* 1. Initiate software reset of the COMET */ + /* Set RESET=1 to place COMET into RESET */ + WRITE_REG_LINE(0, REG_RESET, BIT_RESET); + + /* Set RESET=0, disable software reset. COMET in default mode. */ + WRITE_REG_LINE(0, REG_RESET, 0x0/*~BIT_RESET*/); + return 0; +} + +/* + ****************************************************************************** + * sdla_te_unconfig() + * + * Description: T1/E1 unconfig. + * Arguments: + * Returns: + ****************************************************************************** + */ +static int sdla_te_unconfig(void* pfe) +{ + sdla_fe_t *fe = (sdla_fe_t*)pfe; + + if (!wan_test_bit(TE_CONFIGURED,(void*)&fe->te_param.critical)){ + return -EINVAL; + } + + /* Clear and Kill TE timer poll command */ + wan_clear_bit(TE_CONFIGURED,(void*)&fe->te_param.critical); + wan_set_bit(TE_TIMER_KILL,(void*)&fe->te_param.critical); + + /* FIXME: Alex to disable interrupts here */ + sdla_te_clear_intr(fe); + + wan_del_timer(&fe->te_param.timer); + + fe->te_param.timer_cmd = 0x00; + wan_clear_bit(TE_TIMER_RUNNING,(void*)&fe->te_param.critical); + + ClearTemplate(fe); + + return 0; +} + +/***************************************************************************** +** sdla_te_master_clock() +** sdla_te_normal_clock() +** +** Description: This function is called only if frond end clock is congirued +** originally to NORMAL (otherwise its never called). According +** specification, when the CE recieves AIS alarm, the CE shall +** transmit from it's internal clock. When AIS alarm is cleared +** transmit should change clock type to normal. +** Arguments: +** Returns: +******************************************************************************/ +static int sdla_te_master_clock(sdla_fe_t *fe) +{ + switch(fe->fe_chip_id){ + case CHIP_ID_COMET: + WRITE_REG(REG_TX_TIMING_OPT, + BIT_TX_PLLREF1 | + BIT_TX_PLLREF0 | + BIT_TX_TXELSTBYP); + break; + + case CHIP_ID_COMET_QUAD: + WRITE_REG(REG_TX_TIMING_OPT, + BIT_TX_PLLREF1 | + BIT_TX_PLLREF0); + break; + } + return 0; +} + +static int sdla_te_normal_clock(sdla_fe_t *fe) +{ + WRITE_REG(REG_TX_TIMING_OPT, + BIT_TX_PLLREF1 | + BIT_TX_TXELSTBYP); + return 0; +} + +/* + ****************************************************************************** + * sdla_te_set_status() + * + * Description: Set T1/E1 status. Enable OOF and LCV interrupt (if status + * changed to disconnected. + * Arguments: + * Returns: + ****************************************************************************** + */ +static void sdla_te_set_status(sdla_fe_t* fe, unsigned long alarms) +{ + sdla_t *card = (sdla_t*)fe->card; + unsigned char curr_fe_status = fe->fe_status; + + if (IS_T1_FEMEDIA(fe)){ + if (IS_T1_ALARM(alarms)){ + if (fe->fe_status != FE_DISCONNECTED){ + sdla_te_set_alarms(fe, WAN_TE_BIT_YEL_ALARM); + fe->fe_status = FE_DISCONNECTED; + } + }else{ + sdla_te_clear_alarms(fe, WAN_TE_BIT_YEL_ALARM); + if (!(fe->fe_alarm & WAN_TE_BIT_YEL_ALARM)){ + if (fe->fe_status != FE_CONNECTED){ + fe->fe_status = FE_CONNECTED; + } + }else{ + fe->fe_status = FE_DISCONNECTED; + } + } + }else{ + if (IS_E1_ALARM(alarms)){ + if (fe->fe_status != FE_DISCONNECTED){ + fe->fe_status = FE_DISCONNECTED; + } + }else{ + if (fe->fe_status != FE_CONNECTED){ + fe->fe_status = FE_CONNECTED; + } + } + } + if (curr_fe_status != fe->fe_status){ + if (fe->fe_status == FE_CONNECTED){ + DEBUG_EVENT("%s: %s connected!\n", + fe->name, + FE_MEDIA_DECODE(fe)); + }else{ + DEBUG_EVENT("%s: %s disconnected!\n", + fe->name, + FE_MEDIA_DECODE(fe)); + } + } + +#if 0 + if (IS_T1_FEMEDIA(fe)){ + if (IS_T1_ALARM(alarms)){ + if (fe->fe_status != FE_DISCONNECTED){ + DEBUG_EVENT("%s: T1 disconnected!\n", + fe->name); + fe->fe_status = FE_DISCONNECTED; + } + }else{ + if (fe->fe_status != FE_CONNECTED){ + DEBUG_EVENT("%s: T1 connected!\n", + fe->name); + fe->fe_status = FE_CONNECTED; + } + } + }else{ + if (IS_E1_ALARM(alarms)){ + if (fe->fe_status != FE_DISCONNECTED){ + DEBUG_EVENT("%s: E1 disconnected!\n", + fe->name); + fe->fe_status = FE_DISCONNECTED; + } + }else{ + if (fe->fe_status != FE_CONNECTED){ + DEBUG_EVENT("%s: E1 connected!\n", + fe->name); + fe->fe_status = FE_CONNECTED; + } + } + } +#endif + if (card->wandev.te_report_alarms){ + card->wandev.te_report_alarms(card, alarms); + } + +#if 0 + if (curr_fe_status != fe->fe_status && enable_poll){ + if (fe->fe_status == FE_DISCONNECTED){ + /* Start T1/E1 timer (5 sec) */ + sdla_te_enable_timer(fe, TE_LINKDOWN_TIMER, POLLING_TE1_TIMER * 5); + } +#if 0 + ADEBUG!!!! + if (fe->fe_status == FE_CONNECTED){ + sdla_te_set_intr(fe); + }else{ + sdla_te_clear_intr(fe); + } +#endif + } +#endif + +#if 0 + if (fe->fe_status == FE_CONNECTED){ + WRITE_REG(REG_CDRC_INT_EN, + (READ_REG(REG_CDRC_INT_EN) | BIT_CDRC_INT_EN_LOSE)); + }else{ + WRITE_REG(REG_CDRC_INT_EN, + (READ_REG(REG_CDRC_INT_EN) & ~BIT_CDRC_INT_EN_LOSE)); + } +#endif + + return; +} + +/* + ****************************************************************************** + * sdla_te_print_channels() + * + * Description: Print T1/E1 active channels. + * Arguments: + * Returns: + ****************************************************************************** + */ +static char* sdla_te_print_channels(sdla_fe_t* fe) +{ + int channel_range = IS_T1_FEMEDIA(fe) ? + NUM_OF_T1_CHANNELS : NUM_OF_E1_TIMESLOTS; + static char channels[100]; + int i = 0; + + channels[0] = '\0'; + if (WAN_TE1_ACTIVE_CH(fe) == ENABLE_ALL_CHANNELS){ + memcpy(channels, "All channels", strlen("All channels")); + }else{ + int start_channel = 0, first = 1; + + for(i = 1; i <= channel_range; i++){ + if (WAN_TE1_ACTIVE_CH(fe) & (1 << (i - 1))){ + if (!start_channel){ + start_channel = i; + } + }else{ + if (start_channel){ + if (start_channel + 1 == i){ + if (!first){ + sprintf(&channels[strlen(channels)], ",%d", + start_channel); + }else{ + sprintf(&channels[strlen(channels)], "%d", + start_channel); + } + }else{ + if (!first){ + sprintf(&channels[strlen(channels)], ",%d-%d", + start_channel, i-1); + }else{ + sprintf(&channels[strlen(channels)], "%d-%d", + start_channel, i-1); + } + } + first = 0; + start_channel = 0; + } + } + } + } + + return channels; +} + +/* + ****************************************************************************** + * sdla_channels() + * + * Description: Enable/Disable T1/E1 channels. + * Arguments: + * Returns: + ****************************************************************************** + */ +#if 0 +static void sdla_channels(sdla_fe_t* fe, unsigned long active_ch) +{ + sdla_fe_cfg_t* fe_cfg = &fe->fe_cfg; + int channel_range = + IS_T1_FEMEDIA(fe) ? + NUM_OF_T1_CHANNELS : NUM_OF_E1_TIMESLOTS; + int i = 0; + + for(i = 1; i <= channel_range; i++){ + if ((active_ch & (1 << (i - 1))) != + (WAN_TE1_ACTIVE_CH(fe) & (1 << (i - 1)))){ + if (active_ch & (1 << (i - 1))) { + /* Enable channel `i` */ + EnableTxChannel(fe, i); + EnableRxChannel(fe, i); + }else{ + /* Disable channel `i` */ + DisableTxChannel(fe, i); + DisableRxChannel(fe, i); + } + } + } + return; +} +#endif + +/* + ****************************************************************************** + * ReadAlarmStatus() + * + * Description: Read Alram Status for T1/E1 modes. + * Arguments: + * Returns: bit 0 - ALOS (E1/T1) + * bit 1 - LOS (E1/T1) + * bit 2 - ALTLOS (E1/T1) + * bit 3 - OOF (E1/T1) + * bit 4 - RED (E1/T1) + * bit 5 - AIS (E1/T1) + * bit 6 - OOSMF (E1) + * bit 7 - OOCMF (E1) + * bit 8 - OOOF (E1) + * bit 9 - RAI (E1) + * bit A - YEL (T1) + ****************************************************************************** + */ +static unsigned int sdla_te_read_alarms(sdla_fe_t *fe, int action) +{ + + WAN_ASSERT(fe->write_fe_reg == NULL); + WAN_ASSERT(fe->read_fe_reg == NULL); + + if (IS_FE_ALARM_READ(action)){ + + unsigned long status = 0x00; + unsigned char value = 0x00; + + /* Check common alarm for E1 and T1 configuration + ** 1. ALOS alarm + ** Reg 0xFA + ** Reg 0xF8 (ALOSI = 1) */ + if (READ_REG(REG_RLPS_ALOS_DET_PER) && + (READ_REG(REG_RLPS_CFG_STATUS) & BIT_RLPS_CFG_STATUS_ALOSV)){ + status |= WAN_TE_BIT_ALOS_ALARM; + } + + /* 2. LOS alarm + ** Reg 0x12 */ + if (READ_REG(REG_CDRC_INT_STATUS) & BIT_CDRC_INT_STATUS_LOSV){ + status |= WAN_TE_BIT_LOS_ALARM; + } + + /* 3. ALTLOS alarm ?????????????????? + ** Reg 0x13 */ + if (READ_REG(REG_ALTLOS_STATUS) & BIT_ALTLOS_STATUS_ALTLOS){ + status |= WAN_TE_BIT_ALTLOS_ALARM; + } + + /* Check specific E1 and T1 alarms */ + if (IS_E1_FEMEDIA(fe)){ + /* 4. OOF alarm */ + if (READ_REG(REG_E1_FRMR_FR_STATUS) & BIT_E1_FRMR_FR_STATUS_OOFV){ + status |= WAN_TE_BIT_OOF_ALARM; + } + /* 5. OOSMF alarm */ + if (READ_REG(REG_E1_FRMR_FR_STATUS) & BIT_E1_FRMR_FR_STATUS_OOSMFV){ + status |= WAN_TE_BIT_OOSMF_ALARM; + } + /* 6. OOCMF alarm */ + if (READ_REG(REG_E1_FRMR_FR_STATUS) & BIT_E1_FRMR_FR_STATUS_OOCMFV){ + status |= WAN_TE_BIT_OOCMF_ALARM; + } + /* 7. OOOF alarm */ + if (READ_REG(REG_E1_FRMR_FR_STATUS) & BIT_E1_FRMR_FR_STATUS_OOOFV){ + status |= WAN_TE_BIT_OOOF_ALARM; + } + /* 8. RAI alarm */ + if (READ_REG(REG_E1_FRMR_MAINT_STATUS) & BIT_E1_FRMR_MAINT_STATUS_RAIV){ + status |= WAN_TE_BIT_RAI_ALARM; + } + /* 9. RED alarm + ** Reg 0x97 (REDD) */ + if (READ_REG(REG_E1_FRMR_MAINT_STATUS) & BIT_E1_FRMR_MAINT_STATUS_RED){ + status |= WAN_TE_BIT_RED_ALARM; + } + /* 10. AIS alarm + ** Reg 0x91 (AISC) + ** Reg 0x97 (AIS) */ + if ((READ_REG(REG_E1_FRMR_MAINT_OPT) & BIT_E1_FRMR_MAINT_OPT_AISC) && + (READ_REG(REG_E1_FRMR_MAINT_STATUS) & BIT_E1_FRMR_MAINT_STATUS_AIS)){ + status |= WAN_TE_BIT_AIS_ALARM; + } + } else { + /* 4. OOF alarm + ** Reg 0x4A (INFR=0 T1 mode) */ + if (!(READ_REG(REG_T1_FRMR_INT_STATUS) & BIT_T1_FRMR_INT_STATUS_INFR)){ + status |= WAN_TE_BIT_OOF_ALARM; + } + value = READ_REG(REG_T1_ALMI_DET_STATUS); + + /* 5. AIS alarm + ** Reg 0x62 (AIS) + ** Reg 0x63 (AISD) */ + if (value & BIT_T1_ALMI_DET_STATUS_AISD){ + status |= WAN_TE_BIT_AIS_ALARM; + } + /* 6. RED alarm + ** Reg 0x63 (REDD) */ + if (value & BIT_T1_ALMI_DET_STATUS_REDD){ + status |= WAN_TE_BIT_RED_ALARM; + } + /* 7. YEL alarm + ** Reg 0x62 (YEL) + ** Reg 0x63 (YELD) */ + if (value & BIT_T1_ALMI_DET_STATUS_YELD){ + status |= WAN_TE_BIT_YEL_ALARM; + } + } + fe->fe_alarm = status; + } + + if (IS_FE_ALARM_PRINT(action)){ + sdla_te_print_alarms(fe, fe->fe_alarm); + } + return fe->fe_alarm; +} + +/* +******************************************************************************* +** sdla_te_alaram_print() +** +** Description: +** Arguments: +** Returns: +*/ +static int sdla_te_print_alarms(sdla_fe_t* fe, unsigned int alarms) +{ + if (!alarms){ + alarms = fe->fe_alarm; + } + + if (!alarms){ + DEBUG_EVENT("%s: %s Alarms status: No alarms detected!\n", + fe->name, + FE_MEDIA_DECODE(fe)); + return 0; + } + DEBUG_EVENT("%s: %s Alarms status:\n", + fe->name, + FE_MEDIA_DECODE(fe)); + + if (alarms & WAN_TE_BIT_ALOS_ALARM){ + DEBUG_EVENT("%s: ALOS alarm is ON\n", fe->name); + } + if (alarms & WAN_TE_BIT_LOS_ALARM){ + DEBUG_EVENT("%s: LOS alarm is ON\n", fe->name); + } + if (alarms & WAN_TE_BIT_ALTLOS_ALARM){ + DEBUG_EVENT("%s: ATLLOS alarm is ON\n", fe->name); + } + if (alarms & WAN_TE_BIT_OOF_ALARM){ + DEBUG_EVENT("%s: OOF alarm is ON\n", fe->name); + } + if (alarms & WAN_TE_BIT_RAI_ALARM){ + DEBUG_EVENT("%s: RAI alarm is ON\n", fe->name); + } + if (alarms & WAN_TE_BIT_RED_ALARM){ + DEBUG_EVENT("%s: RED alarm is ON\n", fe->name); + } + if (alarms & WAN_TE_BIT_AIS_ALARM){ + DEBUG_EVENT("%s: AIS alarm is ON\n", fe->name); + } + if (alarms & WAN_TE_BIT_YEL_ALARM){ + DEBUG_EVENT("%s: YEL alarm is ON\n", fe->name); + } + return 0; +} + +/* +******************************************************************************* +** sdla_te_set_alarms() +** +** Description: +** Arguments: +** Returns: +*/ +static int sdla_te_set_alarms(sdla_fe_t* fe, unsigned int alarms) +{ + unsigned char value = 0x00; + + if (alarms & WAN_TE_BIT_YEL_ALARM){ + if (IS_T1_FEMEDIA(fe)){ + value = READ_REG(REG_T1_XBAS_ALARM_TX); + if (!(value & BIT_T1_XBAS_ALARM_TX_XYEL)){ + value |= BIT_T1_XBAS_ALARM_TX_XYEL; + DEBUG_EVENT("%s: Setting YELLOW alarm!\n", + fe->name); + WRITE_REG(REG_T1_XBAS_ALARM_TX, value); + } + } + } + return 0; +} + +/* +******************************************************************************* +** sdla_te_clear_alarms() +** +** Description: +** Arguments: +** Returns: +*/ +static int sdla_te_clear_alarms(sdla_fe_t* fe, unsigned long alarms) +{ + unsigned char value = 0x00; + + if (alarms & WAN_TE_BIT_YEL_ALARM){ + if (IS_T1_FEMEDIA(fe)){ + value = READ_REG(REG_T1_XBAS_ALARM_TX); + if (value & BIT_T1_XBAS_ALARM_TX_XYEL){ + value &= ~BIT_T1_XBAS_ALARM_TX_XYEL; + DEBUG_EVENT("%s: Clearing YELLOW alarm!\n", + fe->name); + WRITE_REG(REG_T1_XBAS_ALARM_TX, value); + } + } + } + return 0; +} + +/* + ****************************************************************************** + * sdla_te_pmon() + * + * Description: Read PMC performance monitoring counters + * Arguments: + * Returns: + ****************************************************************************** + */ +#define PMON_DEF_NUM 0x1FFF +static int sdla_te_pmon(sdla_fe_t *fe, int action) +{ + sdla_te_pmon_t *pmon = &fe->fe_stats.u.te_pmon; + u16 pmon1, pmon2, pmon3, pmon4; + + WAN_ASSERT(fe->write_fe_reg == NULL); + WAN_ASSERT(fe->read_fe_reg == NULL); + /* Update PMON counters */ + WRITE_REG(REG_PMON_BIT_ERROR, 0x00); + + pmon->mask = 0x00; + /* Framing bit for E1/T1 */ + pmon1 = READ_REG(REG_PMON_BIT_ERROR) & BITS_PMON_BIT_ERROR; + /* OOF Error for T1 or Far End Block Error for E1 */ + pmon2 = ((READ_REG(REG_PMON_OOF_FEB_MSB_ERROR) & BITS_PMON_OOF_FEB_MSB_ERROR) << 8) | + READ_REG(REG_PMON_OOF_FEB_LSB_ERROR); + /* Bit Error for T1 or CRC Error for E1 */ + pmon3 = ((READ_REG(REG_PMON_BIT_CRC_MSB_ERROR) & BITS_PMON_BIT_CRC_MSB_ERROR) << 8) | + READ_REG(REG_PMON_BIT_CRC_LSB_ERROR); + /* LCV Error for E1/T1 */ + pmon4 = ((READ_REG(REG_PMON_LCV_MSB_COUNT) & BITS_PMON_LCV_MSB_COUNT) << 8) | + READ_REG(REG_PMON_LCV_LSB_COUNT); + + pmon->mask |= WAN_TE_BIT_PMON_LCV; + if (pmon4 != PMON_DEF_NUM){ + pmon->lcv_errors += pmon4; + } + if (IS_T1_FEMEDIA(fe)){ + pmon->mask |= WAN_TE_BIT_PMON_FER; + pmon->fer_errors += pmon1; + pmon->mask |= WAN_TE_BIT_PMON_OOF; + pmon->oof_errors += pmon2; + pmon->mask |= WAN_TE_BIT_PMON_BEE; + pmon->bee_errors += pmon3; + + }else{ + pmon->mask |= WAN_TE_BIT_PMON_FAS; + pmon->fas_errors += pmon1; + pmon->mask |= WAN_TE_BIT_PMON_FEB; + pmon->feb_errors += pmon2; + pmon->mask |= WAN_TE_BIT_PMON_CRC4; + pmon->crc4_errors += pmon3; + } + return 0; +} + +/* + ****************************************************************************** + * sdla_fe_flush_pmon() + * + * Description: Flush PMC performance monitoring counters + * Arguments: + * Returns: + ****************************************************************************** + */ +static int sdla_te_flush_pmon(sdla_fe_t *fe) +{ + fe->fe_stats.u.te_pmon.lcv_errors = 0; + fe->fe_stats.u.te_pmon.fer_errors = 0; + fe->fe_stats.u.te_pmon.oof_errors = 0; + fe->fe_stats.u.te_pmon.bee_errors = 0; + fe->fe_stats.u.te_pmon.fas_errors = 0; + fe->fe_stats.u.te_pmon.feb_errors = 0; + fe->fe_stats.u.te_pmon.crc4_errors = 0; + return 0; +} + +/* + ****************************************************************************** + * SetLoopBackChannel() + * + * Description: + * Arguments: + * Returns: + ****************************************************************************** + */ +static int SetLoopBackChannel(sdla_fe_t* fe, int channel, unsigned char mode) +{ + /* Set IND bit to 1 in TPSC to enable indirect access to TPSC register */ + WRITE_REG(REG_TPSC_CFG, BIT_TPSC_IND); + + /* Set LOOP to 1 for an IDLE code byte (the transmit data is overwritten + * with the corresponding channel data from the receive line. + */ + if (mode == LINELB_ACTIVATE_CODE){ + WRITE_TPSC_REG(REG_TPSC_DATA_CTRL_BYTE, channel, + ((READ_TPSC_REG(REG_TPSC_DATA_CTRL_BYTE, channel) & MASK_TPSC_DATA_CTRL_BYTE) | + BIT_TPSC_DATA_CTRL_BYTE_LOOP)); + }else{ + WRITE_TPSC_REG(REG_TPSC_DATA_CTRL_BYTE, channel, + ((READ_TPSC_REG(REG_TPSC_DATA_CTRL_BYTE, channel) & MASK_TPSC_DATA_CTRL_BYTE) & + ~BIT_TPSC_DATA_CTRL_BYTE_LOOP)); + } + + /* Set PCCE bit to 1 in TPSC to enable modifing the TPSC register */ + WRITE_REG(REG_TPSC_CFG, + ((READ_REG(REG_TPSC_CFG) & MASK_TPSC_CFG) | BIT_TPSC_PCCE)); + + return WAN_TRUE; +} + +/* + ****************************************************************************** + * sdla_te_intr() + * + * Description: Check interrupt type. + * Arguments: card - pointer to device structure. + * write_register - write register function. + * read_register - read register function. + * Returns: None. + ****************************************************************************** + */ +static int sdla_te_check_intr(sdla_fe_t *fe) +{ + unsigned char val; + + WAN_ASSERT(fe->write_fe_reg == NULL); + WAN_ASSERT(fe->read_fe_reg == NULL); + + if (!wan_test_bit(TE_CONFIGURED,(void*)&fe->te_param.critical)){ + return 0; + } + + if (fe->fe_chip_id == CHIP_ID_COMET_QUAD){ + val = READ_REG_LINE(0, REG_COMET_QUAD_MASTER_INTR); + val &= BITS_COMET_QUAD_MASTER_INTR; + if (!(val & (1 << WAN_FE_LINENO(fe)))){ + DEBUG_TEST("%s: This interrupt not for this port %d\n", + fe->name, + WAN_FE_LINENO(fe)+1); + return 0; + } + } + + return 1; +} + +static int sdla_te_intr(sdla_fe_t *fe) +{ + unsigned char status = fe->fe_status; + unsigned char val; + + WAN_ASSERT(fe->write_fe_reg == NULL); + WAN_ASSERT(fe->read_fe_reg == NULL); + + if (fe->fe_chip_id == CHIP_ID_COMET_QUAD){ + val = READ_REG_LINE(0, REG_COMET_QUAD_MASTER_INTR); + val &= BITS_COMET_QUAD_MASTER_INTR; + if (!(val & (1 << WAN_FE_LINENO(fe)))){ + DEBUG_TEST("%s: This interrupt not for this port %d\n", + fe->name, + WAN_FE_LINENO(fe)+1); + return 0; + } + } + + fe->te_param.intr_src1 = READ_REG(REG_INT_SRC_1); + fe->te_param.intr_src2 = READ_REG(REG_INT_SRC_2); + fe->te_param.intr_src3 = READ_REG(REG_INT_SRC_3); + DEBUG_ISR("%s: %s: INTR SRC1=0x%X SRC2=0x%X SRC3=0x%X\n", + __FUNCTION__, + fe->name, + fe->te_param.intr_src1, + fe->te_param.intr_src2, + fe->te_param.intr_src3); + if (fe->te_param.intr_src1 == 0 && + fe->te_param.intr_src2 == 0 && + fe->te_param.intr_src3 == 0){ + DEBUG_ISR("%s: Unknown %s interrupt!\n", + fe->name, + FE_MEDIA_DECODE(fe)); + return 0; + } + + sdla_te_tx_intr(fe); + sdla_te_rx_intr(fe); + + DEBUG_TEST("%s: FE Interrupt Alarms=0x%lX\n", + fe->name,fe->fe_alarm); + + sdla_te_set_status(fe, fe->fe_alarm); + if (status != fe->fe_status){ + if (fe->fe_status == FE_DISCONNECTED){ + /* AL: March 1, 2006: Disable FE intr */ + sdla_te_clear_intr(fe); + /* Start T1/E1 timer (5 sec) */ + sdla_te_enable_timer(fe, TE_LINKDOWN_TIMER, POLLING_TE1_TIMER * 5); + } + } + +#if 0 + /*NCDEBUG*/ + if (fe->fe_status==FE_CONNECTED){ + /* Interrupt may not work for all alarms. Thus + * as soon as we have an interrupt we should + * do a poll just in case */ + /*NCDEBUG*/ + DEBUG_EVENT("%s: FE Interrupt triggering poll!\n",fe->name); + sdla_te_enable_timer(fe, TE_LINKDOWN_TIMER, POLLING_TE1_TIMER); + } +#endif + return 0; +} + +/* + ****************************************************************************** + * sdla_te_tx_intr() + * + * Description: Read tx interrupt. + * Arguments: card - pointer to device structure. + * write_register - write register function. + * read_register - read register function. + * Returns: None. + ****************************************************************************** + */ +static void sdla_te_tx_intr(sdla_fe_t* fe) +{ + + if (!(fe->te_param.intr_src1 & BITS_TX_INT_SRC_1 || + fe->te_param.intr_src2 & BITS_TX_INT_SRC_2 || + fe->te_param.intr_src3 & BITS_TX_INT_SRC_3)){ + return; + } + +#if 0 + if (fe->te_param.intr_src1 & BIT_INT_SRC_1_TJAT){ + } + if (fe->te_param.intr_src1 & BIT_INT_SRC_1_APRM){ + } + if (fe->te_param.intr_src2 & BIT_INT_SRC_2_TX_ELST){ + } + if (fe->te_param.intr_src2 & BIT_INT_SRC_2_TDPR_1){ + } + if (fe->te_param.intr_src2 & BIT_INT_SRC_2_TDPR_2){ + } + if (fe->te_param.intr_src2 & BIT_INT_SRC_2_TDPR_3){ + } + if (fe->te_param.intr_src3 & BIT_INT_SRC_3_TRAN){ + } + if (fe->te_param.intr_src3 & BIT_INT_SRC_3_XPDE){ + } + if (fe->te_param.intr_src3 & BIT_INT_SRC_3_BTIF){ + } +#endif + return; +} + + +/* + ****************************************************************************** + * sdla_te_rx_intr() + * + * Description: Read rx interrupt. + * Arguments: card - pointer to device structure. + * write_register - write register function. + * read_register - read register function. + * Returns: None. + ****************************************************************************** + */ +static void sdla_te_rx_intr(sdla_fe_t* fe) +{ + if (IS_T1_FEMEDIA(fe)){ + sdla_t1_rx_intr(fe); + }else{ + sdla_e1_rx_intr(fe); + } + return; +} + +/* + ****************************************************************************** + * sdla_t1_rx_intr() + * + * Description: Read tx interrupt. + * Arguments: card - pointer to device structure. + * write_register - write register function. + * read_register - read register function. + * Returns: None. + ****************************************************************************** + */ +static void sdla_t1_rx_intr(sdla_fe_t* fe) +{ + unsigned char status = 0x00; + + if (!(fe->te_param.intr_src1 & BITS_RX_INT_SRC_1 || + fe->te_param.intr_src2 & BITS_RX_INT_SRC_2 || + fe->te_param.intr_src3 & BITS_RX_INT_SRC_3)){ + return; + } + + /* 3. PDVD */ + if (fe->te_param.intr_src3 & BIT_INT_SRC_3_PDVD){ + status = READ_REG(REG_PDVD_INT_EN_STATUS); + if ((status & BIT_PDVD_INT_EN_STATUS_PDVE) && + (status & BIT_PDVD_INT_EN_STATUS_PDVI)){ + if (status & BIT_PDVD_INT_EN_STATUS_PDV){ + DEBUG_EVENT("%s: T1 pulse density violation detected!\n", + fe->name); + } + } + if ((status & BIT_PDVD_INT_EN_STATUS_Z16DE) && + (status & BIT_PDVD_INT_EN_STATUS_Z16DI)){ + DEBUG_EVENT("%s: T1 16 consecutive zeros detected!\n", + fe->name); + } + } + + /* 6. ALMI */ + if (fe->te_param.intr_src3 & BIT_INT_SRC_3_ALMI){ + status = READ_REG(REG_T1_ALMI_INT_STATUS); + if (status & BIT_T1_ALMI_INT_STATUS_YELI){ + if (status & BIT_T1_ALMI_INT_STATUS_YEL){ + if (!(fe->fe_alarm & WAN_TE_BIT_YEL_ALARM)){ +#if 0 +Alex Sep 16 + DEBUG_EVENT("%s: T1 YELLOW alarm is ON\n", + fe->name); + fe->fe_alarm |= WAN_TE_BIT_YEL_ALARM; +#endif + } + }else{ + if (fe->fe_alarm & WAN_TE_BIT_YEL_ALARM){ +#if 0 +Alex Sep 16 + DEBUG_EVENT("%s: T1 YELLOW alarm is OFF\n", + fe->name); + fe->fe_alarm &= ~WAN_TE_BIT_YEL_ALARM; +#endif + } + } + } + if (status & BIT_T1_ALMI_INT_STATUS_REDI){ + if (status & BIT_T1_ALMI_INT_STATUS_RED){ + if (!(fe->fe_alarm & WAN_TE_BIT_RED_ALARM)){ + DEBUG_EVENT("%s: T1 RED alarm is ON\n", + fe->name); + fe->fe_alarm |= WAN_TE_BIT_RED_ALARM; + } + }else{ + if (fe->fe_alarm & WAN_TE_BIT_RED_ALARM){ + DEBUG_EVENT("%s: T1 RED alarm is OFF\n", + fe->name); + fe->fe_alarm &= ~WAN_TE_BIT_RED_ALARM; + } + } + } + if (status & BIT_T1_ALMI_INT_STATUS_AISI){ + if (status & BIT_T1_ALMI_INT_STATUS_AIS){ + if (!(fe->fe_alarm & WAN_TE_BIT_AIS_ALARM)){ + DEBUG_EVENT("%s: T1 Alarm Indication Signal is ON\n", + fe->name); + fe->fe_alarm |= WAN_TE_BIT_AIS_ALARM; + } + }else{ + if (fe->fe_alarm & WAN_TE_BIT_AIS_ALARM){ + DEBUG_EVENT("%s: T1 Alarm Indication Signal is OFF\n", + fe->name); + fe->fe_alarm &= ~WAN_TE_BIT_AIS_ALARM; + } + } + } + +#if 0 + if (status & + (BIT_T1_ALMI_INT_STATUS_YELI | + BIT_T1_ALMI_INT_STATUS_REDI | + BIT_T1_ALMI_INT_STATUS_AISI)){ + if (status & (BIT_T1_ALMI_INT_STATUS_YEL | + BIT_T1_ALMI_INT_STATUS_RED | + BIT_T1_ALMI_INT_STATUS_AIS)){ + + /* Update T1/E1 alarm status */ + if (!(fe->fe_alarm & WAN_TE_BIT_YEL_ALARM) && + (status & BIT_T1_ALMI_INT_STATUS_YEL)){ + DEBUG_EVENT("%s: T1 YELLOW alarm is ON\n", + fe->name); + fe->fe_alarm |= WAN_TE_BIT_YEL_ALARM; + } + if (!(fe->fe_alarm & WAN_TE_BIT_RED_ALARM) && + (status & BIT_T1_ALMI_INT_STATUS_RED)){ + DEBUG_EVENT("%s: T1 RED alarm is ON\n", + fe->name); + fe->fe_alarm |= WAN_TE_BIT_RED_ALARM; + } + if (!(fe->fe_alarm & WAN_TE_BIT_AIS_ALARM) && + (status & BIT_T1_ALMI_INT_STATUS_AIS)){ + DEBUG_EVENT("%s: T1 Alarm Indication Signal is ON\n", + fe->name); + fe->fe_alarm |= WAN_TE_BIT_AIS_ALARM; + } + }else{ + /* Update T1/E1 alarm status */ + if ((fe->fe_alarm & WAN_TE_BIT_YEL_ALARM) && + !(status & BIT_T1_ALMI_INT_STATUS_YEL)){ + DEBUG_EVENT("%s: T1 YELLOW alarm is OFF\n", + fe->name); + fe->fe_alarm &= ~WAN_TE_BIT_YEL_ALARM; + } + if ((fe->fe_alarm & WAN_TE_BIT_RED_ALARM) && + !(status & BIT_T1_ALMI_INT_STATUS_RED)){ + DEBUG_EVENT("%s: T1 RED alarm is OFF\n", + fe->name); + fe->fe_alarm &= ~WAN_TE_BIT_RED_ALARM; + } + if ((fe->fe_alarm & WAN_TE_BIT_AIS_ALARM) && + !(status & BIT_T1_ALMI_INT_STATUS_AIS)){ + DEBUG_EVENT("%s: T1 Alarm Indication Signal is OFF\n", + fe->name); + fe->fe_alarm &= ~WAN_TE_BIT_AIS_ALARM; + } + } + } +#endif + } + + /* 8. RBOC */ + if (fe->te_param.intr_src3 & BIT_INT_SRC_3_RBOC){ + status = READ_REG(REG_T1_RBOC_CODE_STATUS); + if (status & BIT_T1_RBOC_CODE_STATUS_BOCI){ + unsigned long time; + wan_getcurrenttime(&time, NULL); + time = time / 1000; + status &= MASK_T1_RBOC_CODE_STATUS; + switch(status){ + case LINELB_ACTIVATE_CODE: + case LINELB_DEACTIVATE_CODE: + if (wan_test_bit(LINELB_WAITING,(void*)&fe->te_param.critical) && + wan_test_bit(LINELB_CODE_BIT,(void*)&fe->te_param.critical)){ + wan_clear_bit(LINELB_CODE_BIT,(void*)&fe->te_param.critical); + break; + } + + DEBUG_TE1("%s: T1 loopback %s code received.\n", + fe->name, + (status==LINELB_ACTIVATE_CODE)? + "activation" : "deactivation"); + fe->te_param.lb_cmd = status; + fe->te_param.lb_time = time; + break; + + case LINELB_DS1LINE_ALL: + if (wan_test_bit(LINELB_WAITING,(void*)&fe->te_param.critical) && + wan_test_bit(LINELB_CHANNEL_BIT,(void*)&fe->te_param.critical)){ + wan_clear_bit(LINELB_CHANNEL_BIT,(void*)&fe->te_param.critical); + wan_clear_bit(LINELB_WAITING,(void*)&fe->te_param.critical); + break; + } + if (!fe->te_param.lb_cmd) + break; + if ((time - fe->te_param.lb_time) < LINELB_TE1_TIMER){ + DEBUG_TE1("%s: T1 loopback %s mode cancelled!\n", + fe->name, + (fe->te_param.lb_cmd == LINELB_ACTIVATE_CODE) ? + "activatation" : + "deactivation"); + }else{ + if (fe->te_param.lb_cmd == LINELB_ACTIVATE_CODE){ + DEBUG_EVENT("%s: T1 loopback mode activated.\n", + fe->name); + WRITE_REG(REG_MASTER_DIAG, + READ_REG(REG_MASTER_DIAG) | + BIT_MASTER_DIAG_LINELB); + }else{ + DEBUG_EVENT("%s: T1 loopback mode deactivated.\n", + fe->name); + WRITE_REG(REG_MASTER_DIAG, + READ_REG(REG_MASTER_DIAG) & + ~BIT_MASTER_DIAG_LINELB); + } + } + fe->te_param.lb_cmd = 0x00; + fe->te_param.lb_time = 0x00; + break; + + case LINELB_DS3LINE: + break; + + case LINELB_DS1LINE_1: + case LINELB_DS1LINE_2: + case LINELB_DS1LINE_3: + case LINELB_DS1LINE_4: + case LINELB_DS1LINE_5: + case LINELB_DS1LINE_6: + case LINELB_DS1LINE_7: + case LINELB_DS1LINE_8: + case LINELB_DS1LINE_9: + case LINELB_DS1LINE_10: + case LINELB_DS1LINE_11: + case LINELB_DS1LINE_12: + case LINELB_DS1LINE_13: + case LINELB_DS1LINE_14: + case LINELB_DS1LINE_15: + case LINELB_DS1LINE_16: + case LINELB_DS1LINE_17: + case LINELB_DS1LINE_18: + case LINELB_DS1LINE_19: + case LINELB_DS1LINE_20: + case LINELB_DS1LINE_21: + case LINELB_DS1LINE_22: + case LINELB_DS1LINE_23: + case LINELB_DS1LINE_24: + case LINELB_DS1LINE_25: + case LINELB_DS1LINE_26: + case LINELB_DS1LINE_27: + case LINELB_DS1LINE_28: + if (!fe->te_param.lb_cmd) + break; + if ((time - fe->te_param.lb_time) < LINELB_TE1_TIMER){ + DEBUG_TE1("%s: T1 loopback %s mode cancelled!\n", + fe->name, + (fe->te_param.lb_cmd == LINELB_ACTIVATE_CODE) ? + "activatation" : + "deactivation"); + }else{ + int channel = status & LINELB_DS1LINE_MASK; + DEBUG_EVENT("%s: T1 loopback mode %s on channel %d.\n", + fe->name, + (fe->te_param.lb_cmd == LINELB_ACTIVATE_CODE) ? "activated" : "deactivated", + channel); + SetLoopBackChannel(fe, channel, fe->te_param.lb_cmd); + } + fe->te_param.lb_cmd = 0x00; + fe->te_param.lb_time = 0x00; + break; + + default: + DEBUG_TE1("%s: Unknown signal (0x%02x).\n", + fe->name, status); + break; + } + } + } + + /* 7. FRMR */ + if (fe->te_param.intr_src1 & BIT_INT_SRC_1_FRMR){ + status = READ_REG(REG_T1_FRMR_INT_STATUS); + if ((READ_REG(REG_T1_FRMR_INT_EN) & BIT_T1_FRMR_INT_EN_INFRE) && + (status & BIT_T1_FRMR_INT_STATUS_INFRI)){ + if (status & BIT_T1_FRMR_INT_STATUS_INFR){ + if (!(fe->fe_alarm & WAN_TE_BIT_OOF_ALARM)){ + DEBUG_EVENT("%s: T1 Out of Frame alarm is ON!\n", + fe->name); + fe->fe_alarm |= WAN_TE_BIT_OOF_ALARM; + } + }else{ + if (fe->fe_alarm & WAN_TE_BIT_OOF_ALARM){ + DEBUG_EVENT("%s: T1 Out of Frame alarm is OFF!\n", + fe->name); + fe->fe_alarm &= ~WAN_TE_BIT_OOF_ALARM; + } + } + } + } + + /* 1. RLPS */ + if (fe->te_param.intr_src3 & BIT_INT_SRC_3_RLPS){ + status = READ_REG(REG_RLPS_CFG_STATUS); + if ((status & BIT_RLPS_CFG_STATUS_ALOSE) && (status & BIT_RLPS_CFG_STATUS_ALOSI)){ + if (status & BIT_RLPS_CFG_STATUS_ALOSV){ + if (!(fe->fe_alarm & WAN_TE_BIT_ALOS_ALARM)){ + if (WAN_NET_RATELIMIT()){ + DEBUG_EVENT("%s: T1 ALOS alarm is ON\n", + fe->name); + } + fe->fe_alarm |= WAN_TE_BIT_ALOS_ALARM; + } + }else{ + if (fe->fe_alarm & WAN_TE_BIT_ALOS_ALARM){ + if (WAN_NET_RATELIMIT()){ + DEBUG_EVENT("%s: T1 ALOS alarm is OFF\n", + fe->name); + } + fe->fe_alarm &= ~WAN_TE_BIT_ALOS_ALARM; + } + } + } + } + + /* 2. CDRC */ + if (fe->te_param.intr_src1 & BIT_INT_SRC_1_CDRC){ + status = READ_REG(REG_CDRC_INT_STATUS); + if ((READ_REG(REG_CDRC_INT_EN) & BIT_CDRC_INT_EN_LOSE) && + (status & BIT_CDRC_INT_STATUS_LOSI)){ + if (status & BIT_CDRC_INT_STATUS_LOSV){ + if (!(fe->fe_alarm & WAN_TE_BIT_LOS_ALARM)){ + if (WAN_NET_RATELIMIT()){ + DEBUG_EVENT("%s: T1 LOS alarm is ON\n", + fe->name); + } + fe->fe_alarm |= WAN_TE_BIT_LOS_ALARM; + } + }else{ + if (fe->fe_alarm & WAN_TE_BIT_LOS_ALARM){ + if (WAN_NET_RATELIMIT()){ + DEBUG_EVENT("%s: T1 LOS alarm is OFF\n", + fe->name); + } + fe->fe_alarm &= ~WAN_TE_BIT_LOS_ALARM; + } + } + } + if ((READ_REG(REG_CDRC_INT_EN) & BIT_CDRC_INT_EN_LCVE) && + (status & BIT_CDRC_INT_STATUS_LCVI)){ + DEBUG_EVENT("%s: T1 line code violation!\n", + fe->name); + } + if ((READ_REG(REG_CDRC_INT_EN) & BIT_CDRC_INT_EN_LCSDE) && + (status & BIT_CDRC_INT_STATUS_LCSDI)){ + DEBUG_EVENT("%s: T1 line code signature detected!\n", + fe->name); + } + if ((READ_REG(REG_CDRC_INT_EN) & BIT_CDRC_INT_EN_ZNDE) && + (status & BIT_CDRC_INT_STATUS_ZNDI)){ + DEBUG_EVENT("%s: T1 consecutive zeros detected!\n", + fe->name); + } + status = READ_REG(REG_ALTLOS_STATUS); + if ((status & BIT_ALTLOS_STATUS_ALTLOSI) && (status & BIT_ALTLOS_STATUS_ALTLOSE)){ + if (status & BIT_ALTLOS_STATUS_ALTLOS){ + if (!(fe->fe_alarm & WAN_TE_BIT_ALTLOS_ALARM)){ + DEBUG_EVENT("%s: T1 Alternate Loss of Signal alarm is ON\n", + fe->name); + fe->fe_alarm |= WAN_TE_BIT_ALTLOS_ALARM; + } + }else{ + if (fe->fe_alarm & WAN_TE_BIT_ALTLOS_ALARM){ + DEBUG_EVENT("%s: T1 Alternate Loss of Signal alarm is OFF\n", + fe->name); + fe->fe_alarm &= ~WAN_TE_BIT_ALTLOS_ALARM; + } + } + } + } + + /* 14. PMON */ + if (fe->te_param.intr_src1 & BIT_INT_SRC_1_PMON){ + status = READ_REG(REG_PMON_INT_EN_STATUS); + if (status & BIT_PMON_INT_EN_STATUS_XFER){ + DEBUG_TE1("%s: T1 Updating PMON counters...\n", + fe->name); + sdla_te_pmon(fe, 0); + } + } + + /* 9. SIGX */ + if (fe->te_param.intr_src1 & BIT_INT_SRC_1_SIGX){ +#if 0 + unsigned char SIGX_chg_30_25; + unsigned char SIGX_chg_24_17; + unsigned char SIGX_chg_16_9; + unsigned char SIGX_chg_8_1; + + SIGX_chg_30_25 = READ_REG(REG_SIGX_CFG); + SIGX_chg_24_17 = READ_REG(REG_SIGX_TIMESLOT_IND_STATUS); + SIGX_chg_16_9 = READ_REG(REG_SIGX_TIMESLOT_IND_ACCESS); + SIGX_chg_8_1 = READ_REG(REG_SIGX_TIMESLOT_IND_DATA_BUFFER); + +#if 0 + if(IS_E1_FEMEDIA(fe)) { + DEBUG_EVENT("%s: SIGX chg 30-25: 0x%02X\n", + fe->name, SIGX_chg_30_25); + } + DEBUG_EVENT("%s: SIGX chg 24-17: 0x%02X\n", + fe->name, SIGX_chg_24_17); + DEBUG_EVENT("%s: SIGX chg 16-9 : 0x%02X\n", + fe->name, SIGX_chg_16_9); + DEBUG_EVENT("%s: SIGX chg 8-1 : 0x%02X\n", + fe->name, SIGX_chg_8_1); +#endif + + if (SIGX_chg_8_1){ + sdla_te_check_rbsbits(fe, SIGX_chg_8_1, 1, 1); + /* status = READ_SIGX_REG(0x10);*/ + /* printk(KERN_INFO "SIGX reg 0x10: 0x%02X\n", status);*/ + } + + if (SIGX_chg_16_9){ + sdla_te_check_rbsbits(fe, SIGX_chg_16_9, 9, 1); + } + + if (SIGX_chg_24_17){ + sdla_te_check_rbsbits(fe, SIGX_chg_24_17, 17, 1); + } + + if (SIGX_chg_30_25 && IS_E1_FEMEDIA(fe)){ + sdla_te_check_rbsbits(fe, SIGX_chg_30_25, 25, 1); + } +#endif + sdla_te_check_rbsbits(fe, 1, ENABLE_ALL_CHANNELS, 1); + sdla_te_check_rbsbits(fe, 9, ENABLE_ALL_CHANNELS, 1); + sdla_te_check_rbsbits(fe, 17, ENABLE_ALL_CHANNELS, 1); + if (IS_E1_FEMEDIA(fe)){ + sdla_te_check_rbsbits(fe, 25, ENABLE_ALL_CHANNELS, 1); + } + } + + /* 5. IBCD */ + fe->fe_alarm &= ~(WAN_TE_BIT_LOOPUP_CODE|WAN_TE_BIT_LOOPDOWN_CODE); + if (fe->te_param.intr_src3 & BIT_INT_SRC_3_IBCD){ + status = READ_REG(REG_IBCD_INT_EN_STATUS); + if (status & BIT_IBCD_INT_EN_STATUS_LBAI){ + fe->fe_alarm |= WAN_TE_BIT_LOOPUP_CODE; + } + if (status & BIT_IBCD_INT_EN_STATUS_LBDI){ + fe->fe_alarm |= WAN_TE_BIT_LOOPDOWN_CODE; + } + } +#if 0 + /* 4. RJAT */ + if (fe->te_param.intr_src1 & BIT_INT_SRC_1_RJAT){ + } + /* 10. RX-ELST */ + if (fe->te_param.intr_src2 & BIT_INT_SRC_2_RX_ELST){ + } + /* 11. RDLC-1 */ + if (fe->te_param.intr_src2 & BIT_INT_SRC_2_RDLC_1){ + } + /* 12. RDLC-2 */ + if (fe->te_param.intr_src2 & BIT_INT_SRC_2_RDLC_2){ + } + /* 13. RDLC-3 */ + if (fe->te_param.intr_src2 & BIT_INT_SRC_2_RDLC_3){ + } +#endif + + return; +} + + +/* + ****************************************************************************** + * sdla_e1_rx_intr() + * + * Description: Read tx interrupt. + * Arguments: card - pointer to device structure. + * write_register - write register function. + * read_register - read register function. + * Returns: None. + ****************************************************************************** + */ +static void sdla_e1_rx_intr(sdla_fe_t* fe) +{ + unsigned char int_status = 0x00, status = 0x00; + + if (!(fe->te_param.intr_src1 & BITS_RX_INT_SRC_1 || + fe->te_param.intr_src2 & BITS_RX_INT_SRC_2 || + fe->te_param.intr_src3 & BITS_RX_INT_SRC_3)) + return; + + /* 4. FRMR */ + if (fe->te_param.intr_src1 & BIT_INT_SRC_1_FRMR){ + /* Register 0x92h E1 FRMR Framing Status Interrupt Enable */ + unsigned char int_en = READ_REG(REG_E1_FRMR_FRM_STAT_INT_EN); + /* Register 0x94h E1 FRMR */ + int_status = READ_REG(REG_E1_FRMR_FRM_STAT_INT_IND); + /* Register 0x96h E1 FRMR Status */ + status = READ_REG(REG_E1_FRMR_FR_STATUS); + if ((int_en & BIT_E1_FRMR_FRM_STAT_INT_EN_OOFE) && + (int_status & BIT_E1_FRMR_FRM_STAT_INT_IND_OOFI)){ + if (status & BIT_E1_FRMR_FR_STATUS_OOFV){ + if (!(fe->fe_alarm & WAN_TE_BIT_OOF_ALARM)){ + DEBUG_EVENT("%s: E1 Out of Frame alarm is ON\n", + fe->name); + fe->fe_alarm |= WAN_TE_BIT_OOF_ALARM; + } + }else{ + if (fe->fe_alarm & WAN_TE_BIT_OOF_ALARM){ + DEBUG_EVENT("%s: E1 Out of Frame alarm is OFF\n", + fe->name); + fe->fe_alarm &= ~WAN_TE_BIT_OOF_ALARM; + } + } + } + + if ((int_en & BIT_E1_FRMR_FRM_STAT_INT_EN_OOSMFE) && + (int_status & BIT_E1_FRMR_FRM_STAT_INT_IND_OOSMFI)){ + if (status & BIT_E1_FRMR_FR_STATUS_OOSMFV){ + DEBUG_EVENT("%s: E1 Loss of Signaling multiframe alarm is ON\n", + fe->name); + fe->fe_alarm |= WAN_TE_BIT_OOSMF_ALARM; + }else{ + DEBUG_EVENT("%s: E1 Loss of Signaling multiframe alarm is OFF\n", + fe->name); + fe->fe_alarm &= ~WAN_TE_BIT_OOSMF_ALARM; + } + } + + if ((int_en & BIT_E1_FRMR_FRM_STAT_INT_EN_OOCMFE) && + (int_status & BIT_E1_FRMR_FRM_STAT_INT_IND_OOCMFI)){ + if (status & BIT_E1_FRMR_FR_STATUS_OOCMFV){ + DEBUG_EVENT("%s: E1 Loss of CRC multiframe alarm is ON\n", + fe->name); + fe->fe_alarm |= WAN_TE_BIT_OOCMF_ALARM; + }else{ + DEBUG_EVENT("%s: E1 Loss of CRC multiframe alarm is OFF\n", + fe->name); + fe->fe_alarm &= ~WAN_TE_BIT_OOCMF_ALARM; + } + } + + /* Register 0x9Fh E1 FRMR */ + status = READ_REG(REG_E1_FRMR_P_A_INT_STAT); + if ((READ_REG(REG_E1_FRMR_P_A_INT_EN) & BIT_E1_FRMR_P_A_INT_EN_OOOFE) && + (status & BIT_E1_FRMR_P_A_INT_STAT_OOOFI)){ + if (READ_REG(REG_E1_FRMR_FR_STATUS) & BIT_E1_FRMR_FR_STATUS_OOOFV){ + DEBUG_EVENT("%s: E1 out of offline frame alarm is ON\n", + fe->name); + fe->fe_alarm |= WAN_TE_BIT_OOOF_ALARM; + }else{ + DEBUG_EVENT("%s: E1 out of offline frame alarm is OFF\n", + fe->name); + fe->fe_alarm &= ~WAN_TE_BIT_OOOF_ALARM; + } + } + + /* Register 0x95h E1 FRMR */ + int_status = READ_REG(REG_E1_FRMR_M_A_INT_IND); + if (int_status & (BIT_E1_FRMR_M_A_INT_IND_REDI | + BIT_E1_FRMR_M_A_INT_IND_AISI | + BIT_E1_FRMR_M_A_INT_IND_RAII)){ + unsigned char int_en = READ_REG(REG_E1_FRMR_M_A_INT_EN); + status = READ_REG(REG_E1_FRMR_MAINT_STATUS); + if ((int_en & BIT_E1_FRMR_M_A_INT_EN_REDE) && + (int_status & BIT_E1_FRMR_M_A_INT_IND_REDI)){ + if (status & BIT_E1_FRMR_MAINT_STATUS_RED){ + DEBUG_EVENT("%s: E1 RED alarm is ON\n", fe->name); + fe->fe_alarm |= WAN_TE_BIT_RED_ALARM; + }else{ + DEBUG_EVENT("%s: E1 RED alarm is OFF\n", fe->name); + fe->fe_alarm &= ~WAN_TE_BIT_RED_ALARM; + } + } + if ((int_en & BIT_E1_FRMR_M_A_INT_EN_AISE) && + (int_status & BIT_E1_FRMR_M_A_INT_IND_AISI)){ + if (status & BIT_E1_FRMR_MAINT_STATUS_AIS){ + DEBUG_EVENT("%s: E1 AIS alarm is ON\n", fe->name); + fe->fe_alarm |= WAN_TE_BIT_AIS_ALARM; + /* AS/ACIF S016 Clause 5.2.3 */ + WRITE_REG(REG_E1_TRAN_TX_ALARM_CTRL, + READ_REG(REG_E1_TRAN_TX_ALARM_CTRL) | + BIT_E1_TRAN_TX_ALARM_RAI); + if (WAN_TE1_CLK(fe) == WAN_NORMAL_CLK){ + sdla_te_master_clock(fe); + } + }else{ + DEBUG_EVENT("%s: E1 AIS alarm is OFF\n", fe->name); + fe->fe_alarm &= ~WAN_TE_BIT_AIS_ALARM; + /* AS/ACIF S016 Clause 5.2.3 */ + WRITE_REG(REG_E1_TRAN_TX_ALARM_CTRL, + READ_REG(REG_E1_TRAN_TX_ALARM_CTRL) & + ~BIT_E1_TRAN_TX_ALARM_RAI); + if (WAN_TE1_CLK(fe) == WAN_NORMAL_CLK){ + sdla_te_normal_clock(fe); + } + } + } + if ((int_en & BIT_E1_FRMR_M_A_INT_EN_RAIE) && + (int_status & BIT_E1_FRMR_M_A_INT_IND_RAII)){ + if (status & BIT_E1_FRMR_MAINT_STATUS_RAIV){ + DEBUG_EVENT("%s: E1 RAI alarm is ON\n", fe->name); + fe->fe_alarm |= WAN_TE_BIT_RAI_ALARM; + }else{ + DEBUG_EVENT("%s: E1 RAI alarm is OFF\n", fe->name); + fe->fe_alarm &= ~WAN_TE_BIT_RAI_ALARM; + } + } + } + } + + /* 1. RLPS */ + if (fe->te_param.intr_src3 & BIT_INT_SRC_3_RLPS){ + status = READ_REG(REG_RLPS_CFG_STATUS); + if ((status & BIT_RLPS_CFG_STATUS_ALOSE) && + (status & BIT_RLPS_CFG_STATUS_ALOSI)){ + if (status & BIT_RLPS_CFG_STATUS_ALOSV){ + if (!(fe->fe_alarm & WAN_TE_BIT_ALOS_ALARM)){ + DEBUG_EVENT("%s: E1 ALOS alarm is ON\n", + fe->name); + fe->fe_alarm |= WAN_TE_BIT_ALOS_ALARM; + /* AS/ACIF S016 Clause 5.2.3 */ + WRITE_REG(REG_E1_TRAN_TX_ALARM_CTRL, + READ_REG(REG_E1_TRAN_TX_ALARM_CTRL) | + BIT_E1_TRAN_TX_ALARM_RAI); + } + }else{ + if (fe->fe_alarm & WAN_TE_BIT_ALOS_ALARM){ + DEBUG_EVENT("%s: E1 ALOS alarm is OFF\n", + fe->name); + fe->fe_alarm &= ~WAN_TE_BIT_ALOS_ALARM; + /* AS/ACIF S016 Clause 5.2.3 */ + WRITE_REG(REG_E1_TRAN_TX_ALARM_CTRL, + READ_REG(REG_E1_TRAN_TX_ALARM_CTRL) & + ~BIT_E1_TRAN_TX_ALARM_RAI); + } + } + } + } + + /* 2. CDRC */ + if (fe->te_param.intr_src1 & BIT_INT_SRC_1_CDRC){ + status = READ_REG(REG_CDRC_INT_STATUS); + if ((READ_REG(REG_CDRC_INT_EN) & BIT_CDRC_INT_EN_LOSE) && + (status & BIT_CDRC_INT_STATUS_LOSI)){ + if (status & BIT_CDRC_INT_STATUS_LOSV){ + if (!(fe->fe_alarm & WAN_TE_BIT_LOS_ALARM)){ + DEBUG_EVENT("%s: E1 LOS alarm is ON\n", fe->name); + fe->fe_alarm |= WAN_TE_BIT_LOS_ALARM; + } + }else{ + if (fe->fe_alarm & WAN_TE_BIT_LOS_ALARM){ + DEBUG_EVENT("%s: E1 LOS alarm is OFF\n", fe->name); + fe->fe_alarm &= ~WAN_TE_BIT_LOS_ALARM; + } + } + } + if ((READ_REG(REG_CDRC_INT_EN) & BIT_CDRC_INT_EN_LCVE) && + (status & BIT_CDRC_INT_STATUS_LCVI)){ + DEBUG_EVENT("%s: E1 line code violation!\n", fe->name); + } + if ((READ_REG(REG_CDRC_INT_EN) & BIT_CDRC_INT_EN_LCSDE) && + (status & BIT_CDRC_INT_STATUS_LCSDI)){ + DEBUG_EVENT("%s: E1 line code signature detected!\n", fe->name); + } + if ((READ_REG(REG_CDRC_INT_EN) & BIT_CDRC_INT_EN_ZNDE) && + (status & BIT_CDRC_INT_STATUS_ZNDI)){ + DEBUG_EVENT("%s: E1 consecutive zeros detected!\n", fe->name); + } + status = READ_REG(REG_ALTLOS_STATUS); + if ((status & BIT_ALTLOS_STATUS_ALTLOSI) && + (status & BIT_ALTLOS_STATUS_ALTLOSE)){ + if (status & BIT_ALTLOS_STATUS_ALTLOS){ + if (!(fe->fe_alarm & WAN_TE_BIT_ALTLOS_ALARM)){ + DEBUG_EVENT("%s: E1 Alternate Loss of Signal alarm is ON\n", + fe->name); + fe->fe_alarm |= WAN_TE_BIT_ALTLOS_ALARM; + } + }else{ + if (fe->fe_alarm & WAN_TE_BIT_ALTLOS_ALARM){ + DEBUG_EVENT("%s: E1 Alternate Loss of Signal alarm is OFF\n", + fe->name); + fe->fe_alarm &= ~WAN_TE_BIT_ALTLOS_ALARM; + } + } + } + } + /* 11. PMON */ + if (fe->te_param.intr_src1 & BIT_INT_SRC_1_PMON){ + status = READ_REG(REG_PMON_INT_EN_STATUS); + if (status & BIT_PMON_INT_EN_STATUS_XFER){ + sdla_te_pmon(fe, 0); + } + } +#if 0 + /* 3. RJAT */ + if (fe->te_param.intr_src1 & BIT_INT_SRC_1_RJAT){ + } + /* 5. SIGX */ + if (fe->te_param.intr_src1 & BIT_INT_SRC_1_SIGX){ + } + /* 6. RX-ELST */ + if (fe->te_param.intr_src2 & BIT_INT_SRC_2_RX_ELST){ + } + /* 7. PRGD */ + if (fe->te_param.intr_src1 & BIT_INT_SRC_1_PRGD){ + } + /* 8. RDLC-1 */ + if (fe->te_param.intr_src2 & BIT_INT_SRC_2_RDLC_1){ + } + /* 9. RDLC-2 */ + if (fe->te_param.intr_src2 & BIT_INT_SRC_2_RDLC_2){ + } + /* 10. RDLC-3 */ + if (fe->te_param.intr_src2 & BIT_INT_SRC_2_RDLC_3){ + } +#endif + if (!(READ_REG(REG_RLPS_CFG_STATUS) & BIT_RLPS_CFG_STATUS_ALOSV)){ + fe->fe_alarm &= ~WAN_TE_BIT_ALOS_ALARM; + } + return; +} + +/* + ****************************************************************************** + * sdla_te_set_lbmode() + * + * Description: + * Arguments: + * Returns: + ****************************************************************************** + */ +static int +sdla_te_set_lbmode(sdla_fe_t *fe, unsigned char type, unsigned char mode) +{ + int err = 1; + + WAN_ASSERT(fe->write_fe_reg == NULL); + WAN_ASSERT(fe->read_fe_reg == NULL); + switch(type){ + case WAN_TE1_LINELB_MODE: + err = sdla_te_linelb(fe, mode); + break; + case WAN_TE1_PAYLB_MODE: + err = sdla_te_paylb(fe, mode); + break; + case WAN_TE1_DDLB_MODE: + err = sdla_te_ddlb(fe, mode); + break; + case WAN_TE1_TX_LB_MODE: + err = sdla_te_lb(fe, mode); + break; + } + + return err; +} + +/* + ****************************************************************************** + * sdla_te_linelb() + * + * Description: + * Arguments: + * Returns: + ****************************************************************************** + */ +static int sdla_te_linelb(sdla_fe_t* fe, unsigned char mode) +{ + + WAN_ASSERT(fe->write_fe_reg == NULL); + WAN_ASSERT(fe->read_fe_reg == NULL); + if (mode == WAN_TE1_ACTIVATE_LB){ + DEBUG_EVENT("%s: %s Line Loopback mode activated.\n", + fe->name, + FE_MEDIA_DECODE(fe)); + WRITE_REG(REG_MASTER_DIAG, + READ_REG(REG_MASTER_DIAG) | BIT_MASTER_DIAG_LINELB); + }else{ + DEBUG_EVENT("%s: %s Line Loopback mode deactivated.\n", + fe->name, + FE_MEDIA_DECODE(fe)); + WRITE_REG(REG_MASTER_DIAG, + READ_REG(REG_MASTER_DIAG) & ~BIT_MASTER_DIAG_LINELB); + } + return 0; +} + +/* + ****************************************************************************** + * sdla_te_paylb() + * + * Description: + * Arguments: + * Returns: + ****************************************************************************** + */ +static int sdla_te_paylb(sdla_fe_t* fe, unsigned char mode) +{ + WAN_ASSERT(fe->write_fe_reg == NULL); + WAN_ASSERT(fe->read_fe_reg == NULL); + if (mode == WAN_TE1_ACTIVATE_LB){ + DEBUG_EVENT("%s: %s Payload Loopback mode activated.\n", + fe->name, + FE_MEDIA_DECODE(fe)); + WRITE_REG(REG_MASTER_DIAG, + READ_REG(REG_MASTER_DIAG) | BIT_MASTER_DIAG_PAYLB); + }else{ + DEBUG_EVENT("%s: %s Payload Loopback mode deactivated.\n", + fe->name, + FE_MEDIA_DECODE(fe)); + WRITE_REG(REG_MASTER_DIAG, + READ_REG(REG_MASTER_DIAG) & ~BIT_MASTER_DIAG_PAYLB); + } + return 0; +} + +/* + ****************************************************************************** + * sdla_te_ddlb() + * + * Description: + * Arguments: + * Returns: + ****************************************************************************** + */ +static int sdla_te_ddlb(sdla_fe_t* fe, unsigned char mode) +{ + WAN_ASSERT(fe->write_fe_reg == NULL); + WAN_ASSERT(fe->read_fe_reg == NULL); + if (mode == WAN_TE1_ACTIVATE_LB){ + DEBUG_EVENT("%s: %s Diagnostic Digital Loopback mode activated.\n", + fe->name, + FE_MEDIA_DECODE(fe)); + WRITE_REG(REG_MASTER_DIAG, + READ_REG(REG_MASTER_DIAG) | BIT_MASTER_DIAG_DDLB); + }else{ + DEBUG_EVENT("%s: %s Diagnostic Digital Loopback mode deactivated.\n", + fe->name, + FE_MEDIA_DECODE(fe)); + WRITE_REG(REG_MASTER_DIAG, + READ_REG(REG_MASTER_DIAG) & ~BIT_MASTER_DIAG_DDLB); + } + return 0; +} + +/* + ****************************************************************************** + * sdla_te_timer() + * + * Description: + * Arguments: + * Returns: + ****************************************************************************** + */ +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) +static void sdla_te_timer(void* pfe) +#elif defined(__WINDOWS__) +static void sdla_te_timer(IN PKDPC Dpc, void* pfe, void* arg2, void* arg3) +#else +static void sdla_te_timer(unsigned long pfe) +#endif +{ + sdla_fe_t *fe = (sdla_fe_t*)pfe; + sdla_t *card = (sdla_t*)fe->card; + wan_device_t *wandev = &card->wandev; + + if (wan_test_bit(TE_TIMER_KILL,(void*)&fe->te_param.critical)){ + wan_clear_bit(TE_TIMER_RUNNING,(void*)&fe->te_param.critical); + return; + } + /*WAN_ASSERT1(wandev->te_enable_timer == NULL); */ + DEBUG_TIMER("%s: TE1 timer!\n", fe->name); + /* Enable hardware interrupt for TE1 */ + + if (wandev->fe_enable_timer){ + wandev->fe_enable_timer(fe->card); + }else{ + sdla_te_polling(fe); + } + + return; +} + +/* + ****************************************************************************** + * sdla_te_enable_timer() + * + * Description: Enable software timer interrupt in delay ms. + * Arguments: + * Returns: + ****************************************************************************** + */ +static void sdla_te_enable_timer(sdla_fe_t* fe, unsigned char cmd, unsigned long delay) +{ + sdla_t *card = (sdla_t*)fe->card; + + WAN_ASSERT1(card == NULL); + DEBUG_TEST("%s: %s:%d Cmd=0x%X\n", + fe->name,__FUNCTION__,__LINE__,cmd); + +#if defined (__WINDOWS__) + if(KeGetCurrentIrql() > DISPATCH_LEVEL){ + /* May get here on AFT card because front end interrupt + is handled inside ISR not in DPC as on S514. + The KeSetTimer() function is illegal inside ISR, + so queue 'front_end_dpc_obj' DPC and this routine + will be called again from xilinx_front_end_dpc(). + */ + card->xilinx_fe_dpc.te_timer_delay = delay; + fe->te_param.timer_cmd=(unsigned char)cmd; + + if(KeInsertQueueDpc(&card->front_end_dpc_obj, NULL, + (PVOID)ENABLE_TE_TIMER) == FALSE){ + + DEBUG_TE1("Failed to queue 'front_end_dpc_obj'!\n"); + }else{ + DEBUG_TEST("Successfully queued 'front_end_dpc_obj'.\n"); + } + return; + }/* if() */ +#endif + if (wan_test_bit(TE_TIMER_KILL,(void*)&fe->te_param.critical)){ + wan_clear_bit( + TE_TIMER_RUNNING, + (void*)&fe->te_param.critical); + return; + } + + if (wan_test_bit(TE_TIMER_RUNNING,(void*)&fe->te_param.critical)){ + if (fe->te_param.timer_cmd == cmd){ + /* Just ignore current request */ + return; + } + DEBUG_TEST("%s: TE_TIMER_RUNNING: new_cmd=%X curr_cmd=%X\n", + fe->name, + cmd, + fe->te_param.timer_cmd); + return; + } + + wan_set_bit(TE_TIMER_RUNNING,(void*)&fe->te_param.critical); + + fe->te_param.timer_cmd=cmd; + + wan_add_timer(&fe->te_param.timer, delay * HZ / 1000); + return; +} + +/* + ****************************************************************************** + * sdla_te_polling() + * + * Description: + * Arguments: + * Returns: + ****************************************************************************** + */ +static int sdla_te_polling(sdla_fe_t* fe) +{ + sdla_t* card = (sdla_t*)fe->card; + + WAN_ASSERT(fe->write_fe_reg == NULL); + WAN_ASSERT(fe->read_fe_reg == NULL); + + DEBUG_TEST("%s: TE1 Polling State=%s Cmd=0x%X!\n", + fe->name, fe->fe_status==FE_CONNECTED?"Con":"Disconn", + fe->te_param.timer_cmd); + + wan_clear_bit(TE_TIMER_RUNNING,(void*)&fe->te_param.critical); + + switch(fe->te_param.timer_cmd){ + + case TE_LINELB_TIMER: + + if (IS_T1_FEMEDIA(fe)){ + + /* Sending T1 activation/deactivation loopback signal */ + if (fe->te_param.lb_tx_cnt > 10){ + WRITE_REG(REG_T1_XBOC_CODE, + (fe->te_param.lb_tx_cmd == WAN_TE1_ACTIVATE_LB) ? + LINELB_ACTIVATE_CODE : LINELB_DEACTIVATE_CODE); + }else{ + WRITE_REG(REG_T1_XBOC_CODE, LINELB_DS1LINE_ALL); + } + + if (--fe->te_param.lb_tx_cnt){ + sdla_te_enable_timer(fe, TE_LINELB_TIMER, LINELB_TE1_TIMER); + }else{ + DEBUG_TE1("%s: T1 loopback %s signal sent.\n", + fe->name, + (fe->te_param.lb_tx_cmd == WAN_TE1_ACTIVATE_LB) ? + "activation" : "deactivation"); + fe->te_param.lb_tx_cmd = 0x00; + } + } + break; + + case TE_SET_INTR: + sdla_te_set_intr(fe); + break; + + case TE_LINKDOWN_TIMER: + sdla_te_read_alarms(fe, WAN_FE_ALARM_READ); + sdla_te_pmon(fe, 0); + sdla_te_set_status(fe, fe->fe_alarm); + if (fe->fe_status == FE_CONNECTED){ + sdla_te_enable_timer(fe, TE_LINKUP_TIMER, POLLING_TE1_TIMER); + }else{ + sdla_te_enable_timer(fe, TE_LINKDOWN_TIMER, POLLING_TE1_TIMER); + } + break; + + case TE_LINKUP_TIMER: + /* ALEX: + ** Do not update protocol front end state from TE_LINKDOWN_TIMER + ** because it cause to stay longer in interrupt handler + ** (critical for XILINX code) */ + if (fe->fe_status == FE_CONNECTED){ + if (card->wandev.te_link_state){ + card->wandev.te_link_state(card); + } + /* AL: March 1, 2006: Enable FE INTR */ + sdla_te_set_intr(fe); + }else{ + sdla_te_enable_timer(fe, TE_LINKDOWN_TIMER, POLLING_TE1_TIMER); + } + break; + + case TE_RBS_READ: + /* Physically read RBS status and print */ + sdla_te_rbs_print(fe, 0); + break; + + case TE_SET_RBS: + /* Set RBS bits */ + sdla_te_set_rbsbits( fe, + fe->te_param.timer_channel, + fe->te_param.timer_abcd); + fe->te_param.timer_channel = 0; + fe->te_param.timer_abcd = 0; + break; + } + return 0; +} + +/* + ****************************************************************************** + * sdla_te_lb() + * + * Description: + * Arguments: + * Returns: + ****************************************************************************** + */ +static int sdla_te_lb(sdla_fe_t* fe, unsigned char mode) +{ + WAN_ASSERT(fe->write_fe_reg == NULL); + WAN_ASSERT(fe->read_fe_reg == NULL); + + if (!IS_T1_FEMEDIA(fe)){ + return 1; + } + if (fe->fe_status != FE_CONNECTED){ + return 1; + } + if (wan_test_bit(TE_TIMER_RUNNING,(void*)&fe->te_param.critical)){ + return 1; + } + if (wan_test_bit(LINELB_WAITING,(void*)&fe->te_param.critical)){ + DEBUG_TE1("%s: Still waiting for far end to send loopback signal back!\n", + fe->name); + } + DEBUG_TE1("%s: Sending %s loopback %s signal...\n", + fe->name, + FE_MEDIA_DECODE(fe), + (mode == WAN_TE1_ACTIVATE_LB) ? + "activation" : "deactivation"); + fe->te_param.lb_tx_cmd = mode; + fe->te_param.lb_tx_cnt = LINELB_CODE_CNT + LINELB_CHANNEL_CNT; + wan_set_bit(LINELB_WAITING,(void*)&fe->te_param.critical); + wan_set_bit(LINELB_CODE_BIT,(void*)&fe->te_param.critical); + wan_set_bit(LINELB_CHANNEL_BIT,(void*)&fe->te_param.critical); + sdla_te_enable_timer(fe, TE_LINELB_TIMER, LINELB_TE1_TIMER); + return 0; +} + + + +/* + ****************************************************************************** + * sdla_te_udp() + * + * Description: + * Arguments: + * Returns: + ****************************************************************************** + */ +static int sdla_te_udp(sdla_fe_t *fe, void* p_udp_cmd, unsigned char* data) +{ + wan_cmd_t *udp_cmd = (wan_cmd_t*)p_udp_cmd; + sdla_fe_debug_t *fe_debug; + int err = 0; + + switch(udp_cmd->wan_cmd_command){ + case WAN_GET_MEDIA_TYPE: + data[0] = (IS_T1_FEMEDIA(fe) ? WAN_MEDIA_T1 : + IS_E1_FEMEDIA(fe) ? WAN_MEDIA_E1 : + WAN_MEDIA_NONE); + udp_cmd->wan_cmd_return_code = WAN_CMD_OK; + udp_cmd->wan_cmd_data_len = sizeof(unsigned char); + break; + + case WAN_FE_SET_LB_MODE: + /* Activate/Deactivate Line Loopback modes */ + err = sdla_te_set_lbmode(fe, data[0], data[1]); + udp_cmd->wan_cmd_return_code = + (!err) ? WAN_CMD_OK : WAN_UDP_FAILED_CMD; + udp_cmd->wan_cmd_data_len = 0x00; + break; + + case WAN_FE_GET_STAT: + /* TE1_56K Read T1/E1/56K alarms */ +#if 0 + *(unsigned long *)&data[0] = fe->fe_alarm; +#endif + /* TE1 Update T1/E1 perfomance counters */ + memcpy(&data[0], &fe->fe_stats, sizeof(sdla_fe_stats_t)); + udp_cmd->wan_cmd_return_code = WAN_CMD_OK; + udp_cmd->wan_cmd_data_len = sizeof(sdla_fe_stats_t); + break; + + case WAN_FE_FLUSH_PMON: + /* TE1 Flush T1/E1 pmon counters */ + sdla_te_flush_pmon(fe); + udp_cmd->wan_cmd_return_code = WAN_CMD_OK; + break; + + case WAN_FE_GET_CFG: + /* Read T1/E1 configuration */ + memcpy(&data[0], + &fe->fe_cfg, + sizeof(sdla_fe_cfg_t)); + udp_cmd->wan_cmd_return_code = WAN_CMD_OK; + udp_cmd->wan_cmd_data_len = sizeof(sdla_fe_cfg_t); + break; + + case WAN_FE_SET_DEBUG_MODE: + fe_debug = (sdla_fe_debug_t*)&data[0]; + switch(fe_debug->type){ + case WAN_FE_DEBUG_RBS: + if (fe_debug->mode == WAN_FE_DEBUG_RBS_READ){ + DEBUG_EVENT("%s: Reading RBS status!\n", + fe->name); + sdla_te_enable_timer(fe, TE_RBS_READ, POLLING_TE1_TIMER); + udp_cmd->wan_cmd_return_code = WAN_CMD_OK; + }else if (fe_debug->mode == WAN_FE_DEBUG_RBS_PRINT){ + sdla_te_rbs_print(fe, 1); + udp_cmd->wan_cmd_return_code = WAN_CMD_OK; + }else if (fe_debug->mode == WAN_FE_DEBUG_RBS_RX_ENABLE){ + /* Enable extra debugging */ + DEBUG_EVENT("%s: Enable RBS RX DEBUG mode!\n", + fe->name); + fe->fe_debug |= WAN_FE_DEBUG_RBS_RX_ENABLE; + sdla_te_rbs_print(fe, 1); + udp_cmd->wan_cmd_return_code = WAN_CMD_OK; + }else if (fe_debug->mode == WAN_FE_DEBUG_RBS_TX_ENABLE){ + /* Enable extra debugging */ + DEBUG_EVENT("%s: Enable RBS TX DEBUG mode!\n", + fe->name); + fe->fe_debug |= WAN_FE_DEBUG_RBS_TX_ENABLE; + sdla_te_rbs_print(fe, 1); + udp_cmd->wan_cmd_return_code = WAN_CMD_OK; + }else if (fe_debug->mode == WAN_FE_DEBUG_RBS_RX_DISABLE){ + /* Disable extra debugging */ + DEBUG_EVENT("%s: Disable RBS RX DEBUG mode!\n", + fe->name); + fe->fe_debug &= ~WAN_FE_DEBUG_RBS_RX_ENABLE; + sdla_te_rbs_print(fe, 1); + udp_cmd->wan_cmd_return_code = WAN_CMD_OK; + }else if (fe_debug->mode == WAN_FE_DEBUG_RBS_TX_DISABLE){ + /* Disable extra debugging */ + DEBUG_EVENT("%s: Disable RBS TX DEBUG mode!\n", + fe->name); + fe->fe_debug &= ~WAN_FE_DEBUG_RBS_TX_ENABLE; + sdla_te_rbs_print(fe, 1); + udp_cmd->wan_cmd_return_code = WAN_CMD_OK; + }else if (fe_debug->mode == WAN_FE_DEBUG_RBS_SET){ + /* Set RBS bits */ + if (IS_T1_FEMEDIA(fe)){ + if (fe_debug->channel < 1 || fe_debug->channel > 24){ + DEBUG_EVENT("%s: Invalid channel number %d\n", + fe->name, + fe_debug->channel); + break; + } + }else{ + if (fe_debug->channel < 0 || fe_debug->channel > 31){ + DEBUG_EVENT("%s: Invalid channel number %d\n", + fe->name, + fe_debug->channel); + break; + } + } + + fe->te_param.timer_channel = fe_debug->channel; + fe->te_param.timer_abcd = fe_debug->abcd; + sdla_te_enable_timer(fe, TE_SET_RBS, POLLING_TE1_TIMER); + udp_cmd->wan_cmd_return_code = WAN_CMD_OK; + } + break; + case WAN_FE_DEBUG_ALARM: + if (fe_debug->mode == WAN_FE_DEBUG_ALARM_AIS_ENABLE){ + /* Enable TX AIS alarm */ + DEBUG_EVENT("%s: Enable TX AIS alarm!\n", + fe->name); + WRITE_REG(REG_E1_TRAN_TX_ALARM_CTRL, + READ_REG(REG_E1_TRAN_TX_ALARM_CTRL) | + BIT_E1_TRAN_TX_ALARM_AIS); + WRITE_REG(REG_TX_LINE_CONF, + READ_REG(REG_TX_LINE_CONF) | + BIT_TX_LINE_CONF_TAISEN); + udp_cmd->wan_cmd_return_code = WAN_CMD_OK; + }else if (fe_debug->mode == WAN_FE_DEBUG_ALARM_AIS_DISABLE){ + /* Disable TX AIS alarm */ + DEBUG_EVENT("%s: Disable TX AIS alarm!\n", + fe->name); + WRITE_REG(REG_E1_TRAN_TX_ALARM_CTRL, + READ_REG(REG_E1_TRAN_TX_ALARM_CTRL) & + ~BIT_E1_TRAN_TX_ALARM_AIS); + WRITE_REG(REG_TX_LINE_CONF, + READ_REG(REG_TX_LINE_CONF) & + ~BIT_TX_LINE_CONF_TAISEN); + udp_cmd->wan_cmd_return_code = WAN_CMD_OK; + } + break; + default: + udp_cmd->wan_cmd_return_code = WAN_UDP_INVALID_CMD; + break; + } + udp_cmd->wan_cmd_data_len = 0; + break; + case WAN_FE_TX_MODE: + fe_debug = (sdla_fe_debug_t*)&data[0]; + switch(fe_debug->mode){ + case WAN_FE_TXMODE_ENABLE: + DEBUG_EVENT("%s: Enable Transmitter!\n", + fe->name); + WRITE_REG(REG_XLPG_LINE_CFG, fe->te_param.xlpg_scale); + udp_cmd->wan_cmd_return_code = WAN_CMD_OK; + break; + case WAN_FE_TXMODE_DISABLE: + DEBUG_EVENT("%s: Disable Transmitter (tx tri-state mode)!\n", + fe->name); + WRITE_REG(REG_XLPG_LINE_CFG, BIT_XLPG_LINE_CFG_HIGHZ); + udp_cmd->wan_cmd_return_code = WAN_CMD_OK; + break; + } + break; + default: + udp_cmd->wan_cmd_return_code = WAN_UDP_INVALID_CMD; + udp_cmd->wan_cmd_data_len = 0; + break; + } + return 0; +} + +/* + ****************************************************************************** + * sdla_te_set_RBS() + * + * Description: + * Arguments: + * Returns: + ****************************************************************************** + */ +static int +sdla_te_set_rbsbits(sdla_fe_t *fe, int channel, unsigned char status) +{ + sdla_t* card = (sdla_t*)fe->card; + unsigned char rbsbits = 0x00; + + if (channel > fe->te_param.max_channels){ + DEBUG_EVENT("%s: Invalid channel number %d\n", + fe->name, channel); + return -EINVAL; + } + + if (status & WAN_RBS_SIG_A) rbsbits |= BIT_TPSC_SIGBYTE_A; + if (status & WAN_RBS_SIG_B) rbsbits |= BIT_TPSC_SIGBYTE_B; + if (IS_T1_FEMEDIA(fe) && WAN_FE_FRAME(fe) == WAN_FR_D4){ + if (status & WAN_RBS_SIG_A) rbsbits |= BIT_TPSC_SIGBYTE_C; + if (status & WAN_RBS_SIG_B) rbsbits |= BIT_TPSC_SIGBYTE_D; + }else{ + if (status & WAN_RBS_SIG_C) rbsbits |= BIT_TPSC_SIGBYTE_C; + if (status & WAN_RBS_SIG_D) rbsbits |= BIT_TPSC_SIGBYTE_D; + } + if (fe->fe_debug & WAN_FE_DEBUG_RBS_TX_ENABLE){ + DEBUG_EVENT("%s: %s:%-3d TX RBS A:%1d B:%1d C:%1d D:%1d\n", + fe->name, + FE_MEDIA_DECODE(fe), + channel, + (rbsbits & BIT_TPSC_SIGBYTE_A) ? 1 : 0, + (rbsbits & BIT_TPSC_SIGBYTE_B) ? 1 : 0, + (rbsbits & BIT_TPSC_SIGBYTE_C) ? 1 : 0, + (rbsbits & BIT_TPSC_SIGBYTE_D) ? 1 : 0); + } + if (rbsbits & BIT_TPSC_SIGBYTE_A){ + wan_set_bit(channel,(unsigned long*)&fe->te_param.tx_rbs_A); + }else{ + wan_clear_bit(channel,(unsigned long*)&fe->te_param.tx_rbs_A); + } + if (rbsbits & BIT_TPSC_SIGBYTE_B){ + wan_set_bit(channel,(unsigned long*)&fe->te_param.tx_rbs_B); + }else{ + wan_clear_bit(channel,(unsigned long*)&fe->te_param.tx_rbs_B); + } + if (rbsbits & BIT_TPSC_SIGBYTE_C){ + wan_set_bit(channel,(unsigned long*)&fe->te_param.tx_rbs_C); + }else{ + wan_clear_bit(channel,(unsigned long*)&fe->te_param.tx_rbs_C); + } + if (rbsbits & BIT_TPSC_SIGBYTE_D){ + wan_set_bit(channel,(unsigned long*)&fe->te_param.tx_rbs_D); + }else{ + wan_clear_bit(channel,(unsigned long*)&fe->te_param.tx_rbs_D); + } + if (fe->te_param.ptr_te_Tx_sig_off){ + unsigned char tx_sig = TE_SET_TX_SIG_BITS | rbsbits; + card->hw_iface.poke( + card->hw, + fe->te_param.ptr_te_Tx_sig_off + channel - 1, + &tx_sig, + sizeof(tx_sig)); + }else{ + if (IS_T1_FEMEDIA(fe)){ + WRITE_TPSC_REG(REG_TPSC_SIGNALING_BYTE, channel, + (rbsbits | + BIT_TPSC_SIGBYTE_SIGC_0 | + BIT_TPSC_SIGBYTE_SIGC_1)); + }else{ + WRITE_TPSC_REG(REG_TPSC_SIGNALING_BYTE, channel, + (rbsbits | + BIT_TPSC_SIGBYTE_SIGSRC)); + } + } + return 0; +} + +#if 0 +static void sdla_te_abcd_update(sdla_fe_t* fe) +{ + unsigned char sigx_cfg; + + sigx_cfg = READ_REG(REG_SIGX_CFG); + WRITE_REG(REG_SIGX_CFG, READ_REG(REG_SIGX_CFG) | BIT_SIGX_COSS); + fe->te_param.SIGX_chg_30_25 = + READ_REG(REG_SIGX_CFG) & MASK_SIGX_COSS_30_25; + fe->te_param.SIGX_chg_24_17 = + READ_REG(REG_SIGX_TIMESLOT_IND_STATUS); + fe->te_param.SIGX_chg_16_9 = + READ_REG(REG_SIGX_TIMESLOT_IND_ACCESS); + fe->te_param.SIGX_chg_8_1 = + READ_REG(REG_SIGX_TIMESLOT_IND_DATA_BUFFER); + WRITE_REG(REG_SIGX_CFG, sigx_cfg); + + if ((IS_E1_FEMEDIA(fe) && + fe->te_param.SIGX_chg_30_25) || + fe->te_param.SIGX_chg_24_17 || + fe->te_param.SIGX_chg_16_9 || + fe->te_param.SIGX_chg_8_1){ + sdla_te_enable_timer(fe, TE_ABCD_UPDATE, 10); + } + return; +} +#endif + + +/* + ****************************************************************************** + * sdla_te_rbs_update() + * + * Description: + * Arguments: + * Returns: + ****************************************************************************** + */ +static int +sdla_te_rbs_update(sdla_fe_t* fe, int channo, unsigned char status) +{ + + if (fe->fe_debug & WAN_FE_DEBUG_RBS_RX_ENABLE){ + DEBUG_EVENT( + "%s: %s:%-3d RX RBS A:%1d B:%1d C:%1d D:%1d\n", + fe->name, + FE_MEDIA_DECODE(fe), + channo, + (status & WAN_RBS_SIG_A) ? 1 : 0, + (status & WAN_RBS_SIG_B) ? 1 : 0, + (status & WAN_RBS_SIG_C) ? 1 : 0, + (status & WAN_RBS_SIG_D) ? 1 : 0); + } + + /* Update rbs value in private structures */ + wan_set_bit(channo, &fe->te_param.rx_rbs_status); + fe->te_param.rx_rbs[channo] = status; + + if (status & WAN_RBS_SIG_A){ + wan_set_bit(channo, + (unsigned long*)&fe->te_param.rx_rbs_A); + }else{ + wan_clear_bit(channo, + (unsigned long*)&fe->te_param.rx_rbs_A); + } + if (status & WAN_RBS_SIG_B){ + wan_set_bit(channo, + (unsigned long*)&fe->te_param.rx_rbs_B); + }else{ + wan_clear_bit(channo, + (unsigned long*)&fe->te_param.rx_rbs_B); + } + if (status & WAN_RBS_SIG_C){ + wan_set_bit(channo, + (unsigned long*)&fe->te_param.rx_rbs_C); + }else{ + wan_clear_bit(channo, + (unsigned long*)&fe->te_param.rx_rbs_C); + } + if (status & WAN_RBS_SIG_D){ + wan_set_bit(channo, + (unsigned long*)&fe->te_param.rx_rbs_D); + }else{ + wan_clear_bit(channo, + (unsigned long*)&fe->te_param.rx_rbs_D); + } + + return 0; +} + +/* + ****************************************************************************** + * sdla_te_rbs_report() + * + * Description: + * Arguments: + * Returns: + ****************************************************************************** + */ +static int +sdla_te_rbs_report(sdla_fe_t* fe) +{ + sdla_t* card = (sdla_t*)fe->card; + int ch = 1, max_channels; + + max_channels = fe->te_param.max_channels; + ch = (IS_E1_FEMEDIA(fe)) ? 0 : 1; + for(; ch <= max_channels; ch++) { + if (wan_test_bit(ch, &fe->te_param.rx_rbs_status)){ + if (card->wandev.te_report_rbsbits){ + card->wandev.te_report_rbsbits( + card, + ch, + fe->te_param.rx_rbs[ch]); + } + wan_clear_bit(ch, &fe->te_param.rx_rbs_status); + } + } + return 0; +} + +/* + ****************************************************************************** + * sdla_te_check_rbsbits() + * + * Description: + * Arguments: + * Returns: + ****************************************************************************** + */ +static int +sdla_te_check_rbsbits(sdla_fe_t* fe, int ch_base, unsigned int ts_map, int report) +{ + unsigned char status = 0x0, rbsbits = 0x00; + unsigned char sigx_cfg = 0x00; + int i = 0, channel; + + sigx_cfg = READ_REG(REG_SIGX_CFG); + WRITE_REG(REG_SIGX_CFG, sigx_cfg | BIT_SIGX_COSS); + switch(ch_base){ + case 1: + status = READ_REG(REG_SIGX_CHG_8_1); + break; + case 9: + status = READ_REG(REG_SIGX_CHG_16_9); + break; + case 17: + status = READ_REG(REG_SIGX_CHG_24_17); + break; + case 25: + status = READ_REG(REG_SIGX_CHG_30_25) & MASK_SIGX_COSS_30_25; + break; + } + WRITE_REG(REG_SIGX_CFG, sigx_cfg); + + if (status == 0x00){ + return 0; + } + + for(i = 0; i < 8; i ++) { + channel = ch_base + i; + if (IS_E1_FEMEDIA(fe)){ + if (channel >= 16){ + channel++; + } + if (channel > 31){ + continue; + } + } + /* If this channel/timeslot is not selected, move to + * another channel/timeslot */ + if (!wan_test_bit(channel-1, &ts_map)){ + continue; + } + if(status & ((unsigned char)(0x01 << i))) { + unsigned char abcd_status = 0x00; + + rbsbits = READ_SIGX_REG(REG_SIGX_CURRENT, channel); + if (channel > 16){ + rbsbits &= 0x0F; + }else{ + rbsbits = (rbsbits >> 4) & 0x0F; + } + + if (rbsbits & BIT_SIGX_A) abcd_status |= WAN_RBS_SIG_A; + if (rbsbits & BIT_SIGX_B) abcd_status |= WAN_RBS_SIG_B; + if (rbsbits & BIT_SIGX_C) abcd_status |= WAN_RBS_SIG_C; + if (rbsbits & BIT_SIGX_D) abcd_status |= WAN_RBS_SIG_D; + sdla_te_rbs_update(fe, channel, abcd_status); + } + } + return 0; +} + +/* + ****************************************************************************** + * sdla_te_read_rbsbits() + * + * Description: + * Arguments: + * Returns: + ****************************************************************************** + */ +static unsigned char +sdla_te_read_rbsbits(sdla_fe_t* fe, int channo, int mode) +{ + sdla_t* card = (sdla_t*)fe->card; + unsigned char rbsbits = 0x00, status = 0x00; + + rbsbits = READ_SIGX_REG(REG_SIGX_CURRENT, channo); + if (channo <= 16){ + rbsbits = (rbsbits >> 4) & 0x0F; + }else{ + rbsbits &= 0xF; + } + + if (rbsbits & BIT_SIGX_A) status |= WAN_RBS_SIG_A; + if (rbsbits & BIT_SIGX_B) status |= WAN_RBS_SIG_B; + if (rbsbits & BIT_SIGX_C) status |= WAN_RBS_SIG_C; + if (rbsbits & BIT_SIGX_D) status |= WAN_RBS_SIG_D; + + if (mode & WAN_TE_RBS_UPDATE){ + sdla_te_rbs_update(fe, channo, status); + } + + if ((mode & WAN_TE_RBS_REPORT) && card->wandev.te_report_rbsbits){ + card->wandev.te_report_rbsbits( + card, + channo, + status); + } + return status; +} + +/* + ****************************************************************************** + * sdla_te_rbs_print_banner() + * + * Description: + * Arguments: + * Returns: + ****************************************************************************** + */ +static int +sdla_te_rbs_print_banner(sdla_fe_t* fe) +{ + if (IS_T1_FEMEDIA(fe)){ + DEBUG_EVENT("%s: 111111111122222\n", + fe->name); + DEBUG_EVENT("%s: 123456789012345678901234\n", + fe->name); + DEBUG_EVENT("%s: ------------------------\n", + fe->name); + }else{ + DEBUG_EVENT("%s: 11111111112222222222333\n", + fe->name); + DEBUG_EVENT("%s: 12345678901234567890123456789012\n", + fe->name); + DEBUG_EVENT("%s: --------------------------------\n", + fe->name); + } + return 0; +} + +/* + ****************************************************************************** + * sdla_te_rbs_print_bits() + * + * Description: + * Arguments: + * Returns: + ****************************************************************************** + */ +static int +sdla_te_rbs_print_bits(sdla_fe_t* fe, unsigned long bits, char *msg) +{ + int i, max_channels = fe->te_param.max_channels; + int start_chan = 1; + + if (IS_E1_FEMEDIA(fe)){ + start_chan = 0; + } + _DEBUG_EVENT("%s: %s ", fe->name, msg); + for(i=start_chan; i <= max_channels; i++) + _DEBUG_EVENT("%01d", + wan_test_bit(i, &bits) ? 1 : 0); + _DEBUG_EVENT("\n"); + return 0; +} + +/* + ****************************************************************************** + * sdla_te_rbs_print() + * + * Description: + * Arguments: + * Returns: + ****************************************************************************** + */ +static int +sdla_te_rbs_print(sdla_fe_t* fe, int last_status) +{ + unsigned long rx_a = 0x00; + unsigned long rx_b = 0x00; + unsigned long rx_c = 0x00; + unsigned long rx_d = 0x00; + + if (last_status){ + rx_a = fe->te_param.rx_rbs_A; + rx_b = fe->te_param.rx_rbs_B; + rx_c = fe->te_param.rx_rbs_C; + rx_d = fe->te_param.rx_rbs_D; + + DEBUG_EVENT("%s: Last Status:\n", + fe->name); + sdla_te_rbs_print_banner(fe); + sdla_te_rbs_print_bits(fe, fe->te_param.tx_rbs_A, "TX A:"); + sdla_te_rbs_print_bits(fe, fe->te_param.tx_rbs_B, "TX B:"); + sdla_te_rbs_print_bits(fe, fe->te_param.tx_rbs_C, "TX C:"); + sdla_te_rbs_print_bits(fe, fe->te_param.tx_rbs_D, "TX D:"); + DEBUG_EVENT("%s:\n", fe->name); + }else{ + int i, channo = 0; + unsigned char rbsbits = 0x00; + for(i = 0; i < fe->te_param.max_channels; i++) { + + channo = (IS_T1_FEMEDIA(fe)) ? i+1 : i; + rbsbits = READ_SIGX_REG(REG_SIGX_CURRENT, channo); + DEBUG_TE1("%s: Update status for ch %d\n", + fe->name, + channo); + if (rbsbits & BIT_SIGX_CURRENT_A_N){ + wan_set_bit(channo, &rx_a); + } + if (rbsbits & BIT_SIGX_CURRENT_B_N){ + wan_set_bit(channo, &rx_b); + } + if (rbsbits & BIT_SIGX_CURRENT_C_N){ + wan_set_bit(channo, &rx_c); + } + if (rbsbits & BIT_SIGX_CURRENT_D_N){ + wan_set_bit(channo, &rx_d); + } + if ((IS_E1_FEMEDIA(fe) && (channo < 16)) || + (IS_T1_FEMEDIA(fe) && (channo <= 8))){ + DEBUG_TE1("%s: Update status for ch %d\n", + fe->name, channo+16); + if (rbsbits & BIT_SIGX_CURRENT_A_N16){ + wan_set_bit(channo+16, &rx_a); + } + if (rbsbits & BIT_SIGX_CURRENT_B_N16){ + wan_set_bit(channo+16, &rx_b); + } + if (rbsbits & BIT_SIGX_CURRENT_C_N16){ + wan_set_bit(channo+16, &rx_c); + } + if (rbsbits & BIT_SIGX_CURRENT_D_N16){ + wan_set_bit(channo+16, &rx_d); + } + } + if (i >= 15){ + break; + } + } + DEBUG_EVENT("%s: Current Status:\n", + fe->name); + sdla_te_rbs_print_banner(fe); + } + + sdla_te_rbs_print_bits(fe, rx_a, "RX A:"); + sdla_te_rbs_print_bits(fe, rx_b, "RX B:"); + sdla_te_rbs_print_bits(fe, rx_c, "RX C:"); + sdla_te_rbs_print_bits(fe, rx_d, "RX D:"); + return 0; +} + + +#if 0 +static int +sdla_te_check_rbsbits(sdla_fe_t* fe, unsigned char sig_chg, int channel_base, int report) +{ + sdla_t* card = (sdla_t*)fe->card; + int SIGX_addr = 0; + unsigned char status = 0x0; + int i = 0; + + if (fe->fe_status == FE_CONNECTED){ +#if 0 + DEBUG_EVENT("Read RBS: sig_chg: 0x%02X, ch base: %d\n", + sig_chg, channel_base); +#endif + } + + if (IS_T1_FEMEDIA(fe)){ + SIGX_addr = (channel_base == 9) ? 0x18 : 0x10; + } + + for(i = 0; i < 8; i ++) { + if(sig_chg & ((unsigned char)(0x01 << i))) { + status = READ_SIGX_REG(SIGX_addr, i+1); + if (fe->fe_status != FE_CONNECTED){ + return -EINVAL; + } +#if 0 + DEBUG_EVENT("%s: SIGX bit %d set, value 0x%02X read from reg 0x%02X\n", + fe->name, i, status, SIGX_addr + i); +#endif + if (channel_base == 17){ + status &= 0x0F; + }else{ + status = (status >> 4) & 0x0F; + } + + DEBUG_TE1("%s: %s:%d RX RBS A:%1d B:%1d C:%1d D:%1d\n", + fe->name, + FE_MEDIA_DECODE(fe), + channel_base + i, + (status & BIT_SIGX_A) ? 1 : 0, + (status & BIT_SIGX_B) ? 1 : 0, + (status & BIT_SIGX_C) ? 1 : 0, + (status & BIT_SIGX_D) ? 1 : 0); + + if (report && card->wandev.te_report_rbsbits){ + card->wandev.te_report_rbsbits( + card, + channel_base+i, + status); + } + } + } + return 0; +} +#endif + +#if !defined(CONFIG_PRODUCT_WANPIPE_GENERIC) +/* + ****************************************************************************** + * sdla_te_get_snmp_data() + * + * Description: + * Arguments: + * Returns: + ****************************************************************************** + */ +#define DSX1IFINDEX 4 +#define DSX1TIMEELAPSED 5 +#define DSX1VALIDINTERVALS 6 +#define DSX1LINETYPE 7 +#define DSX1LINECODING 8 +#define DSX1SENDCODE 9 +#define DSX1CIRCUITIDENTIFIER 10 +#define DSX1LOOPBACKCONFIG 11 +#define DSX1LINESTATUS 12 +#define DSX1SIGNALMODE 13 +#define DSX1TRANSMITCLOCKSOURCE 14 +#define DSX1FDL 15 +#define DSX1INVALIDINTERVALS 16 +#define DSX1LINELENGTH 17 +#define DSX1LINESTATUSLASTCHANGE 18 +#define DSX1LINESTATUSCHANGETRAPENABLE 19 +#define DSX1LOOPBACKSTATUS 20 +#define DSX1DS1CHANNELNUMBER 21 +#define DSX1CHANNELIZATION 22 +#define DSX1CURRENTINDEX 25 +#define DSX1CURRENTESS 26 +#define DSX1CURRENTSESS 27 +#define DSX1CURRENTSEFSS 28 +#define DSX1CURRENTUASS 29 +#define DSX1CURRENTCSSS 30 +#define DSX1CURRENTPCVS 31 +#define DSX1CURRENTLESS 32 +#define DSX1CURRENTBESS 33 +#define DSX1CURRENTDMS 34 +#define DSX1CURRENTLCVS 35 +#define DSX1INTERVALINDEX 38 +#define DSX1INTERVALNUMBER 39 +#define DSX1INTERVALESS 40 +#define DSX1INTERVALSESS 41 +#define DSX1INTERVALSEFSS 42 +#define DSX1INTERVALUASS 43 +#define DSX1INTERVALCSSS 44 +#define DSX1INTERVALPCVS 45 +#define DSX1INTERVALLESS 46 +#define DSX1INTERVALBESS 47 +#define DSX1INTERVALDMS 48 +#define DSX1INTERVALLCVS 49 +#define DSX1INTERVALVALIDDATA 50 +#define DSX1TOTALINDEX 53 +#define DSX1TOTALESS 54 +#define DSX1TOTALSESS 55 +#define DSX1TOTALSEFSS 56 +#define DSX1TOTALUASS 57 +#define DSX1TOTALCSSS 58 +#define DSX1TOTALPCVS 59 +#define DSX1TOTALLESS 60 +#define DSX1TOTALBESS 61 +#define DSX1TOTALDMS 62 +#define DSX1TOTALLCVS 63 +#define DSX1FARENDCURRENTINDEX 66 +#define DSX1FARENDTIMEELAPSED 67 +#define DSX1FARENDVALIDINTERVALS 68 +#define DSX1FARENDCURRENTESS 69 +#define DSX1FARENDCURRENTSESS 70 +#define DSX1FARENDCURRENTSEFSS 71 +#define DSX1FARENDCURRENTUASS 72 +#define DSX1FARENDCURRENTCSSS 73 +#define DSX1FARENDCURRENTLESS 74 +#define DSX1FARENDCURRENTPCVS 75 +#define DSX1FARENDCURRENTBESS 76 +#define DSX1FARENDCURRENTDMS 77 +#define DSX1FARENDINVALIDINTERVALS 78 +#define DSX1FARENDINTERVALINDEX 81 +#define DSX1FARENDINTERVALNUMBER 82 +#define DSX1FARENDINTERVALESS 83 +#define DSX1FARENDINTERVALSESS 84 +#define DSX1FARENDINTERVALSEFSS 85 +#define DSX1FARENDINTERVALUASS 86 +#define DSX1FARENDINTERVALCSSS 87 +#define DSX1FARENDINTERVALLESS 88 +#define DSX1FARENDINTERVALPCVS 89 +#define DSX1FARENDINTERVALBESS 90 +#define DSX1FARENDINTERVALDMS 91 +#define DSX1FARENDINTERVALVALIDDATA 92 +#define DSX1FARENDTOTALINDEX 95 +#define DSX1FARENDTOTALESS 96 +#define DSX1FARENDTOTALSESS 97 +#define DSX1FARENDTOTALSEFSS 98 +#define DSX1FARENDTOTALUASS 99 +#define DSX1FARENDTOTALCSSS 100 +#define DSX1FARENDTOTALLESS 101 +#define DSX1FARENDTOTALPCVS 102 +#define DSX1FARENDTOTALBESS 103 +#define DSX1FARENDTOTALDMS 104 +#define DSX1FRACINDEX 107 +#define DSX1FRACNUMBER 108 +#define DSX1FRACIFINDEX 109 +#define DSX1CHANMAPPEDIFINDEX 112 + +static int sdla_te_get_snmp_data(sdla_fe_t* fe, void* pdev, void* data) +{ +#if 0 +/* FIXME: NC dev not used + * ALEX please confirm + */ + netdevice_t* dev = (netdevice_t *)dev_ptr; +#endif + wanpipe_snmp_t* snmp; + sdla_te_pmon_t* pmon = &fe->fe_stats.u.te_pmon; + unsigned long alarms = 0; + + snmp = (wanpipe_snmp_t*)data; + + switch(snmp->snmp_magic){ + case DSX1LINESTATUS: + alarms = fe->fe_alarm; + snmp->snmp_val = 0; + if (alarms & WAN_TE_BIT_YEL_ALARM){ + snmp->snmp_val |= SNMP_DSX1_RCVFARENDLOF; + } + if (alarms & WAN_TE_BIT_AIS_ALARM){ + snmp->snmp_val |= SNMP_DSX1_RCVAIS; + } + if (alarms & WAN_TE_BIT_RED_ALARM){ + snmp->snmp_val |= SNMP_DSX1_LOSSOFFRAME; + } + if (alarms & WAN_TE_BIT_LOS_ALARM){ + snmp->snmp_val |= SNMP_DSX1_LOSSOFSIGNAL; + } + + if (!snmp->snmp_val){ + snmp->snmp_val = SNMP_DSX1_NOALARM; + } + break; + + case DSX1CURRENTLCVS: + case DSX1INTERVALLCVS: + case DSX1TOTALLCVS: + /* Current measurement in a current 15 minutes interval */ + /* FIXME: Currently, I return total number of LCV */ + snmp->snmp_val = pmon->lcv_errors; + break; + + case DSX1CURRENTSEFSS: + case DSX1INTERVALSEFSS: + case DSX1TOTALSEFSS: + /* Second with one or more Out of Frame defects */ + /* FIXME: If we got OOF errors, return 1 */ + if (pmon->oof_errors){ + snmp->snmp_val = 1; + } + break; + + case DSX1CURRENTPCVS: + case DSX1INTERVALPCVS: + case DSX1TOTALPCVS: + /* Second with one or more CRC or bit errors defects */ + /* FIXME: If we got OOF errors, return 1 */ + if (IS_T1_FEMEDIA(fe) && pmon->oof_errors){ + snmp->snmp_val = 1; + }else if (IS_E1_FEMEDIA(fe) && pmon->crc4_errors){ + snmp->snmp_val = 1; + } + break; + + break; + } + return 0; +} +#endif + +static int sdla_te_led_ctrl(sdla_fe_t *fe, int mode) +{ + unsigned char led; + + if (!fe->read_fe_reg || !fe->write_fe_reg){ + return -EINVAL; + } + + led= READ_REG(REG_GLOBAL_CFG); + + if (mode == AFT_LED_ON){ + led&=~(BIT_GLOBAL_PIO); + }else if (mode == AFT_LED_OFF){ + led|=BIT_GLOBAL_PIO; + }else{ + if (led&BIT_GLOBAL_PIO){ + led&=~(BIT_GLOBAL_PIO); + }else{ + led|=BIT_GLOBAL_PIO; + } + } + + WRITE_REG(REG_GLOBAL_CFG,led); + return 0; +} + +static int +sdla_te_update_alarm_info(sdla_fe_t* fe, struct seq_file* m, int* stop_cnt) +{ + +#if !defined(__WINDOWS__) + PROC_ADD_LINE(m, + "=============================== %s Alarms ===============================\n", + FE_MEDIA_DECODE(fe)); + PROC_ADD_LINE(m, + PROC_STATS_ALARM_FORMAT, + "ALOS", WAN_TE_ALOS_ALARM(fe->fe_alarm), + "LOS", WAN_TE_LOS_ALARM(fe->fe_alarm)); + PROC_ADD_LINE(m, + PROC_STATS_ALARM_FORMAT, + "RED", WAN_TE_RED_ALARM(fe->fe_alarm), + "AIS", WAN_TE_AIS_ALARM(fe->fe_alarm)); + if (IS_T1_FEMEDIA(fe)){ + PROC_ADD_LINE(m, + PROC_STATS_ALARM_FORMAT, + "YEL", WAN_TE_YEL_ALARM(fe->fe_alarm), + "OOF", WAN_TE_OOF_ALARM(fe->fe_alarm)); + }else{ + PROC_ADD_LINE(m, + PROC_STATS_ALARM_FORMAT, + "OOF", WAN_TE_OOF_ALARM(fe->fe_alarm), + "", ""); + } + return m->count; +#endif + return 0; +} + +static int +sdla_te_update_pmon_info(sdla_fe_t* fe, struct seq_file* m, int* stop_cnt) +{ + +#if !defined(__WINDOWS__) + PROC_ADD_LINE(m, + "=========================== %s PMON counters ============================\n", + FE_MEDIA_DECODE(fe)); + + if (IS_T1_FEMEDIA(fe)){ + PROC_ADD_LINE(m, + PROC_STATS_PMON_FORMAT, + "Framing Bit Error", fe->fe_stats.u.te_pmon.fer_errors, + "Line Code Violation", fe->fe_stats.u.te_pmon.lcv_errors); + PROC_ADD_LINE(m, + PROC_STATS_PMON_FORMAT, + "Out of Frame Errors", fe->fe_stats.u.te_pmon.oof_errors, + "Bit Errors", fe->fe_stats.u.te_pmon.bee_errors); + }else{ + PROC_ADD_LINE(m, + PROC_STATS_PMON_FORMAT, + "Frame Alighment Signal", fe->fe_stats.u.te_pmon.fas_errors, + "Line Code Violation", fe->fe_stats.u.te_pmon.lcv_errors); + PROC_ADD_LINE(m, + PROC_STATS_PMON_FORMAT, + "CRC4 Errors", fe->fe_stats.u.te_pmon.crc4_errors, + "Far End Block Errors", fe->fe_stats.u.te_pmon.feb_errors); + + } + return m->count; +#endif + return 0; +} +/* + ****************************************************************************** + * ClearTemplate() + * + * Description: + * Arguments: + * Returns: + ****************************************************************************** + */ +/************************** End of files *************************************/ diff -Nur linux.org/drivers/net/wan/sdla_te3.c linux-2.6.17/drivers/net/wan/sdla_te3.c --- linux.org/drivers/net/wan/sdla_te3.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/drivers/net/wan/sdla_te3.c 2006-08-30 10:07:16.000000000 +0000 @@ -0,0 +1,1035 @@ +/****************************************************************************** + * + * sdla_te3.c Sangoma T3/E3 front end. + * + * Alex Feldman + * + * Copyright Sangoma Technologies Inc. 1999, 2000,2001, 2002, 2003, 2004 + * + * This program is provided subject to the Software License included in + * this package in the file license.txt. By using this program you agree + * to be bound bythe terms of this license. + * + * Should you not have a copy of the file license.txt, or wish to obtain + * a hard copy of the Software License, please contact Sangoma + * technologies Corporation. + * + * Contact: Sangoma Technologies Inc. 905-474-1990, info@sangoma.com + * + *****************************************************************************/ + + +/****************************************************************************** +** INCLUDE FILES +******************************************************************************/ + +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) +# include +# if !defined(CONFIG_PRODUCT_WANPIPE_GENERIC) +# include +# endif +# include +# include +# include +# include /* WANPIPE common user API definitions */ +# include +#elif (defined __LINUX__) || (defined __KERNEL__) +# include +# include +# include +# include +# include +# include /* WANPIPE common user API definitions */ +#else +# error "No OS Defined" +#endif + +/****************************************************************************** +** DEFINES AND MACROS +******************************************************************************/ + +/****************************************************************************** +** DEFINES AND MACROS +******************************************************************************/ + +#if defined(DEBUG) +#define WRITE_CPLD(reg,val) \ + DEBUG_EVENT("%s: Write to CPLD reg %d value %X\n", \ + fe->name, reg, val); + +#define WRITE_FRAMER(reg,val) \ + DEBUG_EVENT("%s: Write to Framer off %X value %X\n", \ + fe->name, reg, val); +#else + +#define WRITE_CPLD(reg,val) \ + (fe->write_cpld) ? fe->write_cpld(fe->card, reg, val) : -EINVAL + +#define WRITE_FRAMER(reg,val) \ + (fe->write_framer) ? fe->write_framer(fe->card, reg, val) : -EINVAL +#define READ_FRAMER(reg) \ + (fe->read_framer) ? fe->read_framer(fe->card, reg) : 0 +#endif + +#define WAN_FE_SWAP_BIT(value, mask) \ + if ((value) & mask){ \ + (value) &= ~mask; \ + }else{ \ + (value) |= mask; \ + } + +/* DS3: Define DS3 alarm states: LOS OOF YEL */ +#define IS_DS3_ALARM(alarm) ((alarm) & \ + (WAN_TE3_BIT_LOS_ALARM | \ + WAN_TE3_BIT_YEL_ALARM | \ + WAN_TE3_BIT_OOF_ALARM)) + +/* DS3: Define E3 alarm states: LOS OOF YEL */ +#define IS_E3_ALARM(alarm) ((alarm) & \ + (WAN_TE3_BIT_LOS_ALARM | \ + WAN_TE3_BIT_YEL_ALARM | \ + WAN_TE3_BIT_OOF_ALARM)) + +/****************************************************************************** +** FUNCTION DEFINITIONS +******************************************************************************/ + +static int sdla_te3_config(void *p_fe); +static int sdla_te3_unconfig(void *p_fe); +static int sdla_te3_get_fe_status(sdla_fe_t *fe, unsigned char *status); +static int sdla_te3_polling(sdla_fe_t *fe); +static int sdla_ds3_isr(sdla_fe_t *fe); +static int sdla_e3_isr(sdla_fe_t *fe); +static int sdla_te3_isr(sdla_fe_t *fe); +static int sdla_te3_udp(sdla_fe_t *fe, void*, unsigned char*); +static unsigned int sdla_te3_alarm(sdla_fe_t *fe, int); +static int sdla_te3_read_pmon(sdla_fe_t *fe, int); + +static int sdla_te3_update_alarm_info(sdla_fe_t* fe, struct seq_file* m, int* stop_cnt); +static int sdla_te3_update_pmon_info(sdla_fe_t* fe, struct seq_file* m, int* stop_cnt); + +/****************************************************************************** + * sdla_te3_get_fe_status() + * + * Description: + * Arguments: + * Returns: + ****************************************************************************** + */ +static char* sdla_te3_get_fe_media_string(void) +{ + return ("AFT T3/E3"); +} + +/****************************************************************************** + * sdla_te3_get_fe_status() + * + * Description: + * Arguments: + * Returns: + ****************************************************************************** + */ +static unsigned char sdla_te3_get_fe_media(sdla_fe_t *fe) +{ + return fe->fe_cfg.media; +} + +/****************************************************************************** + * sdla_te3_get_fe_status() + * + * Description: + * Arguments: + * Returns: + ****************************************************************************** + */ +static int sdla_te3_get_fe_status(sdla_fe_t *fe, unsigned char *status) +{ + *status = fe->fe_status; + return 0; +} + +/****************************************************************************** + * sdla_te3_polling() + * + * Description: + * Arguments: + * Returns: + ****************************************************************************** + */ +static int sdla_te3_polling(sdla_fe_t *fe) +{ + DEBUG_EVENT("%s: %s: This function is still not supported!\n", + fe->name, __FUNCTION__); + return -EINVAL; +} + +/****************************************************************************** + * sdla_te3_set_status() + * + * Description: + * Arguments: + * Returns: + ****************************************************************************** + */ +static int sdla_te3_set_status(sdla_fe_t *fe) +{ + if (IS_DS3(&fe->fe_cfg)){ + if (IS_DS3_ALARM(fe->fe_alarm)){ + if (fe->fe_status != FE_DISCONNECTED){ + DEBUG_EVENT("%s: DS3 disconnected!\n", + fe->name); + fe->fe_status = FE_DISCONNECTED; + } + }else{ + if (fe->fe_status != FE_CONNECTED){ + DEBUG_EVENT("%s: DS3 connected!\n", + fe->name); + fe->fe_status = FE_CONNECTED; + } + } + }else if (IS_E3(&fe->fe_cfg)){ + if (IS_E3_ALARM(fe->fe_alarm)){ + if (fe->fe_status != FE_DISCONNECTED){ + DEBUG_EVENT("%s: E3 disconnected!\n", + fe->name); + fe->fe_status = FE_DISCONNECTED; + } + }else{ + if (fe->fe_status != FE_CONNECTED){ + DEBUG_EVENT("%s: E3 connected!\n", + fe->name); + fe->fe_status = FE_CONNECTED; + } + } + }else{ + return -EINVAL; + } + return 0; +} + +/****************************************************************************** +** sdla_ds3_tx_isr() +** +** Description: +** Arguments: +** Returns: +******************************************************************************/ +static int sdla_ds3_tx_isr(sdla_fe_t *fe) +{ + unsigned char value; + + value = READ_FRAMER(REG_TxDS3_LAPD_STATUS); + if (value & BIT_TxDS3_LAPD_STATUS_INT){ + DEBUG_EVENT("%s: LAPD Interrupt!\n", + fe->name); + } + return 0; +} + +/****************************************************************************** +** sdla_ds3_rx_isr() +** +** Description: +** Arguments: +** Returns: +******************************************************************************/ +static int sdla_ds3_rx_isr(sdla_fe_t *fe) +{ + unsigned char value, status; + + /* RxDS3 Interrupt status register (0x13) */ + value = READ_FRAMER(REG_RxDS3_INT_STATUS); + status = READ_FRAMER(REG_RxDS3_CFG_STATUS); + if (fe->fe_cfg.frame == WAN_FR_DS3_Cbit && value & BIT_RxDS3_INT_STATUS_CPBIT_ERR){ + if (WAN_NET_RATELIMIT()){ + DEBUG_EVENT("%s: CP Bit Error interrupt detected!\n", + fe->name); + } + } + if (value & BIT_RxDS3_INT_STATUS_LOS){ + if (status & BIT_RxDS3_CFG_STATUS_RxLOS){ + DEBUG_EVENT("%s: LOS Status ON!\n", + fe->name); + fe->fe_alarm |= WAN_TE3_BIT_LOS_ALARM; + }else{ + DEBUG_EVENT("%s: LOS Status OFF!\n", + fe->name); + fe->fe_alarm &= ~WAN_TE3_BIT_LOS_ALARM; + } + } + if (value & BIT_RxDS3_INT_STATUS_AIS){ + DEBUG_EVENT("%s: AIS status %s!\n", + fe->name, + (status & BIT_RxDS3_CFG_STATUS_RxAIS) ? "ON" : "OFF"); + } + if (value & BIT_RxDS3_INT_STATUS_IDLE){ + DEBUG_EVENT("%s: IDLE condition status %s!\n", + fe->name, + (status & BIT_RxDS3_CFG_STATUS_RxIDLE) ? "ON" : "OFF"); + } + if (value & BIT_RxDS3_INT_STATUS_OOF){ + if (status & BIT_RxDS3_CFG_STATUS_RxLOS){ + DEBUG_EVENT("%s: OOF Alarm ON!\n", + fe->name); + fe->fe_alarm |= WAN_TE3_BIT_OOF_ALARM; + }else{ + DEBUG_EVENT("%s: OOF Alarm OFF!\n", + fe->name); + fe->fe_alarm &= ~WAN_TE3_BIT_OOF_ALARM; + } + } + status = READ_FRAMER(REG_RxDS3_STATUS); + if (value & BIT_RxDS3_INT_STATUS_FERF){ + if (status & BIT_RxDS3_STATUS_RxFERF){ + DEBUG_EVENT("%s: Rx FERF status is ON (YELLOW)!\n", + fe->name); + fe->fe_alarm |= WAN_TE3_BIT_YEL_ALARM; + }else{ + DEBUG_EVENT("%s: Rx FERF status is OFF!\n", + fe->name); + fe->fe_alarm &= ~WAN_TE3_BIT_YEL_ALARM; + } + } + if (fe->fe_cfg.frame == WAN_FR_DS3_Cbit && value & BIT_RxDS3_INT_STATUS_AIC){ + DEBUG_EVENT("%s: AIC bit-field status %s!\n", + fe->name, + (status & BIT_RxDS3_STATUS_RxAIC) ? "ON" : "OFF"); + } + if (value & BIT_RxDS3_INT_STATUS_PBIT_ERR){ + DEBUG_EVENT("%s: P-Bit error interrupt!\n", + fe->name); + } + + /* RxDS3 FEAC Interrupt (0x17) */ + value = READ_FRAMER(REG_RxDS3_FEAC_INT); + if (value & BIT_RxDS3_FEAC_REMOVE_INT_STATUS){ + DEBUG_EVENT("%s: RxFEAC Remove Interrupt!\n", + fe->name); + } + if (value & BIT_RxDS3_FEAC_VALID_INT_STATUS){ + DEBUG_EVENT("%s: RxFEAC Valid Interrupt!\n", + fe->name); + } + + return 0; +} + +/****************************************************************************** +** sdla_ds3_isr() +** +** Description: +** Arguments: +** Returns: +******************************************************************************/ +static int sdla_ds3_isr(sdla_fe_t *fe) +{ + unsigned char value; + + value = READ_FRAMER(REG_BLOCK_INT_STATUS); + if (value & BIT_BLOCK_INT_STATUS_RxDS3_E3){ + sdla_ds3_rx_isr(fe); + } + if (value & BIT_BLOCK_INT_STATUS_TxDS3_E3){ + sdla_ds3_tx_isr(fe); + } + + return 0; +} + +/****************************************************************************** +** sdla_e3_tx_isr() +** +** Description: +** Arguments: +** Returns: +******************************************************************************/ +static int sdla_e3_tx_isr(sdla_fe_t *fe) +{ + DEBUG_EVENT("%s: %s: This function is still not supported!\n", + fe->name, __FUNCTION__); + + return 0; +} + + +/****************************************************************************** +** sdla_e3_rx_isr() +** +** Description: +** Arguments: +** Returns: +******************************************************************************/ +static int sdla_e3_rx_isr(sdla_fe_t *fe) +{ + unsigned char int_status1, int_status2; + unsigned char status; + + int_status1 = READ_FRAMER(REG_RxE3_INT_STATUS_1); + int_status2 = READ_FRAMER(REG_RxE3_INT_STATUS_2); + status = READ_FRAMER(REG_RxE3_CFG_STATUS_2); + if (int_status1 & BIT_RxE3_INT_STATUS_OOF){ + if (status & BIT_RxE3_CFG_STATUS_RxOOF){ + DEBUG_EVENT("%s: OOF Alarm ON!\n", + fe->name); + fe->fe_alarm |= WAN_TE3_BIT_OOF_ALARM; + }else{ + DEBUG_EVENT("%s: OOF Alarm OFF!\n", + fe->name); + fe->fe_alarm &= ~WAN_TE3_BIT_OOF_ALARM; + } + } + + if (int_status1 & BIT_RxE3_INT_STATUS_LOF){ + if (status & BIT_RxE3_CFG_STATUS_RxLOF){ + DEBUG_EVENT("%s: LOF Alarm ON!\n", + fe->name); + fe->fe_alarm |= WAN_TE3_BIT_LOF_ALARM; + }else{ + DEBUG_EVENT("%s: LOF Alarm OFF!\n", + fe->name); + fe->fe_alarm &= ~WAN_TE3_BIT_LOF_ALARM; + } + } + + if (int_status1 & BIT_RxE3_INT_STATUS_LOS){ + if (status & BIT_RxE3_CFG_STATUS_RxLOS){ + DEBUG_EVENT("%s: LOS Alarm ON!\n", + fe->name); + fe->fe_alarm |= WAN_TE3_BIT_LOS_ALARM; + }else{ + DEBUG_EVENT("%s: LOS Alarm OFF!\n", + fe->name); + fe->fe_alarm &= ~WAN_TE3_BIT_LOS_ALARM; + } + } + + if (int_status1 & BIT_RxE3_INT_STATUS_AIS){ + if (status & BIT_RxE3_CFG_STATUS_RxAIS){ + DEBUG_EVENT("%s: AIS Alarm ON!\n", + fe->name); + fe->fe_alarm |= WAN_TE3_BIT_AIS_ALARM; + }else{ + DEBUG_EVENT("%s: AIS Alarm OFF!\n", + fe->name); + fe->fe_alarm &= ~WAN_TE3_BIT_AIS_ALARM; + } + } + + if (int_status2 & BIT_RxE3_INT_STATUS_FERF){ + if (status & BIT_RxE3_CFG_STATUS_RxFERF){ + DEBUG_EVENT("%s: Rx FERF status is ON (YELLOW)!\n", + fe->name); + fe->fe_alarm |= WAN_TE3_BIT_YEL_ALARM; + }else{ + DEBUG_EVENT("%s: Rx FERF status is OFF!\n", + fe->name); + fe->fe_alarm &= ~WAN_TE3_BIT_YEL_ALARM; + } + } + + return 0; +} + +/****************************************************************************** + * sdla_e3_isr() + * + * Description: + * Arguments: + * Returns: + ****************************************************************************** + */ +static int sdla_e3_isr(sdla_fe_t *fe) +{ + unsigned char value; + + value = READ_FRAMER(REG_BLOCK_INT_STATUS); + if (value & BIT_BLOCK_INT_STATUS_RxDS3_E3){ + sdla_e3_rx_isr(fe); + } + if (value & BIT_BLOCK_INT_STATUS_TxDS3_E3){ + sdla_e3_tx_isr(fe); + } + return -EINVAL; +} + +/****************************************************************************** + * sdla_te3_isr() + * + * Description: + * Arguments: + * Returns: + ****************************************************************************** + */ +static int sdla_te3_isr(sdla_fe_t *fe) +{ + sdla_fe_cfg_t *fe_cfg = &fe->fe_cfg; + unsigned char value; + int err = 0; + + value = READ_FRAMER(REG_BLOCK_INT_STATUS); + switch(fe_cfg->media){ + case WAN_MEDIA_DS3: + err = sdla_ds3_isr(fe); + break; + case WAN_MEDIA_E3: + err = sdla_e3_isr(fe); + break; + } + fe->fe_alarm = sdla_te3_alarm(fe, 1); + return err; +} + +/****************************************************************************** + * sdla_te3_alarm() + * + * Description: + * Arguments: + * Returns: + ****************************************************************************** + */ +static unsigned int sdla_te3_alarm(sdla_fe_t *fe, int update) +{ + sdla_fe_cfg_t *fe_cfg = &fe->fe_cfg; + unsigned int alarm = 0; + unsigned char value; + + if (fe_cfg->media == WAN_MEDIA_DS3){ + value = READ_FRAMER(REG_RxDS3_CFG_STATUS); + if (value & BIT_RxDS3_CFG_STATUS_RxAIS){ + alarm |= WAN_TE3_BIT_AIS_ALARM; + DEBUG_TE3("%s: (T3/E3) AIS Alarm is ON\n", fe->name); + }else{ + alarm &= ~WAN_TE3_BIT_AIS_ALARM; + DEBUG_TE3("%s: (T3/E3) AIS Alarm is OFF\n", fe->name); + } + if (value & BIT_RxDS3_CFG_STATUS_RxLOS){ + alarm |= WAN_TE3_BIT_LOS_ALARM; + DEBUG_TE3("%s: (T3/E3) LOS Alarm is ON\n", fe->name); + }else{ + alarm &= ~WAN_TE3_BIT_LOS_ALARM; + DEBUG_TE3("%s: (T3/E3) LOS Alarm is OFF\n", fe->name); + } + if (value & BIT_RxDS3_CFG_STATUS_RxOOF){ + alarm |= WAN_TE3_BIT_OOF_ALARM; + DEBUG_TE3("%s: (T3/E3) OOF Alarm is ON\n", fe->name); + }else{ + alarm &= ~WAN_TE3_BIT_OOF_ALARM; + DEBUG_TE3("%s: (T3/E3) OOF Alarm is OFF\n", fe->name); + } + value = READ_FRAMER(REG_RxDS3_STATUS); + if (value & BIT_RxDS3_STATUS_RxFERF){ + alarm |= WAN_TE3_BIT_YEL_ALARM; + DEBUG_TE3("%s: (T3/E3) YEL Alarm is ON\n", fe->name); + }else{ + alarm &= ~WAN_TE3_BIT_YEL_ALARM; + DEBUG_TE3("%s: (T3/E3) YEL Alarm is OFF\n", fe->name); + } + }else{ + value = READ_FRAMER(REG_RxE3_CFG_STATUS_2); + if (value & BIT_RxE3_CFG_STATUS_RxOOF){ + DEBUG_TE3("%s: (T3/E3) OOF Alarm ON!\n", + fe->name); + alarm |= WAN_TE3_BIT_OOF_ALARM; + }else{ + DEBUG_TE3("%s: (T3/E3) OOF Alarm OFF!\n", + fe->name); + alarm &= ~WAN_TE3_BIT_OOF_ALARM; + } + + if (value & BIT_RxE3_CFG_STATUS_RxLOF){ + DEBUG_TE3("%s: (T3/E3) LOF Alarm ON!\n", + fe->name); + alarm |= WAN_TE3_BIT_LOF_ALARM; + }else{ + DEBUG_TE3("%s: (T3/E3) LOF Alarm OFF!\n", + fe->name); + alarm &= ~WAN_TE3_BIT_LOF_ALARM; + } + + if (value & BIT_RxE3_CFG_STATUS_RxLOS){ + DEBUG_TE3("%s: (T3/E3) LOS Alarm ON!\n", + fe->name); + alarm |= WAN_TE3_BIT_LOS_ALARM; + }else{ + DEBUG_TE3("%s: (T3/E3) LOS Alarm OFF!\n", + fe->name); + alarm &= ~WAN_TE3_BIT_LOS_ALARM; + } + + if (value & BIT_RxE3_CFG_STATUS_RxAIS){ + DEBUG_TE3("%s: (T3/E3) AIS Alarm ON!\n", + fe->name); + alarm |= WAN_TE3_BIT_AIS_ALARM; + }else{ + DEBUG_TE3("%s: (T3/E3) AIS Alarm OFF!\n", + fe->name); + alarm &= ~WAN_TE3_BIT_AIS_ALARM; + } + + if (value & BIT_RxE3_CFG_STATUS_RxFERF){ + DEBUG_TE3("%s: (T3/E3) Rx FERF status is ON (YELLOW)!\n", + fe->name); + alarm |= WAN_TE3_BIT_YEL_ALARM; + }else{ + DEBUG_TE3("%s: (T3/E3) Rx FERF status is OFF!\n", + fe->name); + alarm &= ~WAN_TE3_BIT_YEL_ALARM; + } + } + + fe->fe_alarm = alarm; + if (update){ + sdla_te3_set_status(fe); + } + return alarm; +} + + +/****************************************************************************** + * sdla_te3_set_alarm() + * + * Description: + * Arguments: + * Returns: + ****************************************************************************** + */ +static int sdla_te3_set_alarm(sdla_fe_t *fe, unsigned int alarm) +{ + DEBUG_EVENT("%s: %s: This function is still not supported!\n", + fe->name, __FUNCTION__); + return -EINVAL; +} + +/****************************************************************************** + * sdla_te3_read_pmon() + * + * Description: + * Arguments: + * Returns: + ****************************************************************************** + */ +static int sdla_te3_read_pmon(sdla_fe_t *fe, int action) +{ + sdla_te3_pmon_t *pmon = (sdla_te3_pmon_t*)&fe->fe_stats.u.te3_pmon; + unsigned char value_msb, value_lsb; + + value_msb = READ_FRAMER(REG_PMON_LCV_MSB); + value_lsb = READ_FRAMER(REG_PMON_LCV_LSB); + pmon->pmon_lcv += ((value_msb << 8) | value_lsb); + + value_msb = READ_FRAMER(REG_PMON_FRAMING_ERR_CNT_MSB); + value_lsb = READ_FRAMER(REG_PMON_FRAMING_ERR_CNT_LSB); + pmon->pmon_framing += ((value_msb << 8) | value_lsb); + + value_msb = READ_FRAMER(REG_PMON_PARITY_ERR_CNT_MSB); + value_lsb = READ_FRAMER(REG_PMON_PARITY_ERR_CNT_LSB); + pmon->pmon_parity += ((value_msb << 8) | value_lsb); + + value_msb = READ_FRAMER(REG_PMON_FEBE_EVENT_CNT_MSB); + value_lsb = READ_FRAMER(REG_PMON_FEBE_EVENT_CNT_LSB); + pmon->pmon_febe += ((value_msb << 8) | value_lsb); + + value_msb = READ_FRAMER(REG_PMON_CPBIT_ERROR_CNT_MSB); + value_lsb = READ_FRAMER(REG_PMON_CPBIT_ERROR_CNT_LSB); + pmon->pmon_cpbit += ((value_msb << 8) | value_lsb); + return 0; +} + +/****************************************************************************** + * sdla_te3_udp() + * + * Description: + * Arguments: + * Returns: + ****************************************************************************** + */ +static int sdla_te3_udp(sdla_fe_t *fe, void *pudp_cmd, unsigned char *data) +{ + wan_cmd_t *udp_cmd = (wan_cmd_t*)pudp_cmd; + + switch(udp_cmd->wan_cmd_command){ + case WAN_GET_MEDIA_TYPE: + data[0] = fe->fe_cfg.media; + udp_cmd->wan_cmd_return_code = WAN_CMD_OK; + udp_cmd->wan_cmd_data_len = sizeof(unsigned char); + break; + + case WAN_FE_SET_LB_MODE: + /* Activate/Deactivate Line Loopback modes */ +// err = sdla_set_te1_lb_modes(card, data[0], data[1]); +// udp_cmd->wan_cmd_return_code = +// (!err) ? WAN_CMD_OK : WAN_UDP_FAILED_CMD; +// udp_cmd->wan_cmd_data_len = 0x00; + break; + + case WAN_FE_GET_STAT: + /* TE1_56K Read T1/E1/56K alarms */ +#if 0 + *(unsigned long *)&data[0] = sdla_te3_alarm(fe, 0); +#endif + /* TE1 Update T1/E1 perfomance counters */ + sdla_te3_read_pmon(fe, 0); + memcpy(&data[0], &fe->fe_stats, sizeof(sdla_fe_stats_t)); + udp_cmd->wan_cmd_return_code = WAN_CMD_OK; + udp_cmd->wan_cmd_data_len = sizeof(sdla_fe_stats_t); + break; + + case WAN_FE_FLUSH_PMON: + /* TE1 Flush T1/E1 pmon counters */ +// memset(&fe->fe_stats.u.te3_pmon, 0, sizeof(sdla_te3_pmon_t)); + udp_cmd->wan_cmd_return_code = WAN_CMD_OK; + break; + + case WAN_FE_GET_CFG: + /* Read T1/E1 configuration */ + memcpy(&data[0], + &fe->fe_cfg, + sizeof(sdla_fe_cfg_t)); + udp_cmd->wan_cmd_return_code = WAN_CMD_OK; + udp_cmd->wan_cmd_data_len = sizeof(sdla_te_cfg_t); + break; + + default: + udp_cmd->wan_cmd_return_code = WAN_UDP_INVALID_CMD; + udp_cmd->wan_cmd_data_len = 0; + break; + } + return 0; +} + +static int sdla_te3_set_intr(sdla_fe_t *fe) +{ + sdla_fe_cfg_t *fe_cfg = &fe->fe_cfg; + + /* Enable Framer Interrupts */ + /* 1. Block Interrupt Enable */ + WRITE_FRAMER(REG_BLOCK_INT_ENABLE, + BIT_BLOCK_INT_ENABLE_RxDS3_E3 | + BIT_BLOCK_INT_ENABLE_TxDS3_E3); + if (IS_DS3(fe_cfg)){ + /* 1. RxDS3 Interrupt Enable */ + WRITE_FRAMER(REG_RxDS3_INT_ENABLE, + BIT_RxDS3_INT_ENABLE_CPBIT_ERR | + BIT_RxDS3_INT_ENABLE_LOS | + BIT_RxDS3_INT_ENABLE_OOF | + BIT_RxDS3_INT_ENABLE_AIS | + BIT_RxDS3_INT_ENABLE_IDLE | + BIT_RxDS3_INT_ENABLE_FERF | + BIT_RxDS3_INT_ENABLE_AIC | + BIT_RxDS3_INT_ENABLE_PBIT_ERR ); + + /* RxDS3 FEAC */ + WRITE_FRAMER(REG_RxDS3_FEAC_INT, + BIT_RxDS3_FEAC_REMOVE_INT_EN | + BIT_RxDS3_FEAC_VALID_INT_EN); + + /* RxDS3 LAPD */ + WRITE_FRAMER(REG_TxDS3_LAPD_STATUS, + BIT_TxDS3_LAPD_STATUS_INT_EN); + + }else if (IS_E3(fe_cfg)){ + /* RxE3 Interrupt Enable 1 (0x12) */ + WRITE_FRAMER(REG_RxE3_INT_ENABLE_1, + BIT_RxE3_INT_ENABLE_OOF | + BIT_RxE3_INT_ENABLE_LOS | + BIT_RxE3_INT_ENABLE_LOF | + BIT_RxE3_INT_ENABLE_AIS); + + /* RxE3 Interrupt Enable 2 (0x13) */ + WRITE_FRAMER(REG_RxE3_INT_ENABLE_2, + BIT_RxE3_INT_ENABLE_FERF | + BIT_RxE3_INT_ENABLE_FRAMING); + }else{ + return -EINVAL; + } + + return 0; +} + + +/****************************************************************************** + * sdla_te3_liu_config() + * + * Description: Configure Sangoma TE3 board + * Arguments: + * Returns: WAN_TRUE - TE3 configred successfully, otherwise WAN_FALSE. + ****************************************************************************** + */ +static int sdla_te3_liu_config(sdla_fe_t *fe, sdla_te3_liu_cfg_t *liu, char *name) +{ + sdla_fe_cfg_t *fe_cfg = &fe->fe_cfg; + unsigned char data = 0x00; + + if (fe_cfg->media == WAN_MEDIA_E3){ + data |= BIT_CPLD_CNTRL_E3; + } + if (liu->rx_equal == WAN_TRUE){ + DEBUG_TE3("%s: (T3/E3) Enable Receive Equalizer\n", + name); + data |= BIT_CPLD_CNTRL_REQEN; + }else{ + DEBUG_TE3("%s: (T3/E3) Disable Receive Equalizer\n", + name); + data &= ~BIT_CPLD_CNTRL_REQEN; + } + if (liu->tx_lbo == WAN_TRUE){ + DEBUG_TE3("%s: (T3/E2) Enable Transmit Build-out\n", + name); + data |= BIT_CPLD_CNTRL_TxLEV; + }else{ + DEBUG_TE3("%s: (T3/E3) Disable Transmit Build-out\n", + name); + data &= ~BIT_CPLD_CNTRL_TxLEV; + } + /* Write value to CPLD Control register */ + WRITE_CPLD(REG_CPLD_CNTRL, data); + + data = 0x00; + if (liu->taos == WAN_TRUE){ + DEBUG_TE3("%s: (T3/E3) Enable Transmit All Ones\n", + name); + data |= BIT_CPLD_STATUS_TAOS; + }else{ + DEBUG_TE3("%s: (T3/E3) Disable Transmit All Ones\n", + name); + data &= ~BIT_CPLD_STATUS_TAOS; + } + switch(liu->lb_mode){ + case WAN_TE3_LIU_LB_NORMAL: + break; + case WAN_TE3_LIU_LB_ANALOG: + DEBUG_TE3("%s: (T3/E3) Enable Analog Loopback mode!\n", + name); + data |= BIT_CPLD_STATUS_LLB; + data &= ~BIT_CPLD_STATUS_RLB; + break; + case WAN_TE3_LIU_LB_REMOTE: + DEBUG_TE3("%s: (T3/E3) Enable Remote Loopback mode!\n", + name); + data &= ~BIT_CPLD_STATUS_LLB; + data |= BIT_CPLD_STATUS_RLB; + break; + case WAN_TE3_LIU_LB_DIGITAL: + DEBUG_TE3("%s: (T3/E3) Enable Digital Loopback mode!\n", + name); + data |= BIT_CPLD_STATUS_LLB; + data |= BIT_CPLD_STATUS_RLB; + break; + default : + DEBUG_EVENT("%s: (T3/E3) Unknown loopback mode!\n", + name); + break; + } + /* Write value to CPLD Status/Control register */ + WRITE_CPLD(REG_CPLD_STATUS, data); + return 0; +} + +int sdla_te3_iface_init(void *p_fe_iface) +{ + sdla_fe_iface_t *fe_iface = (sdla_fe_iface_t*)p_fe_iface; + + /* Inialize Front-End interface functions */ + fe_iface->config = &sdla_te3_config; + fe_iface->unconfig = &sdla_te3_unconfig; + fe_iface->polling = &sdla_te3_polling; + fe_iface->isr = &sdla_te3_isr; + fe_iface->process_udp = &sdla_te3_udp; + fe_iface->read_alarm = &sdla_te3_alarm; + fe_iface->read_pmon = &sdla_te3_read_pmon; + fe_iface->set_fe_alarm = &sdla_te3_set_alarm; + fe_iface->get_fe_status = &sdla_te3_get_fe_status; + fe_iface->get_fe_media = &sdla_te3_get_fe_media; + fe_iface->get_fe_media_string = &sdla_te3_get_fe_media_string; + fe_iface->update_alarm_info = &sdla_te3_update_alarm_info; + fe_iface->update_pmon_info = &sdla_te3_update_pmon_info; + + return 0; +} +static int sdla_te3_config(void *p_fe) +{ + sdla_fe_t *fe = (sdla_fe_t*)p_fe; + sdla_fe_cfg_t *fe_cfg = &fe->fe_cfg; + sdla_te3_cfg_t *te3_cfg = &fe_cfg->cfg.te3_cfg; + unsigned char data = 0x00; + + /* configure Line Interface Unit */ + sdla_te3_liu_config(fe, &te3_cfg->liu_cfg, fe->name); + + switch(fe_cfg->media){ + case WAN_MEDIA_DS3: + DEBUG_TE3("%s: (T3/E3) Media type DS3\n", + fe->name); + data |= BIT_OPMODE_DS3; + break; + case WAN_MEDIA_E3: + DEBUG_TE3("%s: (T3/E3) Media type E3\n", + fe->name); + data &= ~BIT_OPMODE_DS3; + break; + default: + DEBUG_EVENT("%s: Invalid Media type 0x%X\n", + fe->name,fe_cfg->media); + return -EINVAL; + } + + switch(fe_cfg->frame){ + case WAN_FR_E3_G751: + if (fe_cfg->media != WAN_MEDIA_E3){ + DEBUG_EVENT("%s: (T3/E3) Invalid Frame Format!\n", + fe->name); + return -EINVAL; + } + DEBUG_TE3("%s: (T3/E3) Frame type G.751\n", + fe->name); + data &= ~BIT_OPMODE_FRAME_FRMT; + break; + case WAN_FR_E3_G832: + if (fe_cfg->media != WAN_MEDIA_E3){ + DEBUG_EVENT("%s: (T3/E3) Invalid Frame Format!\n", + fe->name); + return -EINVAL; + } + DEBUG_TE3("%s: (T3/E3) Frame type G.832\n", + fe->name); + data |= BIT_OPMODE_FRAME_FRMT; + break; + case WAN_FR_DS3_Cbit: + if (fe_cfg->media != WAN_MEDIA_DS3){ + DEBUG_EVENT("%s: (T3/E3) Invalid Frame Format!\n", + fe->name); + return -EINVAL; + } + DEBUG_TE3("%s: (T3/E3) Frame type C-bit Parity\n", + fe->name); + data &= ~BIT_OPMODE_FRAME_FRMT; + break; + case WAN_FR_DS3_M13: + if (fe_cfg->media != WAN_MEDIA_DS3){ + DEBUG_EVENT("%s: (T3/E3) Invalid Frame Format!\n", + fe->name); + return -EINVAL; + } + DEBUG_TE3("%s: (T3/E3) Frame type M13\n", + fe->name); + data |= BIT_OPMODE_FRAME_FRMT; + break; + default: + DEBUG_EVENT("%s: Invalid Frame type 0x%X\n", + fe->name,fe_cfg->frame); + return -EINVAL; + } + data |= BIT_OPMODE_INTERNAL_LOS; + data |= (BIT_OPMODE_TIMREFSEL1 | BIT_OPMODE_TIMREFSEL0); + WRITE_FRAMER(REG_OPMODE, data); + + data = 0x00; + switch(fe_cfg->lcode){ + case WAN_LCODE_AMI: + DEBUG_TE3("%s: (T3/E3) Line code AMI\n", + fe->name); + data |= BIT_IO_CONTROL_AMI; + break; + case WAN_LCODE_HDB3: + DEBUG_TE3("%s: (T3/E3) Line code HDB3\n", + fe->name); + data &= ~BIT_IO_CONTROL_AMI; + break; + case WAN_LCODE_B3ZS: + DEBUG_TE3("%s: (T3/E3) Line code B3ZS\n", + fe->name); + data &= ~BIT_IO_CONTROL_AMI; + break; + default: + DEBUG_EVENT("%s: Invalid Lcode 0x%X\n", + fe->name,fe_cfg->lcode); + return -EINVAL; + } + data |= BIT_IO_CONTROL_DISABLE_TXLOC; + data |= BIT_IO_CONTROL_DISABLE_RXLOC; + data |= BIT_IO_CONTROL_RxLINECLK; + WRITE_FRAMER(REG_IO_CONTROL, data); + + /* Initialize Front-End parameters */ + fe->fe_status = FE_DISCONNECTED; + DEBUG_EVENT("%s: DS3 disconnected!\n", + fe->name); + sdla_te3_alarm(fe, 1); + + sdla_te3_set_intr(fe); + return 0; +} + +static int sdla_te3_unconfig(void *p_fe) +{ + sdla_fe_t *fe = (sdla_fe_t*)p_fe; + DEBUG_EVENT("%s: Unconfiguring T3/E3 interface\n", + fe->name); + return 0; +} + +static int +sdla_te3_update_alarm_info(sdla_fe_t* fe, struct seq_file* m, int* stop_cnt) +{ + if (IS_DS3(&fe->fe_cfg)){ + PROC_ADD_LINE(m, + "=============================== DS3 Alarms ===============================\n"); + PROC_ADD_LINE(m, + PROC_STATS_ALARM_FORMAT, + "AIS", WAN_TE3_AIS_ALARM(fe->fe_alarm), + "LOS", WAN_TE3_LOS_ALARM(fe->fe_alarm)); + PROC_ADD_LINE(m, + PROC_STATS_ALARM_FORMAT, + "OOF", WAN_TE3_OOF_ALARM(fe->fe_alarm), + "YEL", WAN_TE3_YEL_ALARM(fe->fe_alarm)); + }else{ + PROC_ADD_LINE(m, + "=============================== E3 Alarms ===============================\n"); + PROC_ADD_LINE(m, + PROC_STATS_ALARM_FORMAT, + "AIS", WAN_TE3_AIS_ALARM(fe->fe_alarm), + "LOS", WAN_TE3_LOS_ALARM(fe->fe_alarm)); + PROC_ADD_LINE(m, + PROC_STATS_ALARM_FORMAT, + "OFF", WAN_TE3_OOF_ALARM(fe->fe_alarm), + "YEL", WAN_TE3_YEL_ALARM(fe->fe_alarm)); + PROC_ADD_LINE(m, + PROC_STATS_ALARM_FORMAT, + "LOF", WAN_TE3_LOF_ALARM(fe->fe_alarm), + "", ""); + } + + return m->count; +} + +static int sdla_te3_update_pmon_info(sdla_fe_t* fe, struct seq_file* m, int* stop_cnt) +{ + PROC_ADD_LINE(m, + "=========================== %s PMON counters ============================\n", + (IS_DS3(&fe->fe_cfg)) ? "DS3" : "E3"); + PROC_ADD_LINE(m, + PROC_STATS_PMON_FORMAT, + "Line Code Violation", fe->fe_stats.u.te3_pmon.pmon_lcv, + "Framing Bit/Byte Error", fe->fe_stats.u.te3_pmon.pmon_framing); + if (IS_DS3(&fe->fe_cfg)){ + if (fe->fe_cfg.frame == WAN_FR_DS3_Cbit){ + PROC_ADD_LINE(m, + PROC_STATS_PMON_FORMAT, + "Parity Error", fe->fe_stats.u.te3_pmon.pmon_parity, + "CP-Bit Error Event", fe->fe_stats.u.te3_pmon.pmon_cpbit); + }else{ + PROC_ADD_LINE(m, + PROC_STATS_PMON_FORMAT, + "Parity Error", fe->fe_stats.u.te3_pmon.pmon_parity, + "FEBE Event", fe->fe_stats.u.te3_pmon.pmon_febe); + + } + }else{ + PROC_ADD_LINE(m, + PROC_STATS_PMON_FORMAT, + "Parity Error", fe->fe_stats.u.te3_pmon.pmon_parity, + "FEBE Event", fe->fe_stats.u.te3_pmon.pmon_febe); + } + + return m->count; +} diff -Nur linux.org/drivers/net/wan/sdla_x25.c linux-2.6.17/drivers/net/wan/sdla_x25.c --- linux.org/drivers/net/wan/sdla_x25.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/drivers/net/wan/sdla_x25.c 2006-08-30 10:07:16.000000000 +0000 @@ -0,0 +1,7912 @@ +/***************************************************************************** +* sdla_x25.c WANPIPE(tm) Multiprotocol WAN Link Driver. X.25 module. +* +* Author: Nenad Corbic +* +* Copyright: (c) 1995-2003 Sangoma Technologies Inc. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version +* 2 of the License, or (at your option) any later version. +* ============================================================================ +* Jul 11, 2003 Nenad Corbic o Update the x25 driver to interface to the new +* api layer. +* Jul 10, 2003 Nenad Corbic o Bug fix: tx frames greater than max packet size +* A duplicate frame was generated due to the +* bug in setup_for_delayed_transmit() function. +* Solution: Tx frames > MTX via tx interrupt. +* Jul 19, 2002 Nenad Corbic o Tx offset initialized in setup_for_delayed_transmit() +* Caused problems if previous frame faild to send. +* Jan 15, 2002 Nenad Corbic o Expanded OOB message reporting to all async +* messages. +* Dec 05, 2001 Nenad Corbic o Bug fix: channel_disconnect() function missed +* an event and marked channel inactive before +* clearing call. +* Oct 10, 2001 Nenad Corbic o Added the dev->do_ioctl function to replace +* the poll_active() function during API operation. +* The API commands are not polled any more, but +* executed in priority through a tx interrupt. +* Sep 20, 2001 Nenad Corbic o The min() function has changed for 2.4.9 +* kernel. Thus using the wp_min() defined in +* wanpipe.h +* Sept 6, 2001 Alex Feldman o Add SNMP support. +* Apr 26, 2001 David Rokhvarg o Added pattern matching on call accept. +* Apr 16, 2001 David Rokhvarg o Fixed auto call accept: user_data filed is +* check as char. +* Apr 03, 2001 Nenad Corbic o Fixed the rx_skb=NULL bug in x25 in rx_intr(). +* Dec 26, 2000 Nenad Corbic o Added a new polling routine, that uses +* a kernel timer (more efficient). +* Dec 25, 2000 Nenad Corbic o Updated for 2.4.X kernel +* Jul 26, 2000 Nenad Corbic o Increased the local packet buffering +* for API to 4096+header_size. +* Jul 17, 2000 Nenad Corbic o Fixed the x25 startup bug. Enable +* communications only after all interfaces +* come up. HIGH SVC/PVC is used to calculate +* the number of channels. +* Enable protocol only after all interfaces +* are enabled. +* Jul 10, 2000 Nenad Corbic o Fixed the M_BIT bug. +* Apr 25, 2000 Nenad Corbic o Pass Modem messages to the API. +* Disable idle timeout in X25 API. +* Apr 14, 2000 Nenad Corbic o Fixed: Large LCN number support. +* Maximum LCN number is 4095. +* Maximum number of X25 channels is 255. +* Apr 06, 2000 Nenad Corbic o Added SMP Support. +* Mar 29, 2000 Nenad Corbic o Added support for S514 PCI Card +* Mar 23, 2000 Nenad Corbic o Improved task queue, BH handling. +* Mar 14, 2000 Nenad Corbic o Updated Protocol Violation handling +* routines. Bug Fix. +* Mar 10, 2000 Nenad Corbic o Bug Fix: corrupted box recovery. +* Mar 09, 2000 Nenad Corbic o Fixed the auto HDLC bug. +* Mar 08, 2000 Nenad Corbic o Fixed LAPB HDLC startup problems. +* Application must bring the link up +* before tx/rx, and bring the +* link down on close(). +* Mar 06, 2000 Nenad Corbic o Added an option for logging call setup +* information. +* Feb 29, 2000 Nenad Corbic o Added support for LAPB HDLC API +* Feb 25, 2000 Nenad Corbic o Fixed the modem failure handling. +* No Modem OOB message will be passed +* to the user. +* Feb 21, 2000 Nenad Corbic o Added Xpipemon Debug Support +* Dec 30, 1999 Nenad Corbic o Socket based X25API +* Sep 17, 1998 Jaspreet Singh o Updates for 2.2.X kernel +* Mar 15, 1998 Alan Cox o 2.1.x porting +* Dec 19, 1997 Jaspreet Singh o Added multi-channel IPX support +* Nov 27, 1997 Jaspreet Singh o Added protection against enabling of irqs +* when they are disabled. +* Nov 17, 1997 Farhan Thawar o Added IPX support +* o Changed if_send() to now buffer packets when +* the board is busy +* o Removed queueing of packets via the polling +* routing +* o Changed if_send() critical flags to properly +* handle race conditions +* Nov 06, 1997 Farhan Thawar o Added support for SVC timeouts +* o Changed PVC encapsulation to ETH_P_IP +* Jul 21, 1997 Jaspreet Singh o Fixed freeing up of buffers using kfree() +* when packets are received. +* Mar 11, 1997 Farhan Thawar Version 3.1.1 +* o added support for V35 +* o changed if_send() to return 0 if +* wandev.critical() is true +* o free socket buffer in if_send() if +* returning 0 +* o added support for single '@' address to +* accept all incoming calls +* o fixed bug in set_chan_state() to disconnect +* Jan 15, 1997 Gene Kozin Version 3.1.0 +* o implemented exec() entry point +* Jan 07, 1997 Gene Kozin Initial version. +*****************************************************************************/ + +/*====================================================== + * Includes + *=====================================================*/ + + +#include +#include +#include /* WAN router definitions */ +#include /* WANPIPE common user API definitions */ +#include +#include +#include +#include /* X.25 firmware API definitions */ +#include +#include + + +/*====================================================== + * Defines & Macros + *=====================================================*/ + + +#define CMD_OK 0 /* normal firmware return code */ +#define CMD_TIMEOUT 0xFF /* firmware command timed out */ +#define MAX_CMD_RETRY 10 /* max number of firmware retries */ + +#define X25_CHAN_MTU 4096 /* unfragmented logical channel MTU */ +#define X25_HRDHDR_SZ 7 /* max encapsulation header size */ +#define X25_CONCT_TMOUT (90*HZ) /* link connection timeout */ +#define X25_RECON_TMOUT (10*HZ) /* link connection timeout */ +#define CONNECT_TIMEOUT (90*HZ) /* link connection timeout */ +#define HOLD_DOWN_TIME (30*HZ) /* link hold down time */ +#define MAX_BH_BUFF 10 + +#undef PRINT_DEBUG +#ifdef PRINT_DEBUG +#define DBG_PRINTK(format, a...) printk(format, ## a) +#else +#define DBG_PRINTK(format, a...) +#endif + +#define TMR_INT_ENABLED_POLL_ACTIVE 0x01 +#define TMR_INT_ENABLED_POLL_CONNECT_ON 0x02 +#define TMR_INT_ENABLED_POLL_CONNECT_OFF 0x04 +#define TMR_INT_ENABLED_POLL_DISCONNECT 0x08 +#define TMR_INT_ENABLED_CMD_EXEC 0x10 +#define TMR_INT_ENABLED_UPDATE 0x20 +#define TMR_INT_ENABLED_UDP_PKT 0x40 + +#define MAX_X25_ADDR_SIZE 16 +#define MAX_X25_DATA_SIZE 129 +#define MAX_X25_FACL_SIZE 110 + +#define TRY_CMD_AGAIN 2 +#define DELAY_RESULT 1 +#define RETURN_RESULT 0 + +#define DCD(x) (x & X25_DCD_MASK ? "Up" : "Down") +#define CTS(x) (x & X25_CTS_MASK ? "Up" : "Down") + +#define MAX_X25_TRACE_QUEUE 100 + +/* Private critical flags */ +enum { + POLL_CRIT = PRIV_CRIT +}; + +/* Driver will not write log messages about + * modem status if defined.*/ +#undef MODEM_NOT_LOG + +/*==================================================== + * For IPXWAN + *===================================================*/ + +#define CVHexToAscii(b) (((unsigned char)(b) > (unsigned char)9) ? ((unsigned char)'A' + ((unsigned char)(b) - (unsigned char)10)) : ((unsigned char)'0' + (unsigned char)(b))) + + +/*==================================================== + * MEMORY DEBUGGING FUNCTION + *==================================================== + +#define KMEM_SAFETYZONE 8 + +static void * dbg_kmalloc(unsigned int size, int prio, int line) { + int i = 0; + void * v = kmalloc(size+sizeof(unsigned int)+2*KMEM_SAFETYZONE*8,prio); + char * c1 = v; + c1 += sizeof(unsigned int); + *((unsigned int *)v) = size; + + for (i = 0; i < KMEM_SAFETYZONE; i++) { + c1[0] = 'D'; c1[1] = 'E'; c1[2] = 'A'; c1[3] = 'D'; + c1[4] = 'B'; c1[5] = 'E'; c1[6] = 'E'; c1[7] = 'F'; + c1 += 8; + } + c1 += size; + for (i = 0; i < KMEM_SAFETYZONE; i++) { + c1[0] = 'M'; c1[1] = 'U'; c1[2] = 'N'; c1[3] = 'G'; + c1[4] = 'W'; c1[5] = 'A'; c1[6] = 'L'; c1[7] = 'L'; + c1 += 8; + } + v = ((char *)v) + sizeof(unsigned int) + KMEM_SAFETYZONE*8; + printk(KERN_INFO "line %d kmalloc(%d,%d) = %p\n",line,size,prio,v); + return v; +} +static void dbg_kfree(void * v, int line) { + unsigned int * sp = (unsigned int *)(((char *)v) - (sizeof(unsigned int) + KMEM_SAFETYZONE*8)); + unsigned int size = *sp; + char * c1 = ((char *)v) - KMEM_SAFETYZONE*8; + int i = 0; + for (i = 0; i < KMEM_SAFETYZONE; i++) { + if ( c1[0] != 'D' || c1[1] != 'E' || c1[2] != 'A' || c1[3] != 'D' + || c1[4] != 'B' || c1[5] != 'E' || c1[6] != 'E' || c1[7] != 'F') { + printk(KERN_INFO "kmalloced block at %p has been corrupted (underrun)!\n",v); + printk(KERN_INFO " %4x: %2x %2x %2x %2x %2x %2x %2x %2x\n", i*8, + c1[0],c1[1],c1[2],c1[3],c1[4],c1[5],c1[6],c1[7] ); + } + c1 += 8; + } + c1 += size; + for (i = 0; i < KMEM_SAFETYZONE; i++) { + if ( c1[0] != 'M' || c1[1] != 'U' || c1[2] != 'N' || c1[3] != 'G' + || c1[4] != 'W' || c1[5] != 'A' || c1[6] != 'L' || c1[7] != 'L' + ) { + printk(KERN_INFO "kmalloced block at %p has been corrupted (overrun):\n",v); + printk(KERN_INFO " %4x: %2x %2x %2x %2x %2x %2x %2x %2x\n", i*8, + c1[0],c1[1],c1[2],c1[3],c1[4],c1[5],c1[6],c1[7] ); + } + c1 += 8; + } + printk(KERN_INFO "line %d kfree(%p)\n",line,v); + v = ((char *)v) - (sizeof(unsigned int) + KMEM_SAFETYZONE*8); + kfree(v); +} + +#define kmalloc(x,y) dbg_kmalloc(x,y,__LINE__) +#define kfree(x) dbg_kfree(x,__LINE__) + +==============================================================*/ + + + +/*=============================================== + * Data Structures + *===============================================*/ + + +/*======================================================== + * Name: x25_channel + * + * Purpose: To hold private informaton for each + * logical channel. + * + * Rationale: Per-channel debugging is possible if each + * channel has its own private area. + * + * Assumptions: + * + * Description: This is an extention of the 'netdevice_t' + * we create for each network interface to keep + * the rest of X.25 channel-specific data. + * + * Construct: Typedef + */ +typedef struct x25_channel +{ + wanpipe_common_t common; /* common area for x25api and socket */ + char name[WAN_IFNAME_SZ+1]; /* interface name, ASCIIZ */ + char addr[WAN_ADDRESS_SZ+1]; /* media address, ASCIIZ */ + unsigned tx_pkt_size; + unsigned short protocol; /* ethertype, 0 - multiplexed */ + char drop_sequence; /* mark sequence for dropping */ + unsigned long state_tick; /* time of the last state change */ + unsigned idle_timeout; /* sec, before disconnecting */ + unsigned long i_timeout_sofar; /* # of sec's we've been idle */ + unsigned hold_timeout; /* sec, before re-connecting */ + unsigned long tick_counter; /* counter for transmit time out */ + char devtint; /* Weather we should dev_tint() */ + struct sk_buff* rx_skb; /* receive socket buffer */ + struct sk_buff* tx_skb; /* transmit socket buffer */ + + sdla_t* card; /* -> owner */ + + int ch_idx; + unsigned char enable_IPX; + unsigned long network_number; + struct net_device_stats ifstats; /* interface statistics */ + + unsigned short transmit_length; + unsigned short tx_offset; + char transmit_buffer[X25_CHAN_MTU+sizeof(x25api_hdr_t)]; + + if_send_stat_t if_send_stat; + rx_intr_stat_t rx_intr_stat; + pipe_mgmt_stat_t pipe_mgmt_stat; + + unsigned long router_start_time; /* Router start time in seconds */ + unsigned long router_up_time; + + char x25_src_addr[WAN_ADDRESS_SZ+1]; /* x25 media source address, + ASCIIZ */ + char accept_dest_addr[WAN_ADDRESS_SZ+1]; /* pattern match string in -d + for accepting calls, ASCIIZ */ + char accept_src_addr[WAN_ADDRESS_SZ+1]; /* pattern match string in -s + for accepting calls, ASCIIZ */ + char accept_usr_data[WAN_ADDRESS_SZ+1];/* pattern match string in -u + for accepting calls, ASCIIZ */ + + /* Entry in proc fs per each interface */ + struct proc_dir_entry* dent; + int chan_direct; + unsigned long chan_establ_time; + unsigned long chan_clear_time; + unsigned char chan_clear_cause; + unsigned char chan_clear_diagn; + char cleared_called_addr[MAX_X25_ADDR_SIZE]; + char cleared_calling_addr[MAX_X25_ADDR_SIZE]; + char cleared_facil[MAX_X25_ADDR_SIZE]; + + unsigned char critical; + + unsigned char call_string[X25_CALL_STR_SZ+1]; + x25api_t x25_api_event; + x25api_hdr_t x25_api_cmd_hdr; + x25api_hdr_t x25_api_tx_hdr; + + unsigned char label [WAN_IF_LABEL_SZ+1]; + unsigned char dlabel [WAN_IF_LABEL_SZ+1]; + + unsigned char used; + pid_t pid; + unsigned long api_state; + spinlock_t lock; + atomic_t cmd_rc; + unsigned long cmd_timeout; + +} x25_channel_t; + +/* FIXME Take this out */ + +#ifdef NEX_OLD_CALL_INFO +typedef struct x25_call_info +{ + char dest[17]; PACKED;/* ASCIIZ destination address */ + char src[17]; PACKED;/* ASCIIZ source address */ + char nuser; PACKED;/* number of user data bytes */ + unsigned char user[127]; PACKED;/* user data */ + char nfacil; PACKED;/* number of facilities */ + struct + { + unsigned char code; PACKED; + unsigned char parm; PACKED; + } facil[64]; /* facilities */ +} x25_call_info_t; +#else +typedef struct x25_call_info +{ + char dest[MAX_X25_ADDR_SIZE] PACKED;/* ASCIIZ destination address */ + char src[MAX_X25_ADDR_SIZE] PACKED;/* ASCIIZ source address */ + unsigned char nuser PACKED; + unsigned char user[MAX_X25_DATA_SIZE] PACKED;/* user data */ + unsigned char nfacil PACKED; + unsigned char facil[MAX_X25_FACL_SIZE] PACKED; + unsigned short lcn PACKED; +} x25_call_info_t; +#endif + + + +/*=============================================== + * Private Function Prototypes + *==============================================*/ + + +/*================================================= + * WAN link driver entry points. These are + * called by the WAN router module. + */ +static int update (wan_device_t* wandev); +static int new_if (wan_device_t* wandev, netdevice_t* dev, + wanif_conf_t* conf); +static int del_if (wan_device_t* wandev, netdevice_t* dev); +static void disable_comm (sdla_t* card); +static void disable_comm_shutdown(sdla_t *card); + + + +/*================================================= + * WANPIPE-specific entry points + */ +static void x25api_bh (unsigned long data); +static void wakeup_sk_bh (netdevice_t *dev); + + +/*================================================= + * Network device interface + */ +static int if_init (netdevice_t* dev); +static int if_open (netdevice_t* dev); +static int if_close (netdevice_t* dev); +static int if_send (struct sk_buff* skb, netdevice_t* dev); +static struct net_device_stats *if_stats (netdevice_t* dev); + +static void if_tx_timeout (netdevice_t *dev); + +/*================================================= + * Interrupt handlers + */ +static void wpx_isr (sdla_t *); +static void rx_intr (sdla_t *); +static void tx_intr (sdla_t *); +static void status_intr (sdla_t *); +static void event_intr (sdla_t *); +static void spur_intr (sdla_t *); +static void timer_intr (sdla_t *); +static void trace_intr (sdla_t *); + + +static int tx_intr_send(sdla_t *, netdevice_t *); +static netdevice_t * move_dev_to_next (sdla_t *, netdevice_t *); + +/*================================================= + * Background polling routines + */ +static void wpx_poll (void*); +static void poll_disconnected (sdla_t* card); +static void poll_connecting (sdla_t* card); +static void poll_active (sdla_t* card); +static void trigger_x25_poll(sdla_t *card); +static void x25_timer_routine(unsigned long data); + + + +/*================================================= + * X.25 firmware interface functions + */ +static int x25_get_version (sdla_t* card, char* str); +static int x25_configure (sdla_t* card, TX25Config* conf); +static int hdlc_configure (sdla_t* card, TX25Config* conf); +static int set_hdlc_level (sdla_t* card); +static int x25_get_err_stats (sdla_t* card); +static int x25_get_stats (sdla_t* card); +static int x25_set_intr_mode (sdla_t* card, int mode); +static int x25_close_hdlc (sdla_t* card); +static int x25_open_hdlc (sdla_t* card); +static int x25_setup_hdlc (sdla_t* card); +static int x25_set_dtr (sdla_t* card, int dtr); +static int x25_get_chan_conf (sdla_t* card, x25_channel_t* chan); +static int x25_place_call (sdla_t* card, x25_channel_t* chan); +static int x25_accept_call (sdla_t* card, int lcn, int qdm, unsigned char *data, int len); +static int x25_interrupt (sdla_t* card, int lcn, int qdm, unsigned char *data, int len); +static int x25_clear_call (sdla_t* card, int lcn, int cause, int diagn, int qdm, unsigned char *data, int len); +static int x25_reset_call (sdla_t* card, int lcn, int cause, int diagn, int qdm); +static int x25_send (sdla_t* card, int lcn, int qdm, int len, void* buf); +static int x25_fetch_events (sdla_t* card); +static int x25_error (sdla_t* card, int err, int cmd, int lcn); +static int is_match_found(unsigned char info[], unsigned char chan[]); + +/*================================================= + * X.25 asynchronous event handlers + */ +static int incoming_call (sdla_t* card, int cmd, int lcn, wan_mbox_t* mb); +static int call_accepted (sdla_t* card, int cmd, int lcn, wan_mbox_t* mb); +static int call_cleared (sdla_t* card, int cmd, int lcn, wan_mbox_t* mb); +static int timeout_event (sdla_t* card, int cmd, int lcn, wan_mbox_t* mb); +static int restart_event (sdla_t* card, int cmd, int lcn, wan_mbox_t* mb); +static int x25_down_event (sdla_t* card, int cmd, int lcn, wan_mbox_t* mb, unsigned char); + + + + +/*================================================= + * Miscellaneous functions + */ +static int connect (sdla_t* card); +static int disconnect (sdla_t* card); +static netdevice_t* get_dev_by_lcn(wan_device_t* wandev, unsigned lcn); +static int chan_connect (netdevice_t* dev); +static int chan_disc (netdevice_t* dev); +static void set_chan_state (netdevice_t* dev, int state); +static int chan_send (netdevice_t* , void* , unsigned, unsigned char); +static unsigned char bps_to_speed_code (unsigned long bps); +static unsigned int dec_to_uint (unsigned char* str, int len); +static unsigned int hex_to_uint (unsigned char*, int); +static void parse_call_info (unsigned char*, x25_call_info_t*); +static netdevice_t * find_channel(sdla_t *, unsigned); +static void bind_lcn_to_dev (sdla_t *, netdevice_t *,unsigned); +static void setup_for_delayed_transmit (netdevice_t*, void*, unsigned); +static int baud_rate_check (int baud); +static int lapb_connect(sdla_t *card, x25_channel_t *chan); + +/*================================================= + * X25 API Functions + */ +static int wanpipe_pull_data_in_skb (sdla_t *, netdevice_t *, struct sk_buff **); +static void trigger_intr_exec(sdla_t *, unsigned char); +static int execute_delayed_cmd (sdla_t*, netdevice_t *, char); +static int api_incoming_call (sdla_t*, wan_mbox_t *, int); +static int alloc_and_init_skb_buf (sdla_t *,struct sk_buff **, int); +static int clear_confirm_event (sdla_t *, wan_mbox_t*); +static int send_oob_msg (sdla_t *, netdevice_t *, wan_mbox_t *); +static int tx_intr_cmd_exec(sdla_t *card); +static void api_oob_event (sdla_t *card,wan_mbox_t *mbox); +static int check_bad_command (sdla_t *, netdevice_t *); +#if 0 +static void hdlc_link_down (sdla_t*); +#endif + +/*================================================= + * XPIPEMON Functions + */ +static int process_udp_mgmt_pkt(sdla_t *,netdevice_t*); +static int udp_pkt_type( struct sk_buff *, sdla_t*); +static int reply_udp( unsigned char *, unsigned int); +static void init_x25_channel_struct( x25_channel_t *); +static void init_global_statistics( sdla_t *); +static int store_udp_mgmt_pkt(int, char, sdla_t*, netdevice_t *, struct sk_buff *, int); +static unsigned short calc_checksum (char *, int); + + + +/*================================================= + * IPX functions + */ +static void switch_net_numbers(unsigned char *, unsigned long, unsigned char); +static int handle_IPXWAN(unsigned char *, char *, unsigned char , + unsigned long , unsigned short ); + +extern void disable_irq(unsigned int); +extern void enable_irq(unsigned int); + +static void S508_S514_lock(sdla_t *, unsigned long *); +static void S508_S514_unlock(sdla_t *, unsigned long *); + +/*================================================= + * PROC fs functions + */ +static void x25_clear_cmd_update(sdla_t* card, unsigned lcn, wan_mbox_t* mb); + +static int x25_get_config_info(void* priv, struct seq_file* m, int* stop_cnt); +static int x25_get_status_info(void* priv, struct seq_file* m, int* stop_cnt); +static int x25_set_dev_config(struct file*, const char*, unsigned long, void *); +static int x25_set_if_info(struct file*, const char*, unsigned long, void *); + +/* SNMP */ +static int x25_snmp_data(sdla_t* card, netdevice_t *dev, void* data); + +static int bind_api_to_svc(sdla_t *card, void *sk_id); +static int x25_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd); +static int x25_api_cmd_setup(x25_channel_t *chan, struct ifreq *ifr); +static int x25_api_setup_cmd_hdr(x25_channel_t *chan, struct ifreq *ifr); +static int x25_api_setup_call_string(x25_channel_t *chan, struct ifreq *ifr); +static int x25_api_get_cmd_result(x25_channel_t *chan, struct ifreq *ifr); +static void x25_update_api_state(sdla_t *card,x25_channel_t *chan); +static netdevice_t *find_free_svc_dev(sdla_t *card); +static void release_svc_dev(sdla_t *card, netdevice_t *dev); +static int wait_for_cmd_rc(sdla_t *card, x25_channel_t* chan); +static int test_chan_command_busy(sdla_t *card,x25_channel_t *chan); + + + +/*================================================= + * Global Variables + *=================================================*/ +static TX25Stats X25Stats; + + + +/*================================================= + * Public Functions + *=================================================*/ + + + + +/*=================================================================== + * wpx_init: X.25 Protocol Initialization routine. + * + * Purpose: To initialize the protocol/firmware. + * + * Rationale: This function is called by setup() function, in + * sdlamain.c, to dynamically setup the x25 protocol. + * This is the first protocol specific function, which + * executes once on startup. + * + * Description: This procedure initializes the x25 firmware and + * sets up the mailbox, transmit and receive buffer + * pointers. It also initializes all debugging structures + * and sets up the X25 environment. + * + * Sets up hardware options defined by user in [wanpipe#] + * section of wanpipe#.conf configuration file. + * + * At this point adapter is completely initialized + * and X.25 firmware is running. + * o read firmware version (to make sure it's alive) + * o configure adapter + * o initialize protocol-specific fields of the + * adapter data space. + * + * Called by: setup() function in sdlamain.c + * + * Assumptions: None + * + * Warnings: None + * + * Return: 0 o.k. + * < 0 failure. + */ + +int wpx_init (sdla_t* card, wandev_conf_t* conf) +{ + int err; + union{ + char str[80]; + TX25Config cfg; + } u; + wan_x25_conf_t* x25_adm_conf = &card->u.x.x25_adm_conf; + wan_x25_conf_t* x25_conf = &card->u.x.x25_conf; + + /* Verify configuration ID */ + if (conf->config_id != WANCONFIG_X25){ + printk(KERN_INFO "%s: invalid configuration ID %u!\n", + card->devname, conf->config_id) + ; + return -EINVAL; + } + + /* Initialize protocol-specific fields */ + /* Alex Apr 8 2004 Sangoma ISA card */ + card->mbox_off = X25_MB_VECTOR + X25_MBOX_OFFS; + card->rxmb_off = X25_MB_VECTOR + X25_RXMBOX_OFFS; + card->flags_off = X25_MB_VECTOR + X25_STATUS_OFFS; + + card->intr_type_off = card->flags_off + offsetof(TX25Status, iflags); + card->intr_perm_off = card->flags_off + offsetof(TX25Status, imask); + + /* Read firmware version. Note that when adapter initializes, it + * clears the mailbox, so it may appear that the first command was + * executed successfully when in fact it was merely erased. To work + * around this, we execute the first command twice. + */ + if (x25_get_version(card, NULL) || x25_get_version(card, u.str)) + return -EIO; + + + /* X25 firmware can run ether in X25 or LAPB HDLC mode. + * Check the user defined option and configure accordingly */ + if (conf->u.x25.LAPB_hdlc_only == WANOPT_YES){ + if (set_hdlc_level(card) != CMD_OK){ + return -EIO; + }else{ + printk(KERN_INFO "%s: running LAP_B HDLC firmware v%s\n", + card->devname, u.str); + } + card->u.x.LAPB_hdlc = 1; + }else{ + printk(KERN_INFO "%s: running X.25 firmware v%s\n", + card->devname, u.str); + card->u.x.LAPB_hdlc = 0; + } + + /* Copy Admin configuration to sdla_t structure */ + memcpy(x25_adm_conf, &conf->u.x25, sizeof(wan_x25_conf_t)); + + if (!x25_adm_conf->cmd_retry_timeout){ + x25_adm_conf->cmd_retry_timeout=5; + } + + DEBUG_EVENT("%s: X25 cmd retry timeout = %i sec\n", + card->devname, + x25_adm_conf->cmd_retry_timeout); + + card->wandev.ignore_front_end_status = conf->ignore_front_end_status; + + if (card->wandev.ignore_front_end_status == WANOPT_NO){ + printk(KERN_INFO + "%s: Enabling front end link monitor\n", + card->devname); + }else{ + printk(KERN_INFO + "%s: Disabling front end link monitor\n", + card->devname); + } + + /* Configure adapter. Here we set resonable defaults, then parse + * device configuration structure and set configuration options. + * Most configuration options are verified and corrected (if + * necessary) since we can't rely on the adapter to do so. + */ + memset(&u.cfg, 0, sizeof(u.cfg)); + u.cfg.t1 = 3; + u.cfg.n2 = 10; + u.cfg.autoHdlc = 1; /* automatic HDLC connection */ + u.cfg.hdlcWindow = 7; + u.cfg.pktWindow = X25_PACKET_WINDOW; + u.cfg.station = X25_STATION_DTE; /* DTE */ + u.cfg.options = 0x0090; /* disable D-bit pragmatics */ + u.cfg.ccittCompat = 1988; + u.cfg.t10t20 = 30; + u.cfg.t11t21 = 30; + u.cfg.t12t22 = 30; + u.cfg.t13t23 = 30; + u.cfg.t16t26 = 30; + u.cfg.t28 = 30; + u.cfg.r10r20 = 5; + u.cfg.r12r22 = 5; + u.cfg.r13r23 = 5; + u.cfg.responseOpt = 1; /* RR's after every packet */ + + + if (conf->u.x25.x25_conf_opt){ + u.cfg.options = conf->u.x25.x25_conf_opt; + } + + if (conf->clocking != WANOPT_EXTERNAL) + u.cfg.baudRate = bps_to_speed_code(conf->bps); + + if (conf->u.x25.station != WANOPT_DTE){ + u.cfg.station = 0; /* DCE mode */ + } + + if (conf->interface != WANOPT_RS232 ){ + u.cfg.hdlcOptions |= 0x80; /* V35 mode */ + } + + card->wandev.mtu = conf->mtu; + + if (!conf->u.x25.defPktSize){ + conf->u.x25.defPktSize = 1024; + DEBUG_EVENT("%s: Defaulting X25 Def Pkt Size to 1024!\n", + card->devname); + } + + err=baud_rate_check(conf->u.x25.defPktSize); + if (err!=0){ + DEBUG_EVENT("%s: Invalid Def Pkt Size %i\n", + card->devname,conf->u.x25.defPktSize); + return err; + } + + if (!conf->u.x25.pktMTU){ + conf->u.x25.pktMTU = 1024; + DEBUG_EVENT("%s: Defaulting X25 Max Pkt Size to 1024!\n", + card->devname); + } + + err=baud_rate_check(conf->u.x25.pktMTU); + if (err!=0){ + DEBUG_EVENT("%s: Invalid Def Pkt Size %i\n", + card->devname,conf->u.x25.defPktSize); + return err; + } + + + if (conf->u.x25.pktMTU > card->wandev.mtu){ + DEBUG_EVENT("%s: Invalid IP MTU %i: Lower than X25 Max Pkt Size %i!\n", + card->devname,card->wandev.mtu,conf->u.x25.pktMTU); + return -EINVAL; + } + + u.cfg.pktMTU = conf->u.x25.pktMTU; + u.cfg.defPktSize = conf->u.x25.defPktSize; + + if (!card->u.x.LAPB_hdlc){ + DEBUG_EVENT("%s: Configuring: X25/LapB \n",card->devname); + DEBUG_EVENT("%s: X25 Station = %s\n", + card->devname,X25_STATION_DECODE(conf->u.x25.station)); + DEBUG_EVENT("%s: X25 DefPktSize = %d\n", + card->devname,conf->u.x25.defPktSize); + DEBUG_EVENT("%s: X25 MaxPktSize = %d\n", + card->devname,conf->u.x25.pktMTU); + DEBUG_EVENT("%s: X25 Window = %d\n", + card->devname,conf->u.x25.pkt_window); + DEBUG_EVENT("%s: LapB Window = %d\n", + card->devname,conf->u.x25.hdlc_window); + } + + if (card->u.x.LAPB_hdlc){ + DEBUG_EVENT("%s: Configuring: LapB \n",card->devname); + DEBUG_EVENT("%s: LapB Station = %s\n", + card->devname,X25_STATION_DECODE(conf->u.x25.station)); + DEBUG_EVENT("%s: LapB Pkt Size = %d\n", + card->devname,u.cfg.defPktSize); + DEBUG_EVENT("%s: LapB Window = %d\n", + card->devname,conf->u.x25.hdlc_window); + u.cfg.hdlcMTU = u.cfg.defPktSize; + } + + if (conf->u.x25.hi_pvc){ + card->u.x.x25_conf.hi_pvc = + wp_min(conf->u.x25.hi_pvc, MAX_LCN_NUM); + card->u.x.x25_conf.lo_pvc = + wp_min(conf->u.x25.lo_pvc, card->u.x.x25_conf.hi_pvc); + } + + if (conf->u.x25.hi_svc){ + card->u.x.x25_conf.hi_svc = + wp_min(conf->u.x25.hi_svc, MAX_LCN_NUM); + card->u.x.x25_conf.lo_svc = + wp_min(conf->u.x25.lo_svc, card->u.x.x25_conf.hi_svc); + } + + /* Figure out the total number of channels to configure */ + card->u.x.num_of_ch = 0; + if (card->u.x.x25_conf.hi_svc != 0){ + card->u.x.num_of_ch = + (card->u.x.x25_conf.hi_svc - card->u.x.x25_conf.lo_svc) + 1; + } + if (card->u.x.x25_conf.hi_pvc != 0){ + card->u.x.num_of_ch += + (card->u.x.x25_conf.hi_pvc - card->u.x.x25_conf.lo_pvc) + 1; + } + + if (card->u.x.num_of_ch == 0){ + printk(KERN_INFO "%s: ERROR, Minimum number of PVC/SVC channels is 1 !\n" + "%s: Please set the Lowest/Highest PVC/SVC values !\n", + card->devname,card->devname); + return -ECHRNG; + } + + u.cfg.loPVC = card->u.x.x25_conf.lo_pvc; + u.cfg.hiPVC = card->u.x.x25_conf.hi_pvc; + u.cfg.loTwoWaySVC = card->u.x.x25_conf.lo_svc; + u.cfg.hiTwoWaySVC = card->u.x.x25_conf.hi_svc; + + if (conf->u.x25.hdlc_window) + u.cfg.hdlcWindow = wp_min(conf->u.x25.hdlc_window, 7); + if (conf->u.x25.pkt_window) + u.cfg.pktWindow = wp_min(conf->u.x25.pkt_window, 7); + + if (conf->u.x25.t1) + u.cfg.t1 = wp_min(conf->u.x25.t1, 30); + if (conf->u.x25.t2) + u.cfg.t2 = wp_min(conf->u.x25.t2, 29); + if (conf->u.x25.t4) + u.cfg.t4 = wp_min(conf->u.x25.t4, 240); + if (conf->u.x25.n2) + u.cfg.n2 = wp_min(conf->u.x25.n2, 30); + + if (conf->u.x25.t10_t20) + u.cfg.t10t20 = wp_min(conf->u.x25.t10_t20,255); + if (conf->u.x25.t11_t21) + u.cfg.t11t21 = wp_min(conf->u.x25.t11_t21,255); + if (conf->u.x25.t12_t22) + u.cfg.t12t22 = wp_min(conf->u.x25.t12_t22,255); + if (conf->u.x25.t13_t23) + u.cfg.t13t23 = wp_min(conf->u.x25.t13_t23,255); + if (conf->u.x25.t16_t26) + u.cfg.t16t26 = wp_min(conf->u.x25.t16_t26, 255); + if (conf->u.x25.t28) + u.cfg.t28 = wp_min(conf->u.x25.t28, 255); + + if (conf->u.x25.r10_r20) + u.cfg.r10r20 = wp_min(conf->u.x25.r10_r20,250); + if (conf->u.x25.r12_r22) + u.cfg.r12r22 = wp_min(conf->u.x25.r12_r22,250); + if (conf->u.x25.r13_r23) + u.cfg.r13r23 = wp_min(conf->u.x25.r13_r23,250); + + + if (conf->u.x25.ccitt_compat) + u.cfg.ccittCompat = conf->u.x25.ccitt_compat; + + DEBUG_EVENT("%s: Low PVC = %d\n", + card->devname,u.cfg.loPVC); + DEBUG_EVENT("%s: High PVC = %d\n", + card->devname,u.cfg.hiPVC); + DEBUG_EVENT("%s: Low SVC = %d\n", + card->devname,u.cfg.loTwoWaySVC); + DEBUG_EVENT("%s: High SVC = %d\n", + card->devname,u.cfg.hiTwoWaySVC); + DEBUG_EVENT("%s: Num of Channels = %d\n", + card->devname,card->u.x.num_of_ch); + + /* Copy the real configuration to card structure */ + x25_conf->lo_pvc = u.cfg.loPVC; + x25_conf->hi_pvc = u.cfg.hiPVC; + x25_conf->lo_svc = u.cfg.loTwoWaySVC; + x25_conf->hi_svc = u.cfg.hiTwoWaySVC; + x25_conf->hdlc_window = u.cfg.hdlcWindow; + x25_conf->pkt_window = u.cfg.pktWindow; + x25_conf->t1 = u.cfg.t1; + x25_conf->t2 = u.cfg.t2; + x25_conf->t4 = u.cfg.t4; + x25_conf->n2 = u.cfg.n2; + x25_conf->t10_t20 = u.cfg.t10t20; + x25_conf->t11_t21 = u.cfg.t11t21; + x25_conf->t12_t22 = u.cfg.t12t22; + x25_conf->t13_t23 = u.cfg.t13t23; + x25_conf->t16_t26 = u.cfg.t16t26; + x25_conf->t28 = u.cfg.t28; + x25_conf->r10_r20 = u.cfg.r10r20; + x25_conf->r12_r22 = u.cfg.r12r22; + x25_conf->r13_r23 = u.cfg.r13r23; + x25_conf->ccitt_compat = u.cfg.ccittCompat; + x25_conf->x25_conf_opt = u.cfg.options; + x25_conf->oob_on_modem = conf->u.x25.oob_on_modem; + x25_conf->pktMTU = u.cfg.pktMTU; + x25_conf->defPktSize = u.cfg.defPktSize; + x25_conf->cmd_retry_timeout = x25_adm_conf->cmd_retry_timeout; + + + /* initialize adapter */ + if (card->u.x.LAPB_hdlc){ + if (hdlc_configure(card, &u.cfg) != CMD_OK) + return -EIO; + }else{ + if (x25_configure(card, &u.cfg) != CMD_OK) + return -EIO; + } + + if ((x25_close_hdlc(card) != CMD_OK) || /* close HDLC link */ + (x25_set_dtr(card, 0) != CMD_OK)) /* drop DTR */ + return -EIO; + + /* Initialize protocol-specific fields of adapter data space */ + card->wandev.bps = conf->bps; + card->wandev.interface = conf->interface; + card->wandev.clocking = conf->clocking; + card->wandev.station = conf->u.x25.station; + card->isr = &wpx_isr; + card->poll = NULL; + card->disable_comm = &disable_comm; + card->exec = NULL; + card->wandev.update = &update; + card->wandev.new_if = &new_if; + card->wandev.del_if = &del_if; + + + card->bind_api_to_svc = &bind_api_to_svc; + + // Proc fs functions + card->wandev.get_config_info = &x25_get_config_info; + card->wandev.get_status_info = &x25_get_status_info; + card->wandev.set_dev_config = &x25_set_dev_config; + card->wandev.set_if_info = &x25_set_if_info; + + /* SNMP data */ + card->get_snmp_data = &x25_snmp_data; + + + /* WARNING: This function cannot exit with an error + * after the change of state */ + card->wandev.state = WAN_DISCONNECTED; + + card->wandev.enable_tx_int = 0; + card->irq_dis_if_send_count = 0; + card->irq_dis_poll_count = 0; + card->u.x.tx_dev = NULL; + card->u.x.no_dev = 0; + + + /* Configure for S514 PCI Card */ + /* Alex Apr 8 2004 Sangoma ISA card */ + card->u.x.hdlc_buf_status_off = + X25_MB_VECTOR + X25_MISC_HDLC_BITS; + + card->u.x.poll_device=NULL; + card->wandev.udp_port = conf->udp_port; + + /* Enable or disable call setup logging */ + if (conf->u.x25.logging == WANOPT_YES){ + printk(KERN_INFO "%s: Enabling Call Logging.\n", + card->devname); + card->u.x.logging = 1; + }else{ + card->u.x.logging = 0; + } + + /* Enable or disable modem status reporting */ + if (conf->u.x25.oob_on_modem == WANOPT_YES){ + printk(KERN_INFO "%s: Enabling OOB on Modem change.\n", + card->devname); + card->u.x.oob_on_modem = 1; + }else{ + card->u.x.oob_on_modem = 0; + } + + init_global_statistics(card); + + + INIT_WORK((&card->u.x.x25_poll_task),wpx_poll,card); + + init_timer(&card->u.x.x25_timer); + card->u.x.x25_timer.data = (unsigned long)card; + card->u.x.x25_timer.function = x25_timer_routine; + + skb_queue_head_init(&card->u.x.trace_queue); + + return 0; +} + +/*========================================================= + * WAN Device Driver Entry Points + *========================================================*/ + +/*============================================================ + * Name: update(), Update device status & statistics. + * + * Purpose: To provide debugging and statitical + * information to the /proc file system. + * /proc/net/wanrouter/wanpipe# + * + * Rationale: The /proc file system is used to collect + * information about the kernel and drivers. + * Using the /proc file system the user + * can see exactly what the sangoma drivers are + * doing. And in what state they are in. + * + * Description: Collect all driver statistical information + * and pass it to the top laywer. + * + * Since we have to execute a debugging command, + * to obtain firmware statitics, we trigger a + * UPDATE function within the timer interrtup. + * We wait until the timer update is complete. + * Once complete return the appropriate return + * code to indicate that the update was successful. + * + * Called by: device_stat() in wanmain.c + * + * Assumptions: + * + * Warnings: This function will degrade the performance + * of the router, since it uses the mailbox. + * + * Return: 0 OK + * <0 Failed (or busy). + */ + +static int update (wan_device_t* wandev) +{ + netdevice_t *dev; + sdla_t* card; + unsigned long smp_flags; + u8 status; + int err=0; + + /* sanity checks */ + if ((wandev == NULL) || (wandev->private == NULL)) + return -EFAULT; + + if (wandev->state == WAN_UNCONFIGURED) + return -ENODEV; + + if (test_bit(SEND_CRIT, (void*)&wandev->critical)) + return -EAGAIN; + + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&wandev->dev_head)); + if (dev == NULL) + return -ENODEV; + + card = wandev->private; + + spin_lock_irqsave(&card->wandev.lock, smp_flags); + + card->hw_iface.peek(card->hw, card->u.x.hdlc_buf_status_off, &status, 1); + if (status & 0x40){ + x25_get_err_stats(card); + x25_get_stats(card); + }else{ + err=-EBUSY; + } + + spin_unlock_irqrestore(&card->wandev.lock, smp_flags); + + return err; +} + + +/*=================================================================== + * Name: new_if + * + * Purpose: To allocate and initialize resources for a + * new logical channel. + * + * Rationale: A new channel can be added dynamically via + * ioctl call. + * + * Description: Allocate a private channel structure, x25_channel_t. + * Parse the user interface options from wanpipe#.conf + * configuration file. + * Bind the private are into the network device private + * area pointer (dev->priv). + * Prepare the network device structure for registration. + * + * Called by: ROUTER_IFNEW Ioctl call, from wanrouter_ioctl() + * (wanmain.c) + * + * Assumptions: None + * + * Warnings: None + * + * Return: 0 Ok + * <0 Failed (channel will not be created) + */ +static int new_if (wan_device_t* wandev, netdevice_t* dev, wanif_conf_t* conf) +{ + sdla_t* card = wandev->private; + x25_channel_t* chan; + int err = 0; + + if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)){ + printk(KERN_INFO "%s: invalid interface name!\n", + card->devname); + return -EINVAL; + } + + if(card->wandev.new_if_cnt++ > 0 && card->u.x.LAPB_hdlc) { + printk(KERN_INFO "%s: Error: Running LAPB HDLC Mode !\n", + card->devname); + printk(KERN_INFO + "%s: Maximum number of network interfaces must be one !\n", + card->devname); + return -EEXIST; + } + + /* allocate and initialize private data */ + chan = kmalloc(sizeof(x25_channel_t), GFP_ATOMIC); + if (chan == NULL){ + printk(KERN_INFO "%s: Error: No memory !\n", + card->devname); + return -ENOMEM; + } + + memset(chan, 0, sizeof(x25_channel_t)); + + WAN_TASKLET_INIT((&chan->common.bh_task),0,x25api_bh,(unsigned long)chan); + /* Bug Fix: Seg Err on PVC startup + * It must be here since bind_lcn_to_dev expects + * it bellow */ + dev->priv = chan; + + strcpy(chan->name, conf->name); + chan->card = card; + chan->tx_skb = chan->rx_skb = NULL; + + /* verify media address */ + if (conf->addr[0] == '@'){ /* SVC */ + + chan->common.svc = 1; + strncpy(chan->addr, &conf->addr[1], WAN_ADDRESS_SZ); + + strncpy(chan->x25_src_addr, + &conf->x25_src_addr[0], WAN_ADDRESS_SZ); + + strncpy(chan->accept_dest_addr, + &conf->accept_dest_addr[0], WAN_ADDRESS_SZ); + + strncpy(chan->accept_src_addr, + &conf->accept_src_addr[0], WAN_ADDRESS_SZ); + + strncpy(chan->accept_usr_data, + &conf->accept_usr_data[0], WAN_ADDRESS_SZ); + + /* Set channel timeouts (default if not specified) */ + chan->idle_timeout = (conf->idle_timeout) ? + conf->idle_timeout : 90; + chan->hold_timeout = (conf->hold_timeout) ? + conf->hold_timeout : 10; + + }else if (is_digit(conf->addr[0])){ /* PVC */ + int lcn = dec_to_uint(conf->addr, 0); + + if ((lcn >= card->u.x.x25_conf.lo_pvc) && (lcn <= card->u.x.x25_conf.hi_pvc)){ + bind_lcn_to_dev (card, dev, lcn); + }else{ + printk(KERN_INFO + "%s: PVC %u is out of range on interface %s!\n", + wandev->name, lcn, chan->name); + err = -EINVAL; + } + }else{ + printk(KERN_INFO + "%s: invalid media address on interface %s!\n", + wandev->name, chan->name); + err = -EINVAL; + } + + if(strcmp(conf->usedby, "WANPIPE") == 0){ + printk(KERN_INFO "%s: Running in WANPIPE mode %s\n", + wandev->name, chan->name); + chan->common.usedby = WANPIPE; + chan->protocol = htons(ETH_P_IP); + + }else if(strcmp(conf->usedby, "API") == 0){ + chan->common.usedby = API; + printk(KERN_INFO "%s: Running in API mode %s\n", + wandev->name, chan->name); + chan->protocol = htons(X25_PROT); + wan_reg_api(chan,dev,card->devname); + } + + if (err){ + kfree(chan); + dev->priv = NULL; + return err; + } + + chan->enable_IPX = conf->enable_IPX; + + if (chan->enable_IPX) + chan->protocol = htons(ETH_P_IPX); + + if (conf->network_number) + chan->network_number = conf->network_number; + else + chan->network_number = 0xDEADBEEF; + + /* prepare network device data space for registration */ + dev->init = &if_init; + + init_x25_channel_struct(chan); + + /* + * Create interface file in proc fs. + */ + err = wanrouter_proc_add_interface(wandev, &chan->dent, chan->name, dev); + if (err){ + printk(KERN_INFO + "%s: can't create /proc/net/router/fr/%s entry!\n", + card->devname, chan->name); + return err; + } + + spin_lock_init(&chan->lock); + + return 0; +} + +/*=================================================================== + * Name: del_if(), Remove a logical channel. + * + * Purpose: To dynamically remove a logical channel. + * + * Rationale: Each logical channel should be dynamically + * removable. This functin is called by an + * IOCTL_IFDEL ioctl call or shutdown(). + * + * Description: Do nothing. + * + * Called by: IOCTL_IFDEL : wanrouter_ioctl() from wanmain.c + * shutdown() from sdlamain.c + * + * Assumptions: + * + * Warnings: + * + * Return: 0 Ok. Void function. + */ + + +static int del_if (wan_device_t* wandev, netdevice_t* dev) +{ + unsigned long smp_flags; + sdla_t *card=wandev->private; + x25_channel_t* chan = dev->priv; + + /* Delete interface name from proc fs. */ + wanrouter_proc_delete_interface(wandev, chan->name); + + WAN_TASKLET_KILL(&chan->common.bh_task); + wan_unreg_api(chan, card->devname); + + wan_spin_lock_irq(&card->wandev.lock,&smp_flags); + card->u.x.tx_dev=NULL; + card->u.x.cmd_dev=NULL; + wan_spin_unlock_irq(&card->wandev.lock,&smp_flags); + return 0; +} + + +/*============================================================ + * Name: disable_comm + * + * Description: Disable communications during shutdown. + * Dont check return code because there is + * nothing we can do about it. + * + * Warning: Dev and private areas are gone at this point. + *===========================================================*/ + +static void disable_comm(sdla_t* card) +{ + del_timer(&card->u.x.x25_timer); + disable_comm_shutdown(card); + return; +} + + +/*============================================================ + * Network Device Interface + *===========================================================*/ + +/*=================================================================== + * Name: if_init(), Netowrk Interface Initialization + * + * Purpose: To initialize a network interface device structure. + * + * Rationale: During network interface startup, the if_init + * is called by the kernel to initialize the + * netowrk device structure. Thus a driver + * can customze a network device. + * + * Description: Initialize the netowrk device call back + * routines. This is where we tell the kernel + * which function to use when it wants to send + * via our interface. + * Furthermore, we initialize the device flags, + * MTU and physical address of the board. + * + * Called by: Kernel (/usr/src/linux/net/core/dev.c) + * (dev->init()) + * + * Assumptions: None + * + * Warnings: None + * + * Return: 0 Ok : Void function. + */ +static int if_init (netdevice_t* dev) +{ + x25_channel_t* chan = dev->priv; + sdla_t* card = chan->card; + wan_device_t* wandev = &card->wandev; + + /* Initialize device driver entry points */ + dev->open = &if_open; + dev->stop = &if_close; + dev->hard_header = NULL; + dev->rebuild_header = NULL; + dev->hard_start_xmit = &if_send; + dev->get_stats = &if_stats; + dev->do_ioctl = &x25_ioctl; + +#if defined(LINUX_2_4)||defined(LINUX_2_6) + if (chan->common.usedby != API){ + dev->tx_timeout = &if_tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; + } +#endif + + /* Initialize media-specific parameters */ + dev->type = ARPHRD_PPP; /* ARP h/w type */ + + dev->flags |= IFF_POINTOPOINT; + dev->flags |= IFF_NOARP; + + if (chan->common.usedby == API){ + dev->mtu = X25_CHAN_MTU+sizeof(x25api_hdr_t); + }else{ + dev->mtu = card->wandev.mtu; + } + + dev->hard_header_len = 0; /* media header length */ + dev->addr_len = 2; /* hardware address length */ + + if (!chan->common.svc){ + *(unsigned short*)dev->dev_addr = htons(chan->common.lcn); + } + + /* Initialize hardware parameters (just for reference) */ + dev->irq = wandev->irq; + dev->dma = wandev->dma; + dev->base_addr = wandev->ioport; + card->hw_iface.getcfg(card->hw, SDLA_MEMBASE, &dev->mem_start); //ALEX_TODAY (unsigned long)wandev->maddr; + card->hw_iface.getcfg(card->hw, SDLA_MEMEND, &dev->mem_end); //ALEX_TODAY wandev->maddr + wandev->msize - 1; + + /* Set transmit buffer queue length */ + dev->tx_queue_len = 100; + + set_chan_state(dev, WAN_DISCONNECTED); + return 0; +} + + +/*=================================================================== + * Name: if_open(), Open/Bring up the Netowrk Interface + * + * Purpose: To bring up a network interface. + * + * Rationale: + * + * Description: Open network interface. + * o prevent module from unloading by incrementing use count + * o if link is disconnected then initiate connection + * + * Called by: Kernel (/usr/src/linux/net/core/dev.c) + * (dev->open()) + * + * Assumptions: None + * + * Warnings: None + * + * Return: 0 Ok + * <0 Failur: Interface will not come up. + */ + +static int if_open (netdevice_t* dev) +{ + x25_channel_t* chan = dev->priv; + sdla_t* card = chan->card; + struct timeval tv; + unsigned long smp_flags; + + if (open_dev_check(dev)) + return -EBUSY; + + + /* Increment the number of interfaces */ + ++card->u.x.no_dev; + + wanpipe_open(card); + + if (!card->u.x.LAPB_hdlc){ + /* X25 can have multiple interfaces thus, start the + * protocol once all interfaces are up */ + + //FIXME: There is a bug here. If interface is + //brought down and up, it will try to enable comm. + if (card->open_cnt == card->u.x.num_of_ch){ + + S508_S514_lock(card, &smp_flags); + connect(card); + S508_S514_unlock(card, &smp_flags); + + del_timer(&card->u.x.x25_timer); + card->u.x.x25_timer.expires=jiffies+HZ; + add_timer(&card->u.x.x25_timer); + } + } + /* Device is not up untill the we are in connected state */ + do_gettimeofday( &tv ); + chan->router_start_time = tv.tv_sec; + + netif_start_queue(dev); + + /* PVC in WANPIPE mode should start connected */ + if (!chan->common.svc && chan->common.usedby == WANPIPE){ + unsigned long flags; + int err; + spin_lock_irqsave(&card->wandev.lock,flags); + err=x25_get_chan_conf(card, chan); + if (err == CMD_OK){ + set_chan_state(dev, WAN_CONNECTED); + }else{ + DEBUG_EVENT("%s:%s: PVC conf error, channel not ready! 0x%X\n", + card->devname,chan->name,err); + set_chan_state(dev, WAN_DISCONNECTED); + } + spin_unlock_irqrestore(&card->wandev.lock,flags); + } + + return 0; +} + +/*=================================================================== + * Name: if_close(), Close/Bring down the Netowrk Interface + * + * Purpose: To bring down a network interface. + * + * Rationale: + * + * Description: Close network interface. + * o decrement use module use count + * + * Called by: Kernel (/usr/src/linux/net/core/dev.c) + * (dev->close()) + * ifconfig down: will trigger the kernel + * which will call this function. + * + * Assumptions: None + * + * Warnings: None + * + * Return: 0 Ok + * <0 Failure: Interface will not exit properly. + */ +static int if_close (netdevice_t* dev) +{ + x25_channel_t* chan = dev->priv; + sdla_t* card = chan->card; + unsigned long smp_flags; + + stop_net_queue(dev); + +#if defined(LINUX_2_1) + dev->start=0; +#endif + + if ((chan->common.state == WAN_CONNECTED) || + (chan->common.state == WAN_CONNECTING)){ + S508_S514_lock(card, &smp_flags); + chan_disc(dev); + set_chan_state(dev, WAN_DISCONNECTED); + S508_S514_unlock(card, &smp_flags); + } + + wanpipe_close(card); + + /* If this is the last close, disconnect physical link */ + if (!card->open_cnt){ + S508_S514_lock(card, &smp_flags); + disconnect(card); + if (card->sk){ + protocol_disconnected(card->sk); + sock_put(card->sk); + card->sk=NULL; + } + x25_set_intr_mode(card, 0); + S508_S514_unlock(card, &smp_flags); + } + + /* Decrement the number of interfaces */ + --card->u.x.no_dev; + return 0; +} + + +/*============================================================================ + * Handle transmit timeout event from netif watchdog + */ +static void if_tx_timeout (netdevice_t *dev) +{ + x25_channel_t* chan = dev->priv; + sdla_t *card = chan->card; + + /* If our device stays busy for at least 5 seconds then we will + * kick start the device by making dev->tbusy = 0. We expect + * that our device never stays busy more than 5 seconds. So this + * is only used as a last resort. + */ + + ++chan->if_send_stat.if_send_tbusy_timeout; + printk (KERN_INFO "%s: Transmit timed out on %s\n", + card->devname, dev->name); + netif_wake_queue (dev); +} + + +/*========================================================================= + * Send a packet on a network interface. + * o set tbusy flag (marks start of the transmission). + * o check link state. If link is not up, then drop the packet. + * o check channel status. If it's down then initiate a call. + * o pass a packet to corresponding WAN device. + * o free socket buffer + * + * Return: 0 complete (socket buffer must be freed) + * non-0 packet may be re-transmitted (tbusy must be set) + * + * Notes: + * 1. This routine is called either by the protocol stack or by the "net + * bottom half" (with interrupts enabled). + * 2. Setting tbusy flag will inhibit further transmit requests from the + * protocol stack and can be used for flow control with protocol layer. + * + *========================================================================*/ + +static int if_send (struct sk_buff* skb, netdevice_t* dev) +{ + x25_channel_t* chan = dev->priv; + sdla_t* card = chan->card; + int udp_type; + unsigned long smp_flags=0; + + ++chan->if_send_stat.if_send_entry; + + /* No need to check frame length, since socket code + * will perform the check for us */ + +#if defined(LINUX_2_1) + if (dev->tbusy){ + netdevice_t *dev2; + + ++chan->if_send_stat.if_send_tbusy; + if ((jiffies - chan->tick_counter) < (5*HZ)){ + return 1; + } + + if_tx_timeout(dev); + } +#else + netif_stop_queue(dev); +#endif + + chan->tick_counter = jiffies; + + /* Critical region starts here */ + S508_S514_lock(card, &smp_flags); + + if (test_and_set_bit(SEND_CRIT, (void*)&card->wandev.critical)){ + printk(KERN_INFO "Hit critical in if_send()! %lx\n",card->wandev.critical); + goto if_send_crit_exit; + } + + udp_type = udp_pkt_type(skb, card); + + if(udp_type != UDP_INVALID_TYPE) { + + if(store_udp_mgmt_pkt(udp_type, UDP_PKT_FRM_STACK, card, dev, skb, + chan->common.lcn)) { + card->hw_iface.set_bit(card->hw, card->intr_perm_off, INTR_ON_TIMER); + if (udp_type == UDP_XPIPE_TYPE){ + chan->if_send_stat.if_send_PIPE_request++; + } + } + start_net_queue(dev); + clear_bit(SEND_CRIT,(void*)&card->wandev.critical); + S508_S514_unlock(card, &smp_flags); + return 0; + } + + if (chan->transmit_length){ + //FIXME: This check doesn't make sense any more + if (chan->common.state != WAN_CONNECTED){ + chan->transmit_length=0; + }else{ + stop_net_queue(dev); + + atomic_inc(&card->u.x.tx_interrupts_pending); + card->hw_iface.set_bit(card->hw, card->intr_perm_off, INTR_ON_TX_FRAME); + clear_bit(SEND_CRIT,(void*)&card->wandev.critical); + S508_S514_unlock(card, &smp_flags); + return 1; + } + } + + if (card->wandev.state != WAN_CONNECTED || + chan->common.state != WAN_CONNECTED){ + ++chan->ifstats.tx_dropped; + ++card->wandev.stats.tx_dropped; + ++chan->if_send_stat.if_send_wan_disconnected; + + }else if (chan->common.usedby == API && + skb->protocol!=htons(WP_X25_PROT) && + skb->protocol!=htons(ETH_P_X25)){ + + /* For backward compatibility we must check + * for WP_X25_PROT as well as ETH_P_X25 prot */ + + printk(KERN_INFO + "%s: Unsupported skb prot=0x%04X not equal to 0x%04X!\n", + chan->name, htons(skb->protocol), htons(chan->protocol)); + + ++chan->ifstats.tx_errors; + ++chan->ifstats.tx_dropped; + ++card->wandev.stats.tx_dropped; + ++chan->if_send_stat.if_send_protocol_error; + + }else switch (chan->common.state){ + + case WAN_DISCONNECTED: + /* Try to establish connection. If succeded, then start + * transmission, else drop a packet. + */ + if (chan->common.usedby == API){ + ++chan->ifstats.tx_dropped; + ++card->wandev.stats.tx_dropped; + break; + }else{ + if (chan_connect(dev) != 0){ + ++chan->ifstats.tx_dropped; + ++card->wandev.stats.tx_dropped; + break; + } + } + /* fall through */ + + case WAN_CONNECTED: + if( skb->protocol == htons(ETH_P_IPX)) { + if(chan->enable_IPX) { + switch_net_numbers( skb->data, + chan->network_number, 0); + } else { + ++card->wandev.stats.tx_dropped; + ++chan->ifstats.tx_dropped; + ++chan->if_send_stat.if_send_protocol_error; + goto if_send_crit_exit; + } + } + /* We never drop here, if cannot send than, copy + * a packet into a transmit buffer + */ + chan_send(dev, skb->data, skb->len, 0); + break; + + default: + ++chan->ifstats.tx_dropped; + ++card->wandev.stats.tx_dropped; + break; + } + + +if_send_crit_exit: + + wan_skb_free(skb); + + start_net_queue(dev); + clear_bit(SEND_CRIT,(void*)&card->wandev.critical); + S508_S514_unlock(card, &smp_flags); + return 0; +} + +/*============================================================================ + * Setup so that a frame can be transmitted on the occurence of a transmit + * interrupt. + *===========================================================================*/ + +static void setup_for_delayed_transmit (netdevice_t* dev, void* buf, + unsigned len) +{ + x25_channel_t* chan = dev->priv; + sdla_t* card = chan->card; + + ++chan->if_send_stat.if_send_adptr_bfrs_full; + + if(chan->transmit_length) { + printk(KERN_INFO "%s: Error, transmit length set in delayed transmit!\n", + card->devname); + return; + } + + if (chan->common.usedby == API){ + if (len > X25_CHAN_MTU+sizeof(x25api_hdr_t)) { + ++chan->ifstats.tx_dropped; + ++card->wandev.stats.tx_dropped; + printk(KERN_INFO "%s: Length is too big for delayed transmit\n", + card->devname); + return; + } + }else{ + if (len > dev->mtu || len > X25_CHAN_MTU) { + ++chan->ifstats.tx_dropped; + ++card->wandev.stats.tx_dropped; + printk(KERN_INFO "%s: Length is too big for delayed transmit\n", + card->devname); + return; + } + } + + /* N.C.: Bug Fix: Fri Jul 19 12:50:02 EDT 2002 + * The tx_offset must be re-initialized to zero, + * each time a new frame is queued for tx. + * Otherwise, tx_offset value might be left from + * previous failure to send !*/ + chan->tx_offset = 0; + + chan->transmit_length = len; + memcpy(chan->transmit_buffer, buf, len); + + ++chan->if_send_stat.if_send_tx_int_enabled; + + /* Enable Transmit Interrupt */ + atomic_inc(&card->u.x.tx_interrupts_pending); + card->hw_iface.set_bit(card->hw, card->intr_perm_off, INTR_ON_TX_FRAME); +} + + +/*=============================================================== + * net_device_stats + * + * Get ethernet-style interface statistics. + * Return a pointer to struct enet_statistics. + * + *==============================================================*/ +static struct net_device_stats *if_stats (netdevice_t* dev) +{ + x25_channel_t *chan = dev->priv; + + if(chan == NULL) + return NULL; + + return &chan->ifstats; +} + +/*============================================================== + * x25_ioctl + * + * Description: + * Network device ioctl function used by the socket api + * layer or higher layers, to execute X25 commands and + * perform registration and unregistration tasts. + * + * Usedby: + * Higher protocol layers such as socket api, dsp, etc. + */ + +static int x25_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) +{ + x25_channel_t *chan; + sdla_t *card; + int err=0; + unsigned long flags; + wan_udp_pkt_t *wan_udp_pkt; + + + if (!dev || !(dev->flags & IFF_UP)){ + return -ENODEV; + } + + if ((chan=dev->priv) == NULL){ + return -ENODEV; + } + + card=chan->card; + + DEBUG_TEST("%s:%s:%s: Cmd(%X)=%s ifr=%p lcn %i\n",__FUNCTION__, + card->devname,dev->name,cmd,DECODE_X25_CMD(cmd),ifr,chan->common.lcn); + switch (cmd){ + + case SIOC_X25_PLACE_CALL: + + if (!test_bit(0,&card->u.x.card_ready)){ + atomic_set(&chan->common.command,0); + trigger_intr_exec(card, TMR_INT_ENABLED_CMD_EXEC); + err = -EBUSY; + goto x25_ioctl_exit; + } + + + if (card->u.x.LAPB_hdlc){ + spin_lock_irqsave(&card->wandev.lock,flags); + err=lapb_connect(card,chan); + spin_unlock_irqrestore(&card->wandev.lock,flags); + goto x25_ioctl_exit; + + } + + if (card->wandev.state != WAN_CONNECTED || + chan->common.state != WAN_DISCONNECTED){ + err = -EBUSY; + goto x25_ioctl_exit; + } + + err=test_chan_command_busy(card,chan); + if (err){ + goto x25_ioctl_exit; + } + + atomic_set(&chan->common.command,X25_PLACE_CALL); + trigger_intr_exec(card, TMR_INT_ENABLED_CMD_EXEC); + + err=wait_for_cmd_rc(card,chan); + + DEBUG_TEST("%s:%s PLACE CALL RC %x\n",card->devname,dev->name,err); + break; + + case SIOC_X25_SET_CALL_DATA: + err=x25_api_cmd_setup(chan,ifr); + break; + + case SIOC_X25_GET_CALL_DATA: + err=x25_api_get_cmd_result(chan, ifr); + break; + + case SIOC_X25_CLEAR_CALL: + + if (card->wandev.state != WAN_CONNECTED){ + err = -EINVAL; + goto x25_ioctl_exit; + } + + + if (chan->common.state == WAN_DISCONNECTED || + chan->common.state == WAN_DISCONNECTING){ + err = -EINVAL; + goto x25_ioctl_exit; + } + + err=test_chan_command_busy(card,chan); + if (err){ + goto x25_ioctl_exit; + } + + if (!chan->common.svc){ + err=-EINVAL; + goto x25_ioctl_exit; + } + + if (chan->common.state == WAN_DISCONNECTED){ + err = -ENETDOWN; + goto x25_ioctl_exit; + } + + err=x25_api_setup_cmd_hdr(chan,ifr); + if (err) + goto x25_ioctl_exit; + + err=x25_api_setup_call_string(chan,ifr); + if (err){ + goto x25_ioctl_exit; + } + + if (chan->x25_api_cmd_hdr.qdm & 0x80){ + if (chan->transmit_length){ + DEBUG_EVENT("%s: Clear call failed: data in tx buf!\n", + chan->common.dev->name); + err= -EBUSY; + goto x25_ioctl_exit; + } + } + + atomic_set(&chan->common.command,X25_CLEAR_CALL); + trigger_intr_exec(card, TMR_INT_ENABLED_CMD_EXEC); + + err=wait_for_cmd_rc(card,chan); + if (err == -EFAULT){ + err=x25_clear_call(card,chan->common.lcn,0,0,0, + chan->call_string,strlen(chan->call_string)); + if (err){ + err=-EINVAL; + } + } + + if (err != 0){ + DEBUG_EVENT("%s:%s: Warning: Clear call failed, delaying disconnect!\n", + card->devname,chan->common.dev->name); + } + + break; + + case SIOC_X25_ACCEPT_CALL: + + if (chan->common.state != WAN_CONNECTING){ + err = -EBUSY; + goto x25_ioctl_exit; + } + + err=test_chan_command_busy(card,chan); + if (err){ + goto x25_ioctl_exit; + } + + err=x25_api_setup_cmd_hdr(chan,ifr); + if (err) + goto x25_ioctl_exit; + + err=x25_api_setup_call_string(chan,ifr); + if (err){ + goto x25_ioctl_exit; + } + + atomic_set(&chan->common.command,X25_ACCEPT_CALL); + trigger_intr_exec(card, TMR_INT_ENABLED_CMD_EXEC); + + err=wait_for_cmd_rc(card,chan); + + DEBUG_TEST("%s:%s ACCEPT CALL RC %x\n",card->devname,dev->name,err); + + break; + + case SIOC_X25_RESET_CALL: + + err=x25_api_setup_cmd_hdr(chan,ifr); + if (err) + goto x25_ioctl_exit; + + err=test_chan_command_busy(card,chan); + if (err){ + goto x25_ioctl_exit; + } + + atomic_set(&chan->common.command,X25_RESET); + trigger_intr_exec(card, TMR_INT_ENABLED_CMD_EXEC); + + err=wait_for_cmd_rc(card,chan); + + DEBUG_TEST("%s:%s RESET CALL RC %x\n",card->devname,dev->name,err); + + break; + + case SIOC_X25_INTERRUPT: + + err=test_chan_command_busy(card,chan); + if (err){ + goto x25_ioctl_exit; + } + + err=x25_api_setup_cmd_hdr(chan,ifr); + if (err) + goto x25_ioctl_exit; + + err=x25_api_setup_call_string(chan,ifr); + if (err){ + goto x25_ioctl_exit; + } + + atomic_set(&chan->common.command,X25_WP_INTERRUPT); + trigger_intr_exec(card, TMR_INT_ENABLED_CMD_EXEC); + + err=wait_for_cmd_rc(card,chan); + + DEBUG_TEST("%s:%s INTERRUPT RC %x\n",card->devname,dev->name,err); + + break; + + case SIOC_X25_SET_LCN_PID: + if (ifr && ifr->ifr_data){ + err = copy_from_user(&chan->pid, + ifr->ifr_data, + sizeof(pid_t)); + } + break; + + case SIOC_X25_SET_LCN_LABEL: + if (ifr && ifr->ifr_data){ + err = copy_from_user(&chan->dlabel[0], + ifr->ifr_data, + WAN_IF_LABEL_SZ); + + chan->dlabel[WAN_IF_LABEL_SZ]=0; + } + break; + + case SIOC_WANPIPE_BIND_SK: + if (!ifr){ + err= -EINVAL; + goto x25_ioctl_exit; + } + + if (card->u.x.LAPB_hdlc){ + set_bit(0,&card->u.x.card_ready); + } + + if (!test_bit(0,&card->u.x.card_ready)){ + atomic_set(&chan->common.command,0); + trigger_intr_exec(card, TMR_INT_ENABLED_CMD_EXEC); + err = -EBUSY; + goto x25_ioctl_exit; + } + + if (ifr->ifr_data && !chan->common.sk){ + if (!spin_is_locked(&card->wandev.lock)){ + spin_lock_irqsave(&card->wandev.lock,flags); + chan->common.sk = (struct sock*)ifr->ifr_data; + sock_hold(chan->common.sk); + set_bit(LCN_SK_ID,&chan->common.used); + spin_unlock_irqrestore(&card->wandev.lock,flags); + }else{ + chan->common.sk = (struct sock*)ifr->ifr_data; + sock_hold(chan->common.sk); + set_bit(LCN_SK_ID,&chan->common.used); + } + break; + } + + err= -EBUSY; + break; + + case SIOC_WANPIPE_UNBIND_SK: + if (!ifr){ + err= -EINVAL; + goto x25_ioctl_exit; + } + + spin_lock_irqsave(&card->wandev.lock,flags); + err=wan_unbind_api_from_svc(chan,ifr->ifr_data); + spin_unlock_irqrestore(&card->wandev.lock,flags); + + if (atomic_read(&chan->common.receive_block)){ + TX25Status status; + + card->hw_iface.peek(card->hw, + card->intr_perm_off, + &status.imask, + sizeof(status.imask)); + atomic_set(&chan->common.receive_block,0); + + if (!(status.imask & INTR_ON_RX_FRAME)){ + DEBUG_EVENT("%s: Disabling x25 flow control!\n", + card->devname); + status.imask |= INTR_ON_RX_FRAME; + card->hw_iface.poke(card->hw, + card->intr_perm_off, + &status.imask, + sizeof(status.imask)); + } + } + + if (chan->common.svc){ + atomic_set(&chan->common.disconnect,1); + }else{ + set_chan_state(dev,WAN_DISCONNECTED); + } + + if (card->u.x.LAPB_hdlc){ + spin_lock_irqsave(&card->wandev.lock,flags); + disconnect(card); + set_chan_state(dev,WAN_DISCONNECTED); + spin_unlock_irqrestore(&card->wandev.lock,flags); + } + + break; + + case SIOC_WANPIPE_GET_SK: + if (!ifr){ + err= -EINVAL; + goto x25_ioctl_exit; + } + + if (test_bit(LCN_SK_ID,&chan->common.used) && chan->common.sk){ + sock_hold(chan->common.sk); + ifr->ifr_data = (void*)chan->common.sk; + }else{ + ifr->ifr_data = NULL; + } + break; + + case SIOC_WANPIPE_CHECK_TX: + case SIOC_ANNEXG_CHECK_TX: + err=chan->transmit_length; + break; + + case SIOC_ANNEXG_KICK: + + if (atomic_read(&chan->common.receive_block)){ + WAN_TASKLET_SCHEDULE((&chan->common.bh_task)); + } + + err=0; + break; + + case SIOC_WANPIPE_SNMP: + case SIOC_WANPIPE_SNMP_IFSPEED: + err = wan_snmp_data(card, dev, cmd, ifr); + break; + + case SIOC_WANPIPE_DEV_STATE: + err = chan->common.state; + break; + + case SIOC_WANPIPE_PIPEMON: + + if (atomic_read(&card->u.x.udp_pkt_len) != 0){ + err = -EBUSY; + goto x25_ioctl_exit; + } + + atomic_set(&card->u.x.udp_pkt_len,sizeof(wan_udp_hdr_t)); + + wan_udp_pkt=(wan_udp_pkt_t*)&card->u.x.udp_pkt_data; + if (copy_from_user(&wan_udp_pkt->wan_udp_hdr,ifr->ifr_data,sizeof(wan_udp_hdr_t))){ + atomic_set(&card->u.x.udp_pkt_len,0); + err = -EINVAL; + goto x25_ioctl_exit; + } + + spin_lock_irqsave(&card->wandev.lock, flags); + + /* We have to check here again because we don't know + * what happened during spin_lock */ + if (test_bit(0,&card->in_isr)){ + printk(KERN_INFO "%s:%s pipemon command busy: try again!\n", + card->devname,dev->name); + atomic_set(&card->u.x.udp_pkt_len,0); + spin_unlock_irqrestore(&card->wandev.lock, flags); + err = -EINVAL; + goto x25_ioctl_exit; + } + + if (process_udp_mgmt_pkt(card,dev) <= 0 ){ + atomic_set(&card->u.x.udp_pkt_len,0); + spin_unlock_irqrestore(&card->wandev.lock, flags); + err = -EINVAL; + goto x25_ioctl_exit; + } + + + spin_unlock_irqrestore(&card->wandev.lock, flags); + + /* This area will still be critical to other + * PIPEMON commands due to udp_pkt_len + * thus we can release the irq */ + + if (atomic_read(&card->u.x.udp_pkt_len) > sizeof(wan_udp_pkt_t)){ + printk(KERN_INFO "(Debug): PiPemon Buf too bit on the way up! %i\n", + atomic_read(&card->u.x.udp_pkt_len)); + atomic_set(&card->u.x.udp_pkt_len,0); + err = -EINVAL; + goto x25_ioctl_exit; + } + + if (copy_to_user(ifr->ifr_data,&wan_udp_pkt->wan_udp_hdr,sizeof(wan_udp_hdr_t))){ + atomic_set(&card->u.x.udp_pkt_len,0); + err = -EFAULT; + goto x25_ioctl_exit; + } + + atomic_set(&card->u.x.udp_pkt_len,0); + break; + + + default: + DEBUG_EVENT("%s: Unsupported Ioctl Call 0x%x \n", + chan->common.dev->name,cmd); + err= -EOPNOTSUPP; + break; + } +x25_ioctl_exit: + + return err; +} + + +/* + * Interrupt Handlers + */ + +/* + * X.25 Interrupt Service Routine. + */ + +static void wpx_isr (sdla_t* card) +{ + u8 intr_type; + + if (!card->hw){ + return; + } + + /* Sanity check, should never happen */ + if (test_bit(0,&card->in_isr)){ + printk(KERN_INFO "%s: Critical in WPX_ISR\n",card->devname); + card->hw_iface.poke_byte(card->hw, card->intr_type_off, 0x00); + return; + } + + card->in_isr = 1; + ++card->statistics.isr_entry; + + if (test_bit(PERI_CRIT,(void*)&card->wandev.critical)){ + card->in_isr=0; + card->hw_iface.poke_byte(card->hw, card->intr_type_off, 0x00); + return; + } + + if (test_bit(SEND_CRIT, (void*)&card->wandev.critical)){ + + card->hw_iface.peek(card->hw, card->intr_type_off, &intr_type, 1); + printk(KERN_INFO "%s: wpx_isr: wandev.critical set to 0x%02lx, int type = 0x%02x\n", + card->devname, + card->wandev.critical, + intr_type); + + card->in_isr = 0; + card->hw_iface.poke_byte(card->hw, card->intr_type_off, 0x00); + return; + } + + /* For all interrupts set the critical flag to CRITICAL_RX_INTR. + * If the if_send routine is called with this flag set it will set + * the enable transmit flag to 1. (for a delayed interrupt) + */ + card->hw_iface.peek(card->hw, card->intr_type_off, &intr_type, 1); + switch (intr_type){ + + case RX_INTR_PENDING: /* receive interrupt */ + rx_intr(card); + break; + + case TX_INTR_PENDING: /* transmit interrupt */ + tx_intr(card); + break; + + case MODEM_INTR_PENDING: /* modem status interrupt */ + status_intr(card); + break; + + case X25_ASY_TRANS_INTR_PENDING: /* network event interrupt */ + event_intr(card); + break; + + case TIMER_INTR_PENDING: + timer_intr(card); + break; + + case TRACE_INTR_PENDING: + trace_intr(card); + break; + + default: /* unwanted interrupt */ + spur_intr(card); + } + + card->in_isr = 0; + card->hw_iface.poke_byte(card->hw, card->intr_type_off, 0x00); +} + +/* + * Receive interrupt handler. + * This routine handles fragmented IP packets using M-bit according to the + * RFC1356. + * o map ligical channel number to network interface. + * o allocate socket buffer or append received packet to the existing one. + * o if M-bit is reset (i.e. it's the last packet in a sequence) then + * decapsulate packet and pass socket buffer to the protocol stack. + * + * Notes: + * 1. When allocating a socket buffer, if M-bit is set then more data is + * coming and we have to allocate buffer for the maximum IP packet size + * expected on this channel. + * 2. If something goes wrong and X.25 packet has to be dropped (e.g. no + * socket buffers available) the whole packet sequence must be discarded. + */ + +static void rx_intr (sdla_t* card) +{ + wan_cmd_t rxmb_cmd; + unsigned lcn; + netdevice_t* dev = NULL; + x25_channel_t* chan; + struct sk_buff* skb=NULL; + TX25Status status; + + card->hw_iface.peek(card->hw, card->flags_off, &status, sizeof(status)); + card->hw_iface.peek(card->hw, card->rxmb_off, &rxmb_cmd, sizeof(rxmb_cmd)); + lcn = rxmb_cmd.wan_cmd_x25_lcn; + dev = find_channel(card, lcn); + + if (dev == NULL){ + /* Invalid channel, discard packet */ + printk(KERN_INFO "%s: receiving on orphaned LCN %d!\n", + card->devname, lcn); + return; + } + + chan = dev->priv; + chan->i_timeout_sofar = jiffies; + + + /* Copy the data from the board, into an + * skb buffer + */ + if (wanpipe_pull_data_in_skb(card,dev,&skb)){ + ++chan->ifstats.rx_dropped; + ++card->wandev.stats.rx_dropped; + ++chan->rx_intr_stat.rx_intr_no_socket; + ++chan->rx_intr_stat.rx_intr_bfr_not_passed_to_stack; + return; + } + + dev->last_rx = jiffies; /* timestamp */ + + /* set rx_skb to NULL so we won't access it later when + * kernel already owns it */ + chan->rx_skb=NULL; + + /* ------------ API ----------------*/ + + if (chan->common.usedby == API){ + + int err = wan_api_enqueue_skb(chan,skb); + + switch (err){ + + case 0: + /* Buffer enqueued ok, proceed to trigger + * API bh */ + WAN_TASKLET_SCHEDULE((&chan->common.bh_task)); + break; + + case 1: + + /* The rx buffer is now full. If we receive + * another packet, we will might drop it. + * Thus, turn off the rx interrupt to implement + * x25 flow control, until the rx queue + * is free */ + + DEBUG_EVENT("%s:%s: Error: Driver Rx buffer is full\n", + card->devname,chan->common.dev->name); + DEBUG_EVENT("%s: Enabling x25 flow control!\n", + card->devname); + status.imask &= ~INTR_ON_RX_FRAME; + card->hw_iface.poke(card->hw, + card->intr_perm_off, + &status.imask, + sizeof(status.imask)); + + atomic_set(&chan->common.receive_block,1); + break; + + default: + + DEBUG_EVENT("%s: Critical Error: Rx intr dropping x25 packet!\n", + card->devname); + ++chan->ifstats.rx_dropped; + ++card->wandev.stats.rx_dropped; + ++chan->rx_intr_stat.rx_intr_bfr_not_passed_to_stack; + wan_skb_free(skb); + break; + } + + return; + } + + + /* ------------- WANPIPE -------------------*/ + + + /* Decapsulate packet, if necessary */ + if (!skb->protocol && !wanrouter_type_trans(skb, dev)){ + /* can't decapsulate packet */ + wan_skb_free(skb); + ++chan->ifstats.rx_errors; + ++chan->ifstats.rx_dropped; + ++card->wandev.stats.rx_dropped; + ++chan->rx_intr_stat.rx_intr_bfr_not_passed_to_stack; + + }else{ + if(handle_IPXWAN(skb->data, chan->name, + chan->enable_IPX, chan->network_number, + skb->protocol)){ + + if( chan->enable_IPX ){ + if(chan_send(dev, skb->data, skb->len,0)){ + chan->tx_skb = skb; + }else{ + wan_skb_free(skb); + ++chan->rx_intr_stat.rx_intr_bfr_not_passed_to_stack; + } + }else{ + /* increment IPX packet dropped statistic */ + ++chan->ifstats.rx_dropped; + ++chan->rx_intr_stat.rx_intr_bfr_not_passed_to_stack; + } + }else{ + skb->mac.raw = skb->data; + chan->ifstats.rx_bytes += skb->len; + + ++chan->ifstats.rx_packets; + ++chan->rx_intr_stat.rx_intr_bfr_passed_to_stack; + netif_rx(skb); + } + } + + return; +} + + +static int wanpipe_pull_data_in_skb (sdla_t *card, netdevice_t *dev, struct sk_buff **skb) +{ + void *bufptr; + wan_cmd_t rxmb_cmd; + unsigned len; /* packet length */ + unsigned qdm; /* Q,D and M bits */ + x25_channel_t *chan = dev->priv; + struct sk_buff *new_skb = *skb; + + card->hw_iface.peek(card->hw, card->rxmb_off, &rxmb_cmd, sizeof(rxmb_cmd)); + len = rxmb_cmd.wan_cmd_data_len; + qdm = rxmb_cmd.wan_cmd_x25_qdm; + + if (chan->common.usedby == WANPIPE){ + if (chan->drop_sequence){ + if (!(qdm & 0x01)){ + chan->drop_sequence = 0; + } + return 1; + } + if (chan->rx_skb) + new_skb = chan->rx_skb; + }else{ + /* Add on the API header to the received + * data + */ + len += sizeof(x25api_hdr_t); + } + + if (new_skb == NULL){ + int bufsize; + + if (chan->common.usedby == WANPIPE){ + bufsize = (qdm & 0x01) ? dev->mtu : len; + }else{ + bufsize = len; + } + + /* Allocate new socket buffer */ + new_skb = dev_alloc_skb(bufsize + 15); + if (new_skb == NULL){ + printk(KERN_INFO "%s: no socket buffers available!\n", + card->devname); + chan->drop_sequence = 1; /* set flag */ + ++chan->ifstats.rx_dropped; + return 1; + } + } + + if (skb_tailroom(new_skb) < len){ + /* No room for the packet. Call off the whole thing! */ + wan_skb_free(new_skb); + if (chan->common.usedby == WANPIPE){ + chan->rx_skb = NULL; + if (qdm & 0x01){ + chan->drop_sequence = 1; + } + } + + if(net_ratelimit()){ + printk(KERN_INFO "%s: unexpectedly long packet sequence " + "on interface %s!\n", card->devname, dev->name); + } + ++chan->ifstats.rx_length_errors; + return 1; + } + + bufptr = skb_put(new_skb,len); + + + if (chan->common.usedby == API){ + /* Fill in the x25api header + */ + x25api_t * api_data = (x25api_t*)bufptr; + api_data->hdr.qdm = rxmb_cmd.wan_cmd_x25_qdm; + api_data->hdr.cause = rxmb_cmd.wan_cmd_x25_cause; + api_data->hdr.diagn = rxmb_cmd.wan_cmd_x25_diagn; + api_data->hdr.length = rxmb_cmd.wan_cmd_data_len; + api_data->hdr.lcn = rxmb_cmd.wan_cmd_x25_lcn; + card->hw_iface.peek(card->hw, card->rxmb_off + offsetof(wan_mbox_t, wan_data), + api_data->data, rxmb_cmd.wan_cmd_data_len); + }else{ + card->hw_iface.peek(card->hw, card->rxmb_off + offsetof(wan_mbox_t, wan_data), + bufptr, len); + } + + new_skb->dev = dev; + + if (chan->common.usedby == API){ + new_skb->mac.raw = new_skb->data; + new_skb->protocol = htons(X25_PROT); + new_skb->pkt_type = WAN_PACKET_DATA; + }else{ + new_skb->protocol = chan->protocol; + } + + /* If qdm bit is set, more data is coming + * thus, exit and wait for more data before + * sending the packet up. (Used by router only) + */ + if ((qdm & 0x01) && (chan->common.usedby == WANPIPE)){ + chan->rx_skb = new_skb; + return 1; + } + + *skb = new_skb; + + return 0; +} + + +/*=============================================================== + * trace_intr + * + * Interrupt will be generated for each + * available trace frame. Copy the new trace + * frame into the trace queue. + * + *===============================================================*/ + +static void trace_intr(sdla_t *card) +{ + wan_mbox_t* mbox = &card->wan_mbox; + TX25Trace *trace; + int err; + struct sk_buff *skb; + unsigned char *buf; + struct timeval tv; + + + if (jiffies-card->u.x.trace_timeout > 3*HZ){ + wan_skb_queue_purge(&card->u.x.trace_queue); + DEBUG_EVENT("%s: Trace Timeout: disabling trace\n",card->devname); + memset(&mbox->wan_command, 0, sizeof(TX25Cmd)); + mbox->wan_command = XPIPE_DISABLE_TRACING; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mbox); + if (err){ + x25_error(card, err, XPIPE_DISABLE_TRACING, 0); + } + return; + } + + memset(&mbox->wan_command, 0, sizeof(TX25Cmd)); + mbox->wan_command = X25_READ_TRACE_DATA; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mbox); + if (err){ + x25_error(card, err, X25_READ_TRACE_DATA, 0); + return; + } + + trace = (TX25Trace*)mbox->wan_data; + + DEBUG_TEST("%s: Trace Interrupt Len %i\n", + card->devname,trace->length); + + card->u.x.trace_lost_cnt+=trace->lost_cnt; + + /* Trace length contains the lapb+x25hader+crc = 7 */ + if (trace->length > X25_MAX_DATA+7){ + DEBUG_EVENT("%s: Error: Trace data overflow len=%i > max=%i\n", + card->devname,trace->length,X25_MAX_DATA); + card->u.x.trace_lost_cnt++; + return; + } + + if (wan_skb_queue_len(&card->u.x.trace_queue) > MAX_X25_TRACE_QUEUE){ + DEBUG_EVENT("%s: Error: Trace queue overflow len=%i\n", + card->devname,MAX_X25_TRACE_QUEUE); + card->u.x.trace_lost_cnt++; + return; + } + + if (trace->lost_cnt){ + DEBUG_EVENT("%s: Error: Firmware trace queue overflow &m=%i\n", + card->devname,trace->lost_cnt); + } + + if (alloc_and_init_skb_buf(card,&skb,sizeof(trace_data_t)+trace->length)){ + card->u.x.trace_lost_cnt++; + return; + } + + buf = skb_put(skb,sizeof(trace_data_t)); + if (!buf){ + wan_skb_free(skb); + card->u.x.trace_lost_cnt++; + return; + } + + trace->lost_cnt=card->u.x.trace_lost_cnt; + card->u.x.trace_lost_cnt=0; + + memcpy(buf,trace,sizeof(TX25Trace)); + + /* Add an additional kernel timestamp */ + { + trace_data_t *trace_hdr=(trace_data_t *)buf; + do_gettimeofday(&tv); + trace_hdr->sec=tv.tv_sec; + trace_hdr->usec=tv.tv_usec; + } + + if (trace->length){ + buf = skb_put(skb,trace->length); + memcpy(buf,trace->data,trace->length); + } + + wan_skb_queue_tail(&card->u.x.trace_queue,skb); + + return; +} + +/*=============================================================== + * tx_intr + * + * Transmit interrupt handler. + * For each dev, check that there is something to send. + * If data available, transmit. + * + *===============================================================*/ + +static void tx_intr (sdla_t* card) +{ + netdevice_t *dev; + unsigned char more_to_tx=0; + TX25Status status; + u8 tmp; + x25_channel_t *chan=NULL; + int i=0; + + card->hw_iface.peek(card->hw, card->flags_off, &status, sizeof(status)); +#if 1 + /* Try sending an async packet first */ + if (card->u.x.timer_int_enabled & TMR_INT_ENABLED_CMD_EXEC){ + if (tx_intr_cmd_exec(card) == 0){ + if (atomic_read(&card->u.x.tx_interrupt_cmd) <= 0){ + atomic_set(&card->u.x.tx_interrupt_cmd,0); + card->u.x.timer_int_enabled &= + ~TMR_INT_ENABLED_CMD_EXEC; + }else{ + return; + } + }else{ + /* There are more commands pending + * re-trigger tx interrupt */ + return; + } + } +#endif + + if (card->u.x.tx_dev == NULL){ + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + card->u.x.tx_dev = dev; + } + + dev = card->u.x.tx_dev; + + for (;;){ + + chan = dev->priv; + if (!chan || !(dev->flags&IFF_UP)){ + dev = move_dev_to_next(card,dev); + goto tx_dev_skip; + } + + if (chan->transmit_length){ + /* Device was set to transmit, check if the TX + * buffers are available + */ + if (chan->common.state != WAN_CONNECTED){ + chan->transmit_length = 0; + chan->tx_offset=0; + + ++card->wandev.stats.tx_dropped; + ++chan->ifstats.tx_dropped; + + if (is_queue_stopped(dev)){ + if (chan->common.usedby == API){ + start_net_queue(dev); + wakeup_sk_bh(dev); + }else{ + wake_net_dev(dev); + } + } + dev = move_dev_to_next(card,dev); + break; + } + + card->hw_iface.peek(card->hw, card->u.x.hdlc_buf_status_off, &tmp, 1); + if ((status.cflags[chan->ch_idx] & 0x40 || card->u.x.LAPB_hdlc) && + (tmp & 0x40) ){ + /* Tx buffer available, we can send */ + + if (tx_intr_send(card, dev)){ + more_to_tx=1; + } + + /* If more than one interface present, move the + * device pointer to the next interface, so on the + * next TX interrupt we will try sending from it. + */ + dev = move_dev_to_next(card,dev); + break; + }else{ + /* Tx buffers not available, but device set + * the TX interrupt. Set more_to_tx and try + * to transmit for other devices. + */ + more_to_tx=1; + dev = move_dev_to_next(card,dev); + } + + }else{ + /* This device was not set to transmit, + * go to next + */ + dev = move_dev_to_next(card,dev); + } +tx_dev_skip: + if (++i >= card->u.x.no_dev){ + if (!more_to_tx){ + DBG_PRINTK(KERN_INFO "%s: Nothing to Send in TX INTR\n", + card->devname); + } + break; + } + + } //End of FOR + + card->u.x.tx_dev = dev; + + if (!more_to_tx){ + /* if any other interfaces have transmit interrupts pending, */ + /* do not disable the global transmit interrupt */ + atomic_dec(&card->u.x.tx_interrupts_pending); + if (atomic_read(&card->u.x.tx_interrupts_pending) <= 0){ + atomic_set(&card->u.x.tx_interrupts_pending,0); + card->hw_iface.clear_bit(card->hw, card->intr_perm_off, INTR_ON_TX_FRAME); + } + } + return; +} + +/*=============================================================== + * move_dev_to_next + * + * + *===============================================================*/ + + +netdevice_t * move_dev_to_next (sdla_t *card, netdevice_t *dev) +{ + struct wan_dev_le *devle; + + if (card->u.x.no_dev == 1){ + return dev; + } + + WAN_LIST_FOREACH(devle, &card->wandev.dev_head, dev_link){ + if (devle->dev == dev){ + dev = WAN_DEVLE2DEV(WAN_LIST_NEXT(devle, dev_link)); + if (!dev){ + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + } + return dev; + } + } + return dev; +} + +/*=============================================================== + * tx_intr_send + * + * + *===============================================================*/ + +static int tx_intr_send(sdla_t *card, netdevice_t *dev) +{ + x25_channel_t* chan = dev->priv; + + if (chan_send (dev,chan->transmit_buffer,chan->transmit_length,1)){ + + /* Packet was split up due to its size, do not disable + * tx_intr + */ + return 1; + } + + chan->transmit_length=0; + chan->tx_offset=0; + + /* If we are in API mode, wakeup the + * sock BH handler, not the NET_BH */ + if (is_queue_stopped(dev)){ + if (chan->common.usedby == API){ + start_net_queue(dev); + wakeup_sk_bh(dev); + }else{ + wake_net_dev(dev); + } + } + return 0; +} + + +/*=============================================================== + * timer_intr + * + * Timer interrupt handler. + * Check who called the timer interrupt and perform + * action accordingly. + * + *===============================================================*/ + +static void timer_intr (sdla_t *card) +{ + u8 tmp; + + DEBUG_TEST("%s: Timer inter 0x%X\n", + card->devname,card->u.x.timer_int_enabled); + + if(card->u.x.timer_int_enabled & TMR_INT_ENABLED_UDP_PKT) { + + card->hw_iface.peek(card->hw, card->u.x.hdlc_buf_status_off, &tmp, 1); + if ((tmp & 0x40) && card->u.x.udp_type == UDP_XPIPE_TYPE){ + + if(process_udp_mgmt_pkt(card,NULL)) { + card->u.x.timer_int_enabled &= + ~TMR_INT_ENABLED_UDP_PKT; + } + } + + }else if (card->u.x.timer_int_enabled & TMR_INT_ENABLED_POLL_ACTIVE) { + + netdevice_t *dev = card->u.x.poll_device; + x25_channel_t *chan = NULL; + + if (!dev){ + card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_POLL_ACTIVE; + return; + } + chan = dev->priv; + + printk(KERN_INFO + "%s: Closing down Idle link %s on LCN %d\n", + card->devname,chan->name,chan->common.lcn); + chan->i_timeout_sofar = jiffies; + chan_disc(dev); + card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_POLL_ACTIVE; + card->u.x.poll_device=NULL; + + }else if (card->u.x.timer_int_enabled & TMR_INT_ENABLED_POLL_CONNECT_ON) { + + wanpipe_set_state(card, WAN_CONNECTED); + if (card->u.x.LAPB_hdlc){ + netdevice_t *dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + set_chan_state(dev,WAN_CONNECTED); + } + + /* 0x8F enable all interrupts */ + x25_set_intr_mode(card, INTR_ON_RX_FRAME| + INTR_ON_TX_FRAME| + INTR_ON_MODEM_STATUS_CHANGE| + //INTR_ON_COMMAND_COMPLETE| + X25_ASY_TRANS_INTR_PENDING | + INTR_ON_TIMER | + DIRECT_RX_INTR_USAGE | + INTR_ON_TRACE_DATA + ); + + card->hw_iface.clear_bit(card->hw, card->intr_perm_off, INTR_ON_TX_FRAME); + card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_POLL_CONNECT_ON; + + }else if (card->u.x.timer_int_enabled & TMR_INT_ENABLED_POLL_CONNECT_OFF) { + + DBG_PRINTK(KERN_INFO "Poll connect, Turning OFF\n"); + disconnect(card); + if (card->u.x.LAPB_hdlc){ + netdevice_t *dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + /* FIXME: CRITICAL NO MAILBOX */ + send_oob_msg(card,dev,&card->wan_mbox); + set_chan_state(dev,WAN_DISCONNECTED); + } + card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_POLL_CONNECT_OFF; + + }else if (card->u.x.timer_int_enabled & TMR_INT_ENABLED_POLL_DISCONNECT) { + + DBG_PRINTK(KERN_INFO "Poll disconnect, trying to connect\n"); + connect(card); + if (card->u.x.LAPB_hdlc){ + netdevice_t *dev; + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + set_chan_state(dev,WAN_CONNECTED); + } + card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_POLL_DISCONNECT; + + }else if (card->u.x.timer_int_enabled & TMR_INT_ENABLED_UPDATE){ + + card->hw_iface.peek(card->hw, card->u.x.hdlc_buf_status_off, &tmp, 1); + if (tmp & 0x40){ + x25_get_err_stats(card); + x25_get_stats(card); + card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_UPDATE; + } + } + + if(!(card->u.x.timer_int_enabled & ~TMR_INT_ENABLED_CMD_EXEC)){ + //printk(KERN_INFO "Turning Timer Off \n"); + card->hw_iface.clear_bit(card->hw, card->intr_perm_off, INTR_ON_TIMER); + } +} + +/*==================================================================== + * Modem status interrupt handler. + *===================================================================*/ +static void status_intr (sdla_t* card) +{ + + /* Added to avoid Modem status message flooding */ + static TX25ModemStatus last_stat; + + wan_mbox_t* mbox = &card->wan_mbox; + TX25ModemStatus *modem_status; + netdevice_t *dev; + x25_channel_t *chan; + int err; + + memset(&mbox->wan_command, 0, sizeof(TX25Cmd)); + mbox->wan_command = X25_READ_MODEM_STATUS; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mbox); + if (err){ + x25_error(card, err, X25_READ_MODEM_STATUS, 0); + }else{ + + modem_status = (TX25ModemStatus*)mbox->wan_data; + + /* Check if the last status was the same + * if it was, do NOT print message again */ + + if (last_stat.status != modem_status->status){ + + printk(KERN_INFO "%s: Modem Status Change: DCD=%s, CTS=%s\n", + card->devname, + DCD(modem_status->status), + CTS(modem_status->status)); + + last_stat.status = modem_status->status; + + if (card->u.x.oob_on_modem){ + struct wan_dev_le *devle; + + DBG_PRINTK(KERN_INFO "Modem status oob msg!\n"); + + mbox->wan_x25_pktType = mbox->wan_command; + mbox->wan_return_code = 0x08; + + /* Send a OOB to all connected sockets */ + WAN_LIST_FOREACH(devle, &card->wandev.dev_head, dev_link){ + dev = WAN_DEVLE2DEV(devle); + chan=dev->priv; + if (chan->common.usedby == API){ + send_oob_msg(card,dev,mbox); + } + } + } + } + } + + memset(&mbox->wan_command, 0, sizeof(TX25Cmd)); + mbox->wan_command = X25_HDLC_LINK_STATUS; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mbox); + if (err){ + x25_error(card, err, X25_HDLC_LINK_STATUS, 0); + } + +} + +/*==================================================================== + * Network event interrupt handler. + *===================================================================*/ +static void event_intr (sdla_t* card) +{ + x25_fetch_events(card); +} + +/*==================================================================== + * Spurious interrupt handler. + * o print a warning + * o + *====================================================================*/ + +static void spur_intr (sdla_t* card) +{ + printk(KERN_INFO "%s: spurious interrupt!\n", card->devname); +} + + +/* + * Background Polling Routines + */ + +/*==================================================================== + * Main polling routine. + * This routine is repeatedly called by the WANPIPE 'thead' to allow for + * time-dependent housekeeping work. + * + * Notes: + * 1. This routine may be called on interrupt context with all interrupts + * enabled. Beware! + *====================================================================*/ + +static void wpx_poll (void *card_ptr) +{ + sdla_t *card=card_ptr; + netdevice_t *dev; + + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + if (dev == NULL) + goto wpx_poll_exit; + + if (card->open_cnt != card->u.x.num_of_ch){ + goto wpx_poll_exit; + } + + if (test_bit(PERI_CRIT,&card->wandev.critical)){ + goto wpx_poll_exit; + } + + if (test_bit(SEND_CRIT,&card->wandev.critical)){ + goto wpx_poll_exit; + } + + switch(card->wandev.state){ + case WAN_CONNECTED: + poll_active(card); + break; + + case WAN_CONNECTING: + poll_connecting(card); + break; + + case WAN_DISCONNECTED: + poll_disconnected(card); + break; + } + +wpx_poll_exit: + clear_bit(POLL_CRIT,&card->wandev.critical); + return; +} + +static void trigger_x25_poll(sdla_t *card) +{ + wan_schedule_task(&card->u.x.x25_poll_task); +} + +/*==================================================================== + * Handle physical link establishment phase. + * o if connection timed out, disconnect the link. + *===================================================================*/ + +static void poll_connecting (sdla_t* card) +{ + unsigned char gflags; + + card->hw_iface.peek(card->hw, card->flags_off + offsetof(TX25Status, gflags), &gflags, 1); + + DEBUG_TEST("%s: Poll Connecting 0x%X\n",card->devname,gflags); + + if (gflags & X25_HDLC_ABM){ + + trigger_intr_exec (card, TMR_INT_ENABLED_POLL_CONNECT_ON); + + }else if ((jiffies - card->state_tick) > CONNECT_TIMEOUT){ + + trigger_intr_exec (card, TMR_INT_ENABLED_POLL_CONNECT_OFF); + + } +} + +/*==================================================================== + * Handle physical link disconnected phase. + * o if hold-down timeout has expired and there are open interfaces, + * connect link. + *===================================================================*/ + +static void poll_disconnected (sdla_t* card) +{ + netdevice_t *dev; + x25_channel_t *chan; + + if (!card->u.x.LAPB_hdlc && card->open_cnt && + ((jiffies - card->state_tick) > HOLD_DOWN_TIME)){ + trigger_intr_exec(card, TMR_INT_ENABLED_POLL_DISCONNECT); + } + + if ((dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head))) == NULL) + return; + + if ((chan=dev->priv) == NULL) + return; + +} + +/*==================================================================== + * Handle active link phase. + * o fetch X.25 asynchronous events. + * o kick off transmission on all interfaces. + *===================================================================*/ + +static void poll_active (sdla_t* card) +{ + struct wan_dev_le *devle; + netdevice_t* dev; + unsigned long flags; + wan_mbox_t* mbox = &card->wan_mbox; + TX25Status status; + unsigned char modem_status; + unsigned char tx_timeout; + + card->hw_iface.peek(card->hw, X25_TX_TIMEOUT_OFFS, &tx_timeout, 1); + if (tx_timeout){ + tx_timeout=0; + card->hw_iface.poke(card->hw, X25_TX_TIMEOUT_OFFS, &tx_timeout, 1); + DEBUG_EVENT("%s: Tx Timeout: no clock, disconnecting! \n", + card->devname); + + spin_lock_irqsave(&card->wandev.lock, flags); + memset(&mbox->wan_command, 0, sizeof(TX25Cmd)); + mbox->wan_command = X25_HDLC_LINK_STATUS; + card->hw_iface.cmd(card->hw, card->mbox_off, mbox); + spin_unlock_irqrestore(&card->wandev.lock, flags); + + x25_down_event (card, X25_HDLC_LINK_STATUS, 0, mbox,ASE_MODEM_DOWN); + trigger_intr_exec(card, TMR_INT_ENABLED_POLL_DISCONNECT); + return; + } + + card->hw_iface.peek(card->hw, X25_MODEM_STATE_OFFS, &modem_status, 1); + + if (!(modem_status&X25_CTS_MASK) || !(modem_status&X25_DCD_MASK)){ + if (card->wandev.ignore_front_end_status == WANOPT_NO){ + + DEBUG_EVENT("%s: Modem state down! DCD=%s CTS=%s\n", + card->devname, + DCD(modem_status), + CTS(modem_status)); + + spin_lock_irqsave(&card->wandev.lock, flags); + memset(&mbox->wan_command, 0, sizeof(TX25Cmd)); + mbox->wan_command = X25_HDLC_LINK_STATUS; + card->hw_iface.cmd(card->hw, card->mbox_off, mbox); + spin_unlock_irqrestore(&card->wandev.lock, flags); + + x25_down_event (card, X25_HDLC_LINK_STATUS, 0, mbox,ASE_MODEM_DOWN); + trigger_intr_exec(card, TMR_INT_ENABLED_POLL_DISCONNECT); + return; + } + } + + card->hw_iface.peek(card->hw, card->flags_off, &status, sizeof(status)); + + if (!(status.gflags & X25_HDLC_ABM)){ + + DEBUG_EVENT("%s: Lapb hdlc link down!\n",card->devname); + + spin_lock_irqsave(&card->wandev.lock, flags); + memset(&mbox->wan_command, 0, sizeof(TX25Cmd)); + mbox->wan_command = X25_HDLC_LINK_STATUS; + card->hw_iface.cmd(card->hw, card->mbox_off, mbox); + spin_unlock_irqrestore(&card->wandev.lock, flags); + + x25_down_event (card, X25_HDLC_LINK_STATUS, 0, mbox,ASE_LAPB_DOWN); + trigger_intr_exec(card, TMR_INT_ENABLED_POLL_DISCONNECT); + return; + } + + + WAN_LIST_FOREACH(devle, &card->wandev.dev_head, dev_link){ + x25_channel_t* chan; + + dev = WAN_DEVLE2DEV(devle); + if (!dev || !wan_netif_priv(dev)) continue; + chan = wan_netif_priv(dev); + + /* If SVC has been idle long enough, close virtual circuit */ + if ( chan->common.svc && + chan->common.state == WAN_CONNECTED && + chan->common.usedby == WANPIPE ){ + + if( (jiffies - chan->i_timeout_sofar) / HZ > chan->idle_timeout ){ + /* Close svc */ + card->u.x.poll_device=dev; + trigger_intr_exec (card, TMR_INT_ENABLED_POLL_ACTIVE); + } + } + + + /* Check if the api aplication has gone + * away but failed to disconnect the svc */ + + if (chan->common.state == WAN_CONNECTED && + atomic_read(&chan->common.disconnect) && + !chan->common.sk && chan->common.svc && + chan->common.lcn){ + + unsigned long flags; + + /* The Application tired to exit, but + * couldn't shut down the link via + * clear call. Possibly due to flow + * control condition */ + + DEBUG_EVENT("%s:%s: Poll Active trying to clear call on lcn %i\n", + card->devname,chan->common.dev->name,chan->common.lcn); + + + spin_lock_irqsave(&card->wandev.lock, flags); + if (x25_clear_call(card,chan->common.lcn, + chan->x25_api_cmd_hdr.cause, + chan->x25_api_cmd_hdr.diagn,0,NULL,0) == 0){ + atomic_set(&chan->common.disconnect,0); + } + spin_unlock_irqrestore(&card->wandev.lock, flags); + + } + } +} + +static void trigger_intr_exec(sdla_t *card, unsigned char TYPE) +{ + u8 intr_perm = 0x00; + card->u.x.timer_int_enabled |= TYPE; + + if (TYPE == TMR_INT_ENABLED_CMD_EXEC){ + atomic_inc(&card->u.x.tx_interrupt_cmd); + card->hw_iface.set_bit(card->hw, card->intr_perm_off, INTR_ON_TX_FRAME); + }else{ + card->hw_iface.peek(card->hw, card->intr_perm_off, &intr_perm, 1); + if (!(intr_perm & INTR_ON_TIMER)){ + card->hw_iface.set_bit(card->hw, card->intr_perm_off, INTR_ON_TIMER); + } + } +} + +/*==================================================================== + * SDLA Firmware-Specific Functions + * + * Almost all X.25 commands can unexpetedly fail due to so called 'X.25 + * asynchronous events' such as restart, interrupt, incoming call request, + * call clear request, etc. They can't be ignored and have to be delt with + * immediately. To tackle with this problem we execute each interface + * command in a loop until good return code is received or maximum number + * of retries is reached. Each interface command returns non-zero return + * code, an asynchronous event/error handler x25_error() is called. + *====================================================================*/ + +/*==================================================================== + * Read X.25 firmware version. + * Put code version as ASCII string in str. + *===================================================================*/ + +static int x25_get_version (sdla_t* card, char* str) +{ + wan_mbox_t* mbox = &card->wan_mbox; + int retry = MAX_CMD_RETRY; + int err; + + do + { + memset(&mbox->wan_command, 0, sizeof(TX25Cmd)); + mbox->wan_command = X25_READ_CODE_VERSION; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mbox); + } while (err && x25_error(card, err, X25_READ_CODE_VERSION, 0) && retry--); + + if (!err && str) + { + int len = mbox->wan_data_len; + + memcpy(str, mbox->wan_data, len); + str[len] = '\0'; + } + return err; +} + +/*==================================================================== + * Configure adapter. + *===================================================================*/ + +static int x25_configure (sdla_t* card, TX25Config* conf) +{ + wan_mbox_t* mbox = &card->wan_mbox; + int retry = MAX_CMD_RETRY; + int err; + + do{ + memset(&mbox->wan_command, 0, sizeof(TX25Cmd)); + memcpy(mbox->wan_data, (void*)conf, sizeof(TX25Config)); + mbox->wan_data_len = sizeof(TX25Config); + mbox->wan_command = X25_SET_CONFIGURATION; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mbox); + } while (err && x25_error(card, err, X25_SET_CONFIGURATION, 0) && retry-- ); + return err; +} + +/*==================================================================== + * Configure adapter for HDLC only. + *===================================================================*/ + +static int hdlc_configure (sdla_t* card, TX25Config* conf) +{ + wan_mbox_t* mbox = &card->wan_mbox; + int retry = MAX_CMD_RETRY; + int err; + + do{ + memset(&mbox->wan_command, 0, sizeof(TX25Cmd)); + memcpy(mbox->wan_data, (void*)conf, sizeof(TX25Config)); + mbox->wan_data_len = sizeof(TX25Config); + mbox->wan_command = X25_HDLC_SET_CONFIG; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mbox); + } while (err && x25_error(card, err, X25_SET_CONFIGURATION, 0) && retry--); + + return err; +} + +static int set_hdlc_level (sdla_t* card) +{ + wan_mbox_t* mbox = &card->wan_mbox; + int retry = MAX_CMD_RETRY; + int err; + + do{ + memset(&mbox->wan_command, 0, sizeof(TX25Cmd)); + mbox->wan_command = SET_PROTOCOL_LEVEL; + mbox->wan_data_len = 1; + mbox->wan_data[0] = HDLC_LEVEL; //| DO_HDLC_LEVEL_ERROR_CHECKING; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mbox); + } while (err && x25_error(card, err, SET_PROTOCOL_LEVEL, 0) && retry--); + + return err; +} + + + +/*==================================================================== + * Get communications error statistics. + *====================================================================*/ + +static int x25_get_err_stats (sdla_t* card) +{ + wan_mbox_t* mbox = &card->wan_mbox; + int retry = MAX_CMD_RETRY; + int err; + + do + { + memset(&mbox->wan_command, 0, sizeof(TX25Cmd)); + mbox->wan_command = X25_HDLC_READ_COMM_ERR; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mbox); + } while (err && x25_error(card, err, X25_HDLC_READ_COMM_ERR, 0) && retry--); + + if (!err) + { + THdlcCommErr* stats = (void*)mbox->wan_data; + + card->wandev.stats.rx_over_errors = stats->rxOverrun; + card->wandev.stats.rx_crc_errors = stats->rxBadCrc; + card->wandev.stats.rx_missed_errors = stats->rxAborted; + card->wandev.stats.tx_aborted_errors = stats->txAborted; + } + return err; +} + +/*==================================================================== + * Get protocol statistics. + *===================================================================*/ + +static int x25_get_stats (sdla_t* card) +{ + wan_mbox_t* mbox = &card->wan_mbox; + int retry = MAX_CMD_RETRY; + int err; + + do + { + memset(&mbox->wan_command, 0, sizeof(TX25Cmd)); + mbox->wan_command = X25_READ_STATISTICS; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mbox); + } while (err && x25_error(card, err, X25_READ_STATISTICS, 0) && retry--) ; + + if (!err) + { + TX25Stats* stats = (void*)mbox->wan_data; + + card->wandev.stats.rx_packets = stats->rxData; + card->wandev.stats.tx_packets = stats->txData; + memcpy(&X25Stats, mbox->wan_data, mbox->wan_data_len); + } + return err; +} + +/*==================================================================== + * Close HDLC link. + *===================================================================*/ + +static int x25_close_hdlc (sdla_t* card) +{ + wan_mbox_t* mbox = &card->wan_mbox; + int retry = MAX_CMD_RETRY; + int err; + + do + { + memset(&mbox->wan_command, 0, sizeof(TX25Cmd)); + mbox->wan_command = X25_HDLC_LINK_CLOSE; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mbox); + } while (err && x25_error(card, err, X25_HDLC_LINK_CLOSE, 0) && retry--); + + return err; +} + + +/*==================================================================== + * Open HDLC link. + *===================================================================*/ + +static int x25_open_hdlc (sdla_t* card) +{ + wan_mbox_t* mbox = &card->wan_mbox; + int retry = MAX_CMD_RETRY; + int err; + + do + { + memset(&mbox->wan_command, 0, sizeof(TX25Cmd)); + mbox->wan_command = X25_HDLC_LINK_OPEN; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mbox); + } while (err && x25_error(card, err, X25_HDLC_LINK_OPEN, 0) && retry--); + + return err; +} + +/*===================================================================== + * Setup HDLC link. + *====================================================================*/ +static int x25_setup_hdlc (sdla_t* card) +{ + wan_mbox_t* mbox = &card->wan_mbox; + int retry = MAX_CMD_RETRY; + int err; + + do + { + memset(&mbox->wan_command, 0, sizeof(TX25Cmd)); + mbox->wan_command = X25_HDLC_LINK_SETUP; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mbox); + } while (err && x25_error(card, err, X25_HDLC_LINK_SETUP, 0) && retry--); + + return err; +} + +/*==================================================================== + * Set (raise/drop) DTR. + *===================================================================*/ + +static int x25_set_dtr (sdla_t* card, int dtr) +{ + wan_mbox_t* mbox = &card->wan_mbox; + int retry = MAX_CMD_RETRY; + int err; + + do + { + memset(&mbox->wan_command, 0, sizeof(TX25Cmd)); + mbox->wan_data[0] = 0; + mbox->wan_data[2] = 0; + mbox->wan_data[1] = dtr ? 0x02 : 0x01; + mbox->wan_data_len = 3; + mbox->wan_command = X25_SET_GLOBAL_VARS; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mbox); + } while (err && x25_error(card, err, X25_SET_GLOBAL_VARS, 0) && retry-- ); + + return err; +} + +/*==================================================================== + * Set interrupt mode. + *===================================================================*/ + +static int x25_set_intr_mode (sdla_t* card, int mode) +{ + wan_mbox_t* mbox = &card->wan_mbox; + int retry = MAX_CMD_RETRY; + int err; + + do + { + memset(&mbox->wan_command, 0, sizeof(TX25Cmd)); + mbox->wan_data[0] = mode; + mbox->wan_data[1] = card->wandev.irq; // ALEX_TODAY card->hw.irq; + mbox->wan_data[2] = 2; + mbox->wan_data_len = 3; + mbox->wan_command = X25_SET_INTERRUPT_MODE; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mbox); + } while (err && x25_error(card, err, X25_SET_INTERRUPT_MODE, 0) && retry--); + + return err; +} + +/*==================================================================== + * Read X.25 channel configuration. + *===================================================================*/ + +static int x25_get_chan_conf (sdla_t* card, x25_channel_t* chan) +{ + wan_mbox_t* mbox = &card->wan_mbox; + int retry = MAX_CMD_RETRY; + int lcn = chan->common.lcn; + int err; + + do{ + memset(&mbox->wan_command, 0, sizeof(TX25Cmd)); + mbox->wan_x25_lcn = lcn; + mbox->wan_command = X25_READ_CHANNEL_CONFIG; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mbox); + } while (err && x25_error(card, err, X25_READ_CHANNEL_CONFIG, lcn) && retry--); + + if (!err){ + TX25Status status; + + card->hw_iface.peek(card->hw, card->flags_off, &status, sizeof(status)); + /* calculate an offset into the array of status bytes */ + if (card->u.x.x25_conf.hi_svc <= X25_MAX_CHAN){ + + chan->ch_idx = lcn - 1; + + }else{ + int offset; + + /* FIX: Apr 14 2000 : Nenad Corbic + * The data field was being compared to 0x1F using + * '&&' instead of '&'. + * This caused X25API to fail for LCNs greater than 255. + */ + switch (mbox->wan_data[0] & 0x1F) + { + case 0x01: + offset = status.pvc_map; break; + case 0x03: + offset = status.icc_map; break; + case 0x07: + offset = status.twc_map; break; + case 0x0B: + offset = status.ogc_map; break; + default: + offset = 0; + } + chan->ch_idx = lcn - 1 - offset; + } + + /* get actual transmit packet size on this channel */ + switch(mbox->wan_data[1] & 0x38) + { + case 0x00: + chan->tx_pkt_size = 16; + break; + case 0x08: + chan->tx_pkt_size = 32; + break; + case 0x10: + chan->tx_pkt_size = 64; + break; + case 0x18: + chan->tx_pkt_size = 128; + break; + case 0x20: + chan->tx_pkt_size = 256; + break; + case 0x28: + chan->tx_pkt_size = 512; + break; + case 0x30: + chan->tx_pkt_size = 1024; + break; + } + if (card->u.x.logging) + printk(KERN_INFO "%s: X.25 packet size on LCN %d is %d.\n", + card->devname, lcn, chan->tx_pkt_size); + } + return err; +} + +/*==================================================================== + * Place X.25 call. + *====================================================================*/ + +static int x25_place_call (sdla_t* card, x25_channel_t* chan) +{ + wan_mbox_t* mbox = &card->wan_mbox; + int retry = MAX_CMD_RETRY; + int err; + + if (chan->common.usedby == WANPIPE){ + if (chan->protocol == htons(ETH_P_IP)){ + + if(strcmp(&chan->x25_src_addr[0], "") == 0){ + sprintf(chan->call_string, "-d%s -uCC", chan->addr); + }else{ + //the source address was supplied + sprintf(chan->call_string, "-d%s -s%s -uCC", + chan->addr, + chan->x25_src_addr); + } + + printk(KERN_INFO "%s: Call String : %s \n", card->devname, chan->call_string); + + }else if (chan->protocol == htons(ETH_P_IPX)){ + sprintf(chan->call_string, "-d%s -u800000008137", chan->addr); + + } + + } + + do + { + memset(&mbox->wan_command, 0, sizeof(TX25Cmd)); + strcpy(mbox->wan_data, chan->call_string); + mbox->wan_data_len = strlen(chan->call_string); + mbox->wan_command = X25_PLACE_CALL; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mbox); + } while (err && x25_error(card, err, X25_PLACE_CALL, 0) && retry--); + + if (!err){ + bind_lcn_to_dev (card, chan->common.dev, mbox->wan_x25_lcn); + } + + chan->x25_api_event.hdr.qdm = mbox->wan_x25_qdm; + chan->x25_api_event.hdr.cause = mbox->wan_x25_cause; + chan->x25_api_event.hdr.diagn = mbox->wan_x25_diagn; + chan->x25_api_event.hdr.pktType = mbox->wan_x25_pktType&0x7F; + chan->x25_api_event.hdr.length = 0; + chan->x25_api_event.hdr.result = 0; + chan->x25_api_event.hdr.lcn = mbox->wan_x25_lcn; + chan->x25_api_event.hdr.mtu = card->u.x.x25_conf.defPktSize; + chan->x25_api_event.hdr.mru = card->u.x.x25_conf.defPktSize; + + + return err; +} + +/*==================================================================== + * Accept X.25 call. + *====================================================================*/ + +static int x25_accept_call (sdla_t* card, int lcn, int qdm, unsigned char *data, int len) +{ + wan_mbox_t* mbox = &card->wan_mbox; + int retry = MAX_CMD_RETRY; + int err; + + do + { + memset(&mbox->wan_command, 0, sizeof(TX25Cmd)); + mbox->wan_x25_lcn = lcn; + mbox->wan_x25_qdm = qdm; + mbox->wan_command = X25_ACCEPT_CALL; + if (len){ + mbox->wan_data_len = len; + strncpy(mbox->wan_data,data,len); + } + err = card->hw_iface.cmd(card->hw, card->mbox_off, mbox); + } while (err && x25_error(card, err, X25_ACCEPT_CALL, lcn) && retry--); + + return err; +} + +static int x25_interrupt (sdla_t* card, int lcn, int qdm, unsigned char *data, int len) +{ + wan_mbox_t* mbox = &card->wan_mbox; + int retry = MAX_CMD_RETRY; + int err; + + do + { + memset(&mbox->wan_command, 0, sizeof(TX25Cmd)); + mbox->wan_x25_lcn = lcn; + mbox->wan_x25_qdm = qdm; + mbox->wan_command = X25_WP_INTERRUPT; + if (len){ + mbox->wan_data_len = len; + strncpy(mbox->wan_data,data,len); + } + err = card->hw_iface.cmd(card->hw, card->mbox_off, mbox); + } while (err && x25_error(card, err, X25_WP_INTERRUPT, lcn) && retry--); + + return err; +} + + +/*==================================================================== + * Clear X.25 call. + *====================================================================*/ + +static int x25_clear_call (sdla_t* card, int lcn, int cause, + int diagn, int qdm, + unsigned char *data, int len) +{ + wan_mbox_t* mbox = &card->wan_mbox; + int retry = MAX_CMD_RETRY; + int err; + + DEBUG_TEST("%s:%s: LCN=%i QDM %x\n",__FUNCTION__,card->devname,lcn,qdm); + do + { + memset(&mbox->wan_command, 0, sizeof(TX25Cmd)); + mbox->wan_x25_qdm = qdm; + mbox->wan_x25_lcn = lcn; + mbox->wan_x25_cause = cause; + mbox->wan_x25_diagn = diagn; + mbox->wan_command = X25_CLEAR_CALL; + if (len){ + mbox->wan_data_len = len; + strncpy(mbox->wan_data,data,len); + } + err = card->hw_iface.cmd(card->hw, card->mbox_off, mbox); + + } while (err && x25_error(card, err, X25_CLEAR_CALL, lcn) && retry--); + + return err; +} + +static int x25_reset_call (sdla_t* card, int lcn, int cause, int diagn, int qdm) +{ + wan_mbox_t* mbox = &card->wan_mbox; + int retry = MAX_CMD_RETRY; + int err; + + DEBUG_TEST("%s:%s: LCN=%i QDM %x\n",__FUNCTION__,card->devname,lcn,qdm); + do + { + memset(&mbox->wan_command, 0, sizeof(TX25Cmd)); + mbox->wan_x25_qdm = qdm; + mbox->wan_x25_lcn = lcn; + mbox->wan_x25_cause = cause; + mbox->wan_x25_diagn = diagn; + mbox->wan_command = X25_RESET; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mbox); + + } while (err && x25_error(card, err, X25_RESET, lcn) && retry--); + + return err; +} + + +/*==================================================================== + * Send X.25 data packet. + *====================================================================*/ + +static int x25_send (sdla_t* card, int lcn, int qdm, int len, void* buf) +{ + wan_mbox_t* mbox = &card->wan_mbox; + int retry = MAX_CMD_RETRY; + int err; + unsigned char cmd; + + if (card->u.x.LAPB_hdlc) + cmd = X25_HDLC_WRITE; + else + cmd = X25_WRITE; + + do + { + memset(&mbox->wan_command, 0, sizeof(TX25Cmd)); + memcpy(mbox->wan_data, buf, len); + mbox->wan_data_len = (unsigned short)len; + mbox->wan_x25_lcn = (unsigned short)lcn; + + if (card->u.x.LAPB_hdlc){ + mbox->wan_x25_pf = (unsigned char)qdm; + }else{ + mbox->wan_x25_qdm = (unsigned char)qdm; + } + + mbox->wan_command = cmd; + + /* The P6-PCI caching used to be a bug on old + * S514 prototype boards. This has been fixed, + * however the check below is a sanity check */ + if (mbox->wan_opp_flag){ + printk(KERN_INFO "\n"); + printk(KERN_INFO "%s: Critical Error: P6-PCI Cache bug!\n", + card->devname); + printk(KERN_INFO "%s: Please contact Sangoma Tech Support!\n\n", + card->devname); + } + + err = card->hw_iface.cmd(card->hw, card->mbox_off, mbox); + + } while (err && x25_error(card, err, cmd , lcn) && retry--); + + + /* If buffers are busy the return code for LAPB HDLC is + * 1. The above functions are looking for return code + * of X25RES_NOT_READY if busy. */ + if (card->u.x.LAPB_hdlc && err == 1){ + err = X25RES_NOT_READY; + } + + return err; +} + +/*==================================================================== + * Fetch X.25 asynchronous events. + *===================================================================*/ + +static int x25_fetch_events (sdla_t* card) +{ + unsigned char gflags; + wan_mbox_t* mbox = &card->wan_mbox; + int err = 0; + + card->hw_iface.peek(card->hw, card->flags_off + offsetof(TX25Status, gflags), &gflags, 1); + if (gflags & 0x20) + { + memset(&mbox->wan_command, 0, sizeof(TX25Cmd)); + mbox->wan_command = X25_IS_DATA_AVAILABLE; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mbox); + if (err) x25_error(card, err, X25_IS_DATA_AVAILABLE, 0); + } + return err; +} + +/*==================================================================== + * X.25 asynchronous event/error handler. + * This routine is called each time interface command returns + * non-zero return code to handle X.25 asynchronous events and + * common errors. Return non-zero to repeat command or zero to + * cancel it. + * + * Notes: + * 1. This function may be called recursively, as handling some of the + * asynchronous events (e.g. call request) requires execution of the + * interface command(s) that, in turn, may also return asynchronous + * events. To avoid re-entrancy problems we copy mailbox to dynamically + * allocated memory before processing events. + *====================================================================*/ + +static int x25_error (sdla_t* card, int err, int cmd, int lcn) +{ + int retry = 1; + wan_mbox_t* mb = &card->wan_mbox; + unsigned dlen = mb->wan_data_len; + +#if 0 + mb = kmalloc(sizeof(wan_mbox_t) + dlen, GFP_ATOMIC); + if (mb == NULL) + { + printk(KERN_INFO "%s: x25_error() out of memory!\n", + card->devname); + return 0; + } + memcpy(mb, card->mbox, sizeof(wan_mbox_t) + dlen); +#endif + + switch (err){ + + case X25RES_ASYNC_PACKET: /* X.25 asynchronous packet was received */ + + mb->wan_data[dlen] = '\0'; + + switch (mb->wan_x25_pktType & 0x7F){ + + + case ASE_CALL_RQST: /* incoming call */ + retry = incoming_call(card, cmd, lcn, mb); + break; + + case ASE_CALL_ACCEPTED: /* connected */ + retry = call_accepted(card, cmd, lcn, mb); + break; + + case ASE_CLEAR_RQST: /* call clear request */ + retry = call_cleared(card, cmd, lcn, mb); + x25_clear_cmd_update(card, lcn, mb); + break; + + case ASE_RESET_RQST: /* reset request */ + printk(KERN_INFO "%s: X.25 reset request on LCN %d! " + "Cause:0x%02X Diagn:0x%02X\n", + card->devname, mb->wan_x25_lcn, mb->wan_x25_cause, + mb->wan_x25_diagn); + api_oob_event (card,mb); + break; + + case ASE_RESTART_RQST: /* restart request */ + retry = restart_event(card, cmd, lcn, mb); + break; + + case ASE_CLEAR_CONFRM: + clear_confirm_event (card,mb); + break; + + default: + printk(KERN_INFO "%s: Rx X.25 event 0x%02X on LCN %d! " + "Cause:0x%02X Diagn:0x%02X\n", + card->devname, mb->wan_x25_pktType&0x7F, + mb->wan_x25_lcn, mb->wan_x25_cause, mb->wan_x25_diagn); + api_oob_event (card,mb); + } + break; + + case X25RES_PROTO_VIOLATION: /* X.25 protocol violation indication */ + + /* Bug Fix: Mar 14 2000 + * The Protocol violation error conditions were + * not handeled previously */ + + switch (mb->wan_x25_pktType & 0x7F){ + + case PVE_CLEAR_RQST: /* Clear request */ + retry = call_cleared(card, cmd, lcn, mb); + break; + + case PVE_RESET_RQST: /* Reset request */ + printk(KERN_INFO "%s: Rx X.25 reset request on LCN %d! " + "Cause:0x%02X Diagn:0x%02X\n", + card->devname, mb->wan_x25_lcn, mb->wan_x25_cause, + mb->wan_x25_diagn); + api_oob_event (card,mb); + break; + + case PVE_RESTART_RQST: /* Restart request */ + retry = restart_event(card, cmd, lcn, mb); + break; + + default : + printk(KERN_INFO + "%s: X.25 protocol violation on LCN %d! " + "Packet:0x%02X Cause:0x%02X Diagn:0x%02X\n", + card->devname, mb->wan_x25_lcn, + mb->wan_x25_pktType & 0x7F, mb->wan_x25_cause, mb->wan_x25_diagn); + api_oob_event(card,mb); + } + break; + + case 0x42: /* X.25 timeout */ + retry = timeout_event(card, cmd, lcn, mb); + break; + + case 0x43: /* X.25 retry limit exceeded */ + printk(KERN_INFO + "%s: exceeded X.25 retry limit on LCN %d! " + "Packet:0x%02X Diagn:0x%02X\n", card->devname, + mb->wan_x25_lcn, mb->wan_x25_pktType&0x7F, mb->wan_x25_diagn); + break; + + case 0x08: /* modem failure */ + api_oob_event(card,mb); + break; + + case 0x09: /* N2 retry limit */ + printk(KERN_INFO "%s: exceeded HDLC retry limit!\n", + card->devname); + x25_down_event(card,cmd,lcn,mb,ASE_LAPB_DOWN); + break; + + case 0x06: /* unnumbered frame was received while in ABM */ + printk(KERN_INFO "%s: Received Unnumbered frame 0x%02X!\n", + card->devname, mb->wan_data[0]); + api_oob_event(card,mb); + break; + + case CMD_TIMEOUT: + printk(KERN_INFO "%s: command 0x%02X timed out!\n", + card->devname, cmd); + retry = 0; /* abort command */ + break; + + case X25RES_NOT_READY: + retry = 1; + break; + + case 0x01: + if (card->u.x.LAPB_hdlc) + break; + + if (mb->wan_command == 0x16) + break; + + if (mb->wan_command == 0x06) + break; + + /* I use the goto statement here so if + * somebody inserts code between the + * case and default, we will not have + * ghost problems */ + goto dflt_2; + + case X25RES_CHANNEL_IN_USE: + + if (cmd == X25_CLEAR_CALL){ + retry =0; + break; + } + + default: +dflt_2: + printk(KERN_INFO "%s: command 0x%02X returned 0x%02X! Lcn %i\n", + card->devname, cmd, err, mb->wan_x25_lcn) + ; + retry = 0; /* abort command */ + } + +// kfree(mb); + + return retry; +} + +/*==================================================================== + * X.25 Asynchronous Event Handlers + * These functions are called by the x25_error() and should return 0, if + * the command resulting in the asynchronous event must be aborted. + *====================================================================*/ + + + +/*==================================================================== + *Handle X.25 incoming call request. + * RFC 1356 establishes the following rules: + * 1. The first octet in the Call User Data (CUD) field of the call + * request packet contains NLPID identifying protocol encapsulation + * 2. Calls MUST NOT be accepted unless router supports requested + * protocol encapsulation. + * 3. A diagnostic code 249 defined by ISO/IEC 8208 may be used + * when clearing a call because protocol encapsulation is not + * supported. + * 4. If an incoming call is received while a call request is + * pending (i.e. call collision has occured), the incoming call + * shall be rejected and call request shall be retried. + *====================================================================*/ + +static int incoming_call (sdla_t* card, int cmd, int lcn, wan_mbox_t* mb) +{ + struct wan_dev_le *devle; + wan_device_t* wandev = &card->wandev; + int new_lcn = mb->wan_x25_lcn; + netdevice_t* dev = get_dev_by_lcn(wandev, new_lcn); + x25_channel_t* chan = NULL; + int accept = 0; /* set to '1' if o.k. to accept call */ + unsigned int user_data; + x25_call_info_t* info; + + /* Make sure there is no call collision */ + if (dev != NULL) + { + printk(KERN_INFO + "%s: X.25 incoming call collision on LCN %d!\n", + card->devname, new_lcn); + + x25_clear_call(card, new_lcn, 0, 0, 0, NULL,0); + return 1; + } + + + /* Parse call request data */ + info = kmalloc(sizeof(x25_call_info_t), GFP_ATOMIC); + if (info == NULL) + { + printk(KERN_INFO + "%s: not enough memory to parse X.25 incoming call " + "on LCN %d!\n", card->devname, new_lcn); + x25_clear_call(card, new_lcn, 0, 0, 0, NULL, 0); + return 1; + } + + parse_call_info(mb->wan_data, info); + + if (card->u.x.logging){ + printk(KERN_INFO "\n"); + printk(KERN_INFO "%s: X.25 incoming call on LCN %d!\n", + card->devname, new_lcn); + } + /* Convert the first two ASCII characters into an + * interger. Used to check the incoming protocol + */ + user_data = hex_to_uint(info->user,2); + + /* Find available channel */ + WAN_LIST_FOREACH(devle, &card->wandev.dev_head, dev_link){ + dev = WAN_DEVLE2DEV(devle); + if (!dev || !wan_netif_priv(dev)){ + continue; + } + + chan = wan_netif_priv(dev); + + if (chan->common.usedby == API){ + dev=NULL; + continue; + } + + if (!chan->common.svc || (chan->common.state != WAN_DISCONNECTED)){ + dev=NULL; + continue; + } + + if (chan->protocol == htons(ETH_P_IP) && user_data != NLPID_IP){ + dev=NULL; + continue; + } + + if (chan->protocol == htons(ETH_P_IPX) && user_data != NLPID_SNAP){ + dev=NULL; + continue; + } + + if (user_data == NLPID_IP && chan->protocol != htons(ETH_P_IP)){ + printk(KERN_INFO "IP packet but configured for IPX : %x, %x\n", + htons(chan->protocol), info->user[0]); + dev=NULL; + continue; + } + + if (user_data == NLPID_SNAP && chan->protocol != htons(ETH_P_IPX)){ + printk(KERN_INFO "IPX packet but configured for IP: %x\n", + htons(chan->protocol)); + dev=NULL; + continue; + } + + if (is_match_found(info->dest, chan->accept_dest_addr) && + is_match_found(info->src, chan->accept_src_addr) && + is_match_found(&info->user[2], chan->accept_usr_data)){ + break; + } + + dev=NULL; + } + + if (dev == NULL){ + + /* If the call is not for any WANPIPE interfaces + * check to see if there is an API listening queue + * waiting for data. If there is send the packet + * up the stack. + */ + if (card->sk != NULL){ + if (api_incoming_call(card,mb,new_lcn)){ + DEBUG_EVENT("%s: Incoming call failed !\n", + card->devname); + x25_clear_call(card, new_lcn, 0, 0x40, 0, NULL, 0); + } + accept = 0; + }else{ + printk(KERN_INFO "%s: no channels available!\n", + card->devname); + + x25_clear_call(card, new_lcn, 0, 0x40, 0, NULL, 0); + } + + }else if (info->nuser == 0){ + + printk(KERN_INFO + "%s: no user data in incoming call on LCN %d!\n", + card->devname, new_lcn) + ; + x25_clear_call(card, new_lcn, 0, 0,0, NULL, 0); + + }else switch (user_data){ + + case 0: /* multiplexed */ + chan->protocol = htons(0); + accept = 1; + break; + + case NLPID_IP: /* IP datagrams */ + accept = 1; + break; + + case NLPID_SNAP: /* IPX datagrams */ + accept = 1; + break; + + default: + printk(KERN_INFO + "%s: unsupported NLPID 0x%x in incoming call " + "on LCN %d!\n", card->devname, user_data, new_lcn); + x25_clear_call(card, new_lcn, 0, 249,0,NULL,0); + } + + if (accept && (x25_accept_call(card, new_lcn, 0, NULL, 0) == CMD_OK)){ + + bind_lcn_to_dev (card, chan->common.dev, new_lcn); + + if (x25_get_chan_conf(card, chan) == CMD_OK) + set_chan_state(dev, WAN_CONNECTED); + else + x25_clear_call(card, new_lcn, 0, 0, 0, NULL, 0); + } + kfree(info); + return 1; +} + +/*==================================================================== + * Pattern matching function in incoming calls. + *====================================================================*/ + +static int is_match_found(unsigned char info[], unsigned char chan[]) +{ + unsigned char temp[WAN_ADDRESS_SZ+1]; + + /* accept all calls */ + if (strcmp(chan, "*") == 0) return 1; + + /* case ?? - must exactly match */ + if (chan[strlen(chan) - 1] != '*' && chan[0] != '*' && strlen(chan)){ + if (strcmp(info, chan) == 0) return 1; + } + + /* case ??* must match at the begining */ + if ( chan[0] != '*' && chan[strlen(chan) - 1] == '*'){ + if (strncmp(info, &chan[0], strlen(chan) - 1) == 0) return 1; + } + + /* case *?? must match at the end */ + if ( chan[0] == '*' && chan[strlen(chan) - 1] != '*'){ + if (strncmp(&info[strlen(info) - strlen(chan)+1], &chan[1], strlen(chan) - 1) == 0) + return 1; + } + + /* case *??* must match somewhere in the string */ + if ( chan[0] == '*' && chan[strlen(chan) - 1] == '*'){ + + strncpy(temp, &chan[1], strlen(chan) - 2); + /* null terminate for strstr() */ + temp[strlen(chan) - 2] = '\0'; + + if (strstr(info, temp)) return 1; + } + + /* if got here the string is empty - do not accept call */ + return 0; +} + +/*==================================================================== + * Handle accepted call. + *====================================================================*/ + +static int call_accepted (sdla_t* card, int cmd, int lcn, wan_mbox_t* mb) +{ + unsigned new_lcn = mb->wan_x25_lcn; + netdevice_t* dev = find_channel(card, new_lcn); + x25_channel_t* chan; + + if (dev == NULL){ + printk(KERN_INFO + "%s: clearing orphaned connection on LCN %d!\n", + card->devname, new_lcn); + x25_clear_call(card, new_lcn, 0, 0, 0, NULL, 0); + return 1; + } + + if (card->u.x.logging) + printk(KERN_INFO "%s: Rx X.25 call accept on Dev %s and Lcn %d!\n", + card->devname, dev->name, new_lcn); + + /* Get channel configuration and notify router */ + chan = dev->priv; + if (x25_get_chan_conf(card, chan) != CMD_OK) + { + x25_clear_call(card, new_lcn, 0, 0, 0, NULL,0); + return 1; + } + + if (chan->common.usedby == API){ + + chan->x25_api_event.hdr.qdm = mb->wan_x25_qdm; + chan->x25_api_event.hdr.cause = mb->wan_x25_cause; + chan->x25_api_event.hdr.diagn = mb->wan_x25_diagn; + chan->x25_api_event.hdr.pktType = mb->wan_x25_pktType&0x7F; + chan->x25_api_event.hdr.length = 0; + chan->x25_api_event.hdr.result = 0; + chan->x25_api_event.hdr.lcn = mb->wan_x25_lcn; + chan->x25_api_event.hdr.mtu = card->u.x.x25_conf.defPktSize; + chan->x25_api_event.hdr.mru = card->u.x.x25_conf.defPktSize; + } + + set_chan_state(dev, WAN_CONNECTED); + + return 1; +} + +/*==================================================================== + * Handle cleared call. + *====================================================================*/ + +static int call_cleared (sdla_t* card, int cmd, int lcn, wan_mbox_t* mb) +{ + unsigned new_lcn = mb->wan_x25_lcn; + netdevice_t* dev = find_channel(card, new_lcn); + x25_channel_t *chan; + unsigned char old_state; + + if (card->u.x.logging){ + printk(KERN_INFO "%s: Rx X.25 clear request on Lcn %d! Cause:0x%02X " + "Diagn:0x%02X\n", + card->devname, new_lcn, mb->wan_x25_cause, mb->wan_x25_diagn); + } + + if (dev == NULL){ + printk(KERN_INFO "%s: X.25 clear request : No device for clear\n", + card->devname); + return 1; + } + + chan=dev->priv; + + old_state = chan->common.state; + + + if (chan->common.usedby == API){ + send_oob_msg(card,dev,mb); + } + + set_chan_state(dev, WAN_DISCONNECTED); + + return ((cmd == X25_WRITE) && (lcn == new_lcn)) ? 0 : 1; +} + +/*==================================================================== + * Handle X.25 restart event. + *====================================================================*/ + +static int restart_event (sdla_t* card, int cmd, int lcn, wan_mbox_t* mb) +{ + struct wan_dev_le *devle; + netdevice_t* dev; + x25_channel_t *chan; + unsigned char old_state,tx_timeout=0; + TX25Status status; + + card->hw_iface.peek(card->hw, card->flags_off, &status, sizeof(status)); + printk(KERN_INFO + "%s: Rx X.25 restart request! Cause:0x%02X Diagn:0x%02X\n", + card->devname, mb->wan_x25_cause, mb->wan_x25_diagn); + + /* After a restart, force the tx timeout to zero + * so the polling code doesn't mistake this condition + * for loss of clock */ + card->hw_iface.poke(card->hw, X25_TX_TIMEOUT_OFFS, &tx_timeout, 1); + + /* down all logical channels */ + WAN_LIST_FOREACH(devle, &card->wandev.dev_head, dev_link){ + + dev = WAN_DEVLE2DEV(devle); + if (!dev || !wan_netif_priv(dev)) continue; + chan = wan_netif_priv(dev); + old_state = chan->common.state; + + if (chan->common.usedby == API){ + send_oob_msg(card,dev,mb); + } + + if (chan->common.svc){ + set_chan_state(dev, WAN_DISCONNECTED); + }else{ + /* PVC in WANPIPE mode always stays + * connected. The PVC in API mode + * should not have a state change, since + * the connection of the socket activates + * the interface */ + if (chan->common.usedby == WANPIPE){ + set_chan_state(dev, WAN_CONNECTED); + } + } + + atomic_set(&chan->common.command,0); + } + + if (card->sk){ + wanpipe_api_listen_rx(NULL,card->sk); + /* NC: Allow user listen socket to + * stay connected to the driver, this way + * no incomint calls would be missed when + * the x25 layer comes back up */ + /* + sock_put(card->sk); + card->sk=NULL; + */ + } + + + /* We use the rx interrupt as x25 flow + * control. If we ever get a restart request + * make sure the rx interrupt is + * re-enabled */ + if (!(status.imask & INTR_ON_RX_FRAME)){ + status.imask |= INTR_ON_RX_FRAME; + card->hw_iface.poke(card->hw, + card->intr_perm_off, + &status.imask, + sizeof(status.imask)); + } + + return (cmd == X25_WRITE) ? 0 : 1; +} + + +static int x25_down_event (sdla_t* card, int cmd, int lcn, wan_mbox_t* mb, unsigned char x25_pkt_type ) +{ + struct wan_dev_le *devle; + netdevice_t* dev; + x25_channel_t *chan; + unsigned char old_state; + TX25Status status; + + card->hw_iface.peek(card->hw, card->flags_off, &status, sizeof(status)); + + printk(KERN_INFO + "%s: Lapb layer disconnected!\n",card->devname); + + clear_bit(0,&card->u.x.card_ready); + + /* down all logical channels */ + WAN_LIST_FOREACH(devle, &card->wandev.dev_head, dev_link){ + dev = WAN_DEVLE2DEV(devle); + if (!dev || !wan_netif_priv(dev)) continue; + chan = wan_netif_priv(dev); + old_state = chan->common.state; + + if (chan->common.usedby == API){ + mb->wan_x25_pktType=x25_pkt_type; + send_oob_msg(card,dev,mb); + } + + set_chan_state(dev, WAN_DISCONNECTED); + } + + if (card->sk){ + wanpipe_api_listen_rx(NULL,card->sk); + /* NC: Allow user listen socket to + * stay connected to the driver, this way + * no incomint calls would be missed when + * the x25 layer comes back up */ + /* + sock_put(card->sk); + card->sk=NULL; + */ + } + + + /* We use the rx interrupt as x25 flow + * control. If we ever get a restart request + * make sure the rx interrupt is + * re-enabled */ + if (!(status.imask & INTR_ON_RX_FRAME)){ + status.imask |= INTR_ON_RX_FRAME; + card->hw_iface.poke(card->hw, + card->intr_perm_off, + &status.imask, + sizeof(status.imask)); + } + + return (cmd == X25_WRITE) ? 0 : 1; + } + + +/*==================================================================== + * Handle timeout event. + *====================================================================*/ + +static int timeout_event (sdla_t* card, int cmd, int lcn, wan_mbox_t* mb) +{ + unsigned new_lcn = mb->wan_x25_lcn; + + if ((mb->wan_x25_pktType&0x7F) == 0x05) /* call request time out */ + { + netdevice_t* dev = find_channel(card,new_lcn); + + printk(KERN_INFO "%s: X.25 call timed timeout on LCN %d!\n", + card->devname, new_lcn); + + if (dev){ + set_chan_state(dev, WAN_DISCONNECTED); + } + }else{ + printk(KERN_INFO "%s: X.25 packet 0x%02X timeout on LCN %d!\n", + card->devname, mb->wan_x25_pktType&0x7F, new_lcn); + } + return 1; +} + +/* + * Miscellaneous + */ + +/*==================================================================== + * Establish physical connection. + * o open HDLC and raise DTR + * + * Return: 0 connection established + * 1 connection is in progress + * <0 error + *===================================================================*/ + +static int connect (sdla_t* card) +{ + if (x25_open_hdlc(card) || x25_setup_hdlc(card)){ + DEBUG_EVENT("%s: Failed to open hdlc and setup hdlc\n",card->devname); + return -EIO; + } + + wanpipe_set_state(card, WAN_CONNECTING); + + x25_set_intr_mode(card, (INTR_ON_TIMER|INTR_ON_TRACE_DATA)); + card->hw_iface.clear_bit(card->hw, card->intr_perm_off, INTR_ON_TIMER); + return 0; +} + +/* + * Tear down physical connection. + * o close HDLC link + * o drop DTR + * + * Return: 0 + * <0 error + */ + +static int disconnect (sdla_t* card) +{ + wanpipe_set_state(card, WAN_DISCONNECTED); + + /* disable all interrupt except timer & trace */ + x25_set_intr_mode(card, INTR_ON_TIMER|INTR_ON_TRACE_DATA); + x25_close_hdlc(card); /* close HDLC link */ + x25_set_dtr(card, 0); /* drop DTR */ + + return 0; +} + +/* + * Find network device by its channel number. + */ + +static netdevice_t* get_dev_by_lcn (wan_device_t* wandev, unsigned lcn) +{ + struct wan_dev_le *devle; + netdevice_t *dev = NULL; + + WAN_LIST_FOREACH(devle, &wandev->dev_head, dev_link){ + dev = WAN_DEVLE2DEV(devle); + if (((x25_channel_t*)dev->priv)->common.lcn == lcn){ + return dev; + } + } + return NULL; +} + +/* + * Initiate connection on the logical channel. + * o for PVC we just get channel configuration + * o for SVCs place an X.25 call + * + * Return: 0 connected + * >0 connection in progress + * <0 failure + */ + +static int chan_connect (netdevice_t* dev) +{ + x25_channel_t* chan = dev->priv; + sdla_t* card = chan->card; + + if (chan->common.svc && chan->common.usedby == WANPIPE){ + if (!chan->addr[0]){ + printk(KERN_INFO "%s: No Destination Address\n", + card->devname); + return -EINVAL; /* no destination address */ + } + printk(KERN_INFO "%s: placing X.25 call to %s ...\n", + card->devname, chan->addr); + + if (x25_place_call(card, chan) != CMD_OK) + return -EIO; + + set_chan_state(dev, WAN_CONNECTING); + return 1; + }else{ + if (x25_get_chan_conf(card, chan) != CMD_OK) + return -EIO; + + set_chan_state(dev, WAN_CONNECTED); + } + return 0; +} + +/* + * Disconnect logical channel. + * o if SVC then clear X.25 call + */ + +static int chan_disc (netdevice_t* dev) +{ + x25_channel_t* chan = dev->priv; + + if (chan->common.svc){ + x25_clear_call(chan->card, chan->common.lcn, 0, 0, 0,NULL,0); + + /* For API we disconnect on clear + * confirmation. + */ + if (chan->common.usedby == API) + return 0; + } + + set_chan_state(dev, WAN_DISCONNECTED); + + return 0; +} + +/* + * Set logical channel state. + */ + +static void set_chan_state (netdevice_t* dev, int state) +{ + x25_channel_t* chan = dev->priv; + sdla_t* card = chan->card; + + if (chan->common.state != state) + { + switch (state) + { + case WAN_CONNECTED: + if (card->u.x.logging){ + printk (KERN_INFO + "%s: interface %s connected, lcn %i !\n", + card->devname, dev->name,chan->common.lcn); + } + *(unsigned short*)dev->dev_addr = htons(chan->common.lcn); + chan->i_timeout_sofar = jiffies; + + /* LAPB is PVC Based */ + if (card->u.x.LAPB_hdlc){ + chan->common.svc=0; + } + break; + + case WAN_CONNECTING: + if (card->u.x.logging){ + printk (KERN_INFO + "%s: interface %s connecting, lcn %i ...\n", + card->devname, dev->name, chan->common.lcn); + } + break; + + case WAN_DISCONNECTED: + if (card->u.x.logging){ + printk (KERN_INFO + "%s: interface %s disconnected, lcn %i !\n", + card->devname, dev->name,chan->common.lcn); + } + + if (!card->u.x.LAPB_hdlc){ + atomic_set(&chan->common.disconnect,0); + } + + if (chan->common.svc) { + *(unsigned short*)dev->dev_addr = 0; + card->u.x.svc_to_dev_map[(chan->common.lcn%X25_MAX_CHAN)]=NULL; + chan->common.lcn = 0; + } + + if (chan->transmit_length){ + chan->transmit_length=0; + chan->tx_offset=0; + if (is_queue_stopped(dev)){ + wake_net_dev(dev); + } + } + + /* We use the rx interrupt as x25 flow + * control. If we ever get a restart request + * make sure the rx interrupt is + * re-enabled */ + + if (atomic_read(&chan->common.receive_block)){ + TX25Status status; + + card->hw_iface.peek(card->hw, + card->intr_perm_off, + &status.imask, + sizeof(status.imask)); + atomic_set(&chan->common.receive_block,0); + + if (!(status.imask & INTR_ON_RX_FRAME)){ + DEBUG_EVENT("%s: Disabling x25 flow control!\n", + card->devname); + status.imask |= INTR_ON_RX_FRAME; + card->hw_iface.poke(card->hw, + card->intr_perm_off, + &status.imask, + sizeof(status.imask)); + } + } + + if (wan_skb_queue_len(&chan->common.rx_queue)){ + DEBUG_EVENT("%s: Purging svc queue!\n", + chan->common.dev->name); + wan_skb_queue_purge(&chan->common.rx_queue); + } + atomic_set(&chan->common.command,0); + atomic_set(&chan->cmd_rc,0); + break; + + case WAN_DISCONNECTING: + if (card->u.x.logging){ + printk(KERN_INFO "\n"); + printk (KERN_INFO + "%s: interface %s disconnecting, lcn %i ...\n", + card->devname, dev->name,chan->common.lcn); + } + + atomic_set(&chan->common.disconnect,0); + break; + } + chan->common.state = state; + x25_update_api_state(card,chan); + + } + chan->state_tick = jiffies; +} + +/* + * Send packet on a logical channel. + * When this function is called, tx_skb field of the channel data + * space points to the transmit socket buffer. When transmission + * is complete, release socket buffer and reset 'tbusy' flag. + * + * Return: 0 - transmission complete + * 1 - busy + * + * Notes: + * 1. If packet length is greater than MTU for this channel, we'll fragment + * the packet into 'complete sequence' using M-bit. + * 2. When transmission is complete, an event notification should be issued + * to the router. + */ + +static int chan_send (netdevice_t* dev, void* buff, unsigned data_len, unsigned char tx_intr) +{ + x25_channel_t* chan = dev->priv; + sdla_t* card = chan->card; + TX25Status status; + u8 tmp; + unsigned len=0, qdm=0, res=0, orig_len = 0; + void *data; + + card->hw_iface.peek(card->hw, card->flags_off, &status, sizeof(status)); + /* Check to see if channel is ready */ + card->hw_iface.peek(card->hw, card->u.x.hdlc_buf_status_off, &tmp, 1); + if ((!(status.cflags[chan->ch_idx] & 0x40) && !card->u.x.LAPB_hdlc) || + !(tmp & 0x40)){ + + if (!tx_intr){ + setup_for_delayed_transmit (dev, buff, data_len); + return 0; + }else{ + /* By returning 0 to tx_intr the packet will be dropped */ + ++card->wandev.stats.tx_dropped; + ++chan->ifstats.tx_dropped; + printk(KERN_INFO "%s: ERROR, Tx intr could not send, dropping %s:\n", + card->devname,dev->name); + ++chan->if_send_stat.if_send_bfr_not_passed_to_adptr; + return 0; + } + } + + if (chan->common.usedby == API){ + /* Remove the API Header */ + x25api_hdr_t *api_data = (x25api_hdr_t *)buff; + + /* Set the qdm bits from the packet header + * User has the option to set the qdm bits + */ + qdm = api_data->qdm; + + orig_len = len = data_len - sizeof(x25api_hdr_t); + data = (unsigned char*)buff + sizeof(x25api_hdr_t); + }else{ + data = buff; + orig_len = len = data_len; + } + + if (tx_intr){ + /* We are in tx_intr, minus the tx_offset from + * the total length. The tx_offset part of the + * data has already been sent. Also, move the + * data pointer to proper offset location. + */ + len -= chan->tx_offset; + data = (unsigned char*)data + chan->tx_offset; + } + + /* Check if the packet length is greater than MTU + * If YES: Cut the len to MTU and set the M bit + */ + + if (len > chan->tx_pkt_size && !card->u.x.LAPB_hdlc){ + + /* NC: Bug Fix Jul 8 2003 + * Since setup_for_delayed_transmit() resets + * the chan->tx_offset value. We must start + * transmitting the "Long" packets + * from the interrupt, not from a process */ + if (!tx_intr){ + setup_for_delayed_transmit (dev, buff, data_len); + return 0; + } + + len = chan->tx_pkt_size; + qdm |= M_BIT; + } + + /* Pass only first three bits of the qdm byte to the send + * routine. In case user sets any other bit which might + * cause errors. + */ + + switch(x25_send(card, chan->common.lcn, (qdm&0x07), len, data)){ + + case 0x00: /* success */ + chan->i_timeout_sofar = jiffies; + +#if defined(LINUX_2_4)||defined(LINUX_2_6) + dev->trans_start=jiffies; +#endif + + if ((qdm & M_BIT) && !card->u.x.LAPB_hdlc){ + + chan->tx_offset += len; + + if (!tx_intr){ + DEBUG_EVENT("%s:%s: Critical Error: qdm set in non-interrupt mode!\n", + __FUNCTION__, + card->devname); + }else{ + /* We are already in tx_inter, thus data is already + * in the buffer. Update the offset and wait for + * next tx_intr. We add on to the offset, since data can + * be X number of times larger than max data size. + */ + ++chan->ifstats.tx_packets; + chan->ifstats.tx_bytes += len; + + ++chan->if_send_stat.if_send_bfr_passed_to_adptr; + + /* The user can set the qdm bit as well. + * If the entire packet was sent and qdm is still + * set, than it's the user who has set the M bit. In that, + * case indicate that the packet was send by returning + * 0 and wait for a new packet. Otherwise, wait for next + * tx interrupt to send the rest of the packet */ + + if (chan->tx_offset < orig_len){ + res=1; + } + } + }else{ + ++chan->ifstats.tx_packets; + chan->ifstats.tx_bytes += len; + + ++chan->if_send_stat.if_send_bfr_passed_to_adptr; + } + break; + + case 0x33: /* Tx busy */ + if (tx_intr){ + printk(KERN_INFO "%s: Tx_intr: Big Error dropping packet %s\n", + card->devname,dev->name); + ++chan->ifstats.tx_dropped; + ++card->wandev.stats.tx_dropped; + ++chan->if_send_stat.if_send_bfr_not_passed_to_adptr; + }else{ + DBG_PRINTK(KERN_INFO + "%s: Send: Big Error should have tx: storring %s\n", + card->devname,dev->name); + setup_for_delayed_transmit (dev, buff, data_len); + } + break; + + default: /* failure */ + ++chan->ifstats.tx_errors; + if (tx_intr){ + printk(KERN_INFO "%s: Tx_intr: Failure to send, dropping %s\n", + card->devname,dev->name); + ++chan->ifstats.tx_dropped; + ++card->wandev.stats.tx_dropped; + ++chan->if_send_stat.if_send_bfr_not_passed_to_adptr; + }else{ + DBG_PRINTK(KERN_INFO "%s: Send: Failure to send !!!, storing %s\n", + card->devname,dev->name); + setup_for_delayed_transmit (dev, buff, data_len); + } + break; + } + + return res; +} + + +/* + * Parse X.25 call request data and fill x25_call_info_t structure. + */ + +static void parse_call_info (unsigned char* str, x25_call_info_t* info) +{ + memset(info, 0, sizeof(x25_call_info_t)); + for (; *str; ++str) + { + int i; + unsigned char ch; + + if (*str == '-') switch (str[1]) { + + /* Take minus 2 off the maximum size so that + * last byte is 0. This way we can use string + * manipulaton functions on call information. + */ + + case 'd': /* destination address */ + for (i = 0; i < (MAX_X25_ADDR_SIZE-2); ++i){ + ch = str[2+i]; + if (isspace(ch)) break; + info->dest[i] = ch; + } + break; + + case 's': /* source address */ + for (i = 0; i < (MAX_X25_ADDR_SIZE-2); ++i){ + ch = str[2+i]; + if (isspace(ch)) break; + info->src[i] = ch; + } + break; + + case 'u': /* user data */ + for (i = 0; i < (MAX_X25_DATA_SIZE-2); ++i){ + ch = str[2+i]; + if (isspace(ch)) break; + info->user[i] = ch; + } + info->nuser = i; + break; + + case 'f': /* facilities */ + for (i = 0; i < (MAX_X25_FACL_SIZE-2); ++i){ + ch = str[2+i]; + if (isspace(ch)) break; + info->facil[i] = ch; + } + info->nfacil = i; + break; + } + } +} + +/* + * Convert line speed in bps to a number used by S502 code. + */ + +static unsigned char bps_to_speed_code (unsigned long bps) +{ + unsigned char number; + + if (bps <= 1200) number = 0x01; + else if (bps <= 2400) number = 0x02; + else if (bps <= 4800) number = 0x03; + else if (bps <= 9600) number = 0x04; + else if (bps <= 19200) number = 0x05; + else if (bps <= 38400) number = 0x06; + else if (bps <= 45000) number = 0x07; + else if (bps <= 56000) number = 0x08; + else if (bps <= 64000) number = 0x09; + else if (bps <= 74000) number = 0x0A; + else if (bps <= 112000) number = 0x0B; + else if (bps <= 128000) number = 0x0C; + else number = 0x0D; + + return number; +} + +/* + * Convert decimal string to unsigned integer. + * If len != 0 then only 'len' characters of the string are converted. + */ + +static unsigned int dec_to_uint (unsigned char* str, int len) +{ + unsigned val; + + if (!len) + len = strlen(str); + + for (val = 0; len && is_digit(*str); ++str, --len) + val = (val * 10) + (*str - (unsigned)'0'); + + return val; +} + +/* + * Convert hex string to unsigned integer. + * If len != 0 then only 'len' characters of the string are conferted. + */ + +static unsigned int hex_to_uint (unsigned char* str, int len) +{ + unsigned val, ch; + + if (!len) + len = strlen(str); + + for (val = 0; len; ++str, --len) + { + ch = *str; + if (is_digit(ch)) + val = (val << 4) + (ch - (unsigned)'0'); + else if (is_hex_digit(ch)) + val = (val << 4) + ((ch & 0xDF) - (unsigned)'A' + 10); + else break; + } + return val; +} + + +static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number, unsigned short proto) +{ + int i; + + if( proto == ETH_P_IPX) { + /* It's an IPX packet */ + if(!enable_IPX) { + /* Return 1 so we don't pass it up the stack. */ + return 1; + } + } else { + /* It's not IPX so pass it up the stack.*/ + return 0; + } + + if( sendpacket[16] == 0x90 && + sendpacket[17] == 0x04) + { + /* It's IPXWAN */ + + if( sendpacket[2] == 0x02 && + sendpacket[34] == 0x00) + { + /* It's a timer request packet */ + printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n",devname); + + /* Go through the routing options and answer no to every + * option except Unnumbered RIP/SAP + */ + for(i = 41; sendpacket[i] == 0x00; i += 5) + { + /* 0x02 is the option for Unnumbered RIP/SAP */ + if( sendpacket[i + 4] != 0x02) + { + sendpacket[i + 1] = 0; + } + } + + /* Skip over the extended Node ID option */ + if( sendpacket[i] == 0x04 ) + { + i += 8; + } + + /* We also want to turn off all header compression opt. */ + for(; sendpacket[i] == 0x80 ;) + { + sendpacket[i + 1] = 0; + i += (sendpacket[i + 2] << 8) + (sendpacket[i + 3]) + 4; + } + + /* Set the packet type to timer response */ + sendpacket[34] = 0x01; + + printk(KERN_INFO "%s: Sending IPXWAN Timer Response\n",devname); + } + else if( sendpacket[34] == 0x02 ) + { + /* This is an information request packet */ + printk(KERN_INFO "%s: Received IPXWAN Information Request packet\n",devname); + + /* Set the packet type to information response */ + sendpacket[34] = 0x03; + + /* Set the router name */ + sendpacket[51] = 'X'; + sendpacket[52] = 'T'; + sendpacket[53] = 'P'; + sendpacket[54] = 'I'; + sendpacket[55] = 'P'; + sendpacket[56] = 'E'; + sendpacket[57] = '-'; + sendpacket[58] = CVHexToAscii(network_number >> 28); + sendpacket[59] = CVHexToAscii((network_number & 0x0F000000)>> 24); + sendpacket[60] = CVHexToAscii((network_number & 0x00F00000)>> 20); + sendpacket[61] = CVHexToAscii((network_number & 0x000F0000)>> 16); + sendpacket[62] = CVHexToAscii((network_number & 0x0000F000)>> 12); + sendpacket[63] = CVHexToAscii((network_number & 0x00000F00)>> 8); + sendpacket[64] = CVHexToAscii((network_number & 0x000000F0)>> 4); + sendpacket[65] = CVHexToAscii(network_number & 0x0000000F); + for(i = 66; i < 99; i+= 1) + { + sendpacket[i] = 0; + } + + printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n",devname); + } + else + { + printk(KERN_INFO "%s: Unknown IPXWAN packet!\n",devname); + return 0; + } + + /* Set the WNodeID to our network address */ + sendpacket[35] = (unsigned char)(network_number >> 24); + sendpacket[36] = (unsigned char)((network_number & 0x00FF0000) >> 16); + sendpacket[37] = (unsigned char)((network_number & 0x0000FF00) >> 8); + sendpacket[38] = (unsigned char)(network_number & 0x000000FF); + + return 1; + } else { + /*If we get here its an IPX-data packet, so it'll get passed up the stack. + */ + /* switch the network numbers */ + switch_net_numbers(sendpacket, network_number, 1); + return 0; + } +} + +/* + * If incoming is 0 (outgoing)- if the net numbers is ours make it 0 + * if incoming is 1 - if the net number is 0 make it ours + */ + +static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming) +{ + unsigned long pnetwork_number; + + pnetwork_number = (unsigned long)((sendpacket[6] << 24) + + (sendpacket[7] << 16) + (sendpacket[8] << 8) + + sendpacket[9]); + + + if (!incoming) { + /*If the destination network number is ours, make it 0 */ + if( pnetwork_number == network_number) { + sendpacket[6] = sendpacket[7] = sendpacket[8] = + sendpacket[9] = 0x00; + } + } else { + /* If the incoming network is 0, make it ours */ + if( pnetwork_number == 0) { + sendpacket[6] = (unsigned char)(network_number >> 24); + sendpacket[7] = (unsigned char)((network_number & + 0x00FF0000) >> 16); + sendpacket[8] = (unsigned char)((network_number & + 0x0000FF00) >> 8); + sendpacket[9] = (unsigned char)(network_number & + 0x000000FF); + } + } + + + pnetwork_number = (unsigned long)((sendpacket[18] << 24) + + (sendpacket[19] << 16) + (sendpacket[20] << 8) + + sendpacket[21]); + + + if( !incoming ) { + /* If the source network is ours, make it 0 */ + if( pnetwork_number == network_number) { + sendpacket[18] = sendpacket[19] = sendpacket[20] = + sendpacket[21] = 0x00; + } + } else { + /* If the source network is 0, make it ours */ + if( pnetwork_number == 0 ) { + sendpacket[18] = (unsigned char)(network_number >> 24); + sendpacket[19] = (unsigned char)((network_number & + 0x00FF0000) >> 16); + sendpacket[20] = (unsigned char)((network_number & + 0x0000FF00) >> 8); + sendpacket[21] = (unsigned char)(network_number & + 0x000000FF); + } + } +} /* switch_net_numbers */ + + + + +/********************* X25API SPECIFIC FUNCTIONS ****************/ + + +/*=============================================================== + * find_channel + * + * Manages the lcn to device map. It increases performance + * because it eliminates the need to search through the link + * list for a device which is bounded to a specific lcn. + * + *===============================================================*/ + + +netdevice_t * find_channel(sdla_t *card, unsigned lcn) +{ + if (card->u.x.LAPB_hdlc){ + + return WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + + }else{ + /* We don't know whether the incoming lcn + * is a PVC or an SVC channel. But we do know that + * the lcn cannot be for both the PVC and the SVC + * channel. + + * If the lcn number is greater or equal to 255, + * take the modulo 255 of that number. We only have + * 255 locations, thus higher numbers must be mapped + * to a number between 0 and 245. + + * We must separate pvc's and svc's since two don't + * have to be contiguous. Meaning pvc's can start + * from 1 to 10 and svc's can start from 256 to 266. + * But 256%255 is 1, i.e. CONFLICT. + */ + + + /* Highest LCN number must be less or equal to 4096 */ + if ((lcn <= MAX_LCN_NUM) && (lcn > 0)){ + + if (lcn < X25_MAX_CHAN){ + if (card->u.x.svc_to_dev_map[lcn]) + return card->u.x.svc_to_dev_map[lcn]; + + if (card->u.x.pvc_to_dev_map[lcn]) + return card->u.x.pvc_to_dev_map[lcn]; + + }else{ + int new_lcn = lcn%X25_MAX_CHAN; + if (card->u.x.svc_to_dev_map[new_lcn]) + return card->u.x.svc_to_dev_map[new_lcn]; + + if (card->u.x.pvc_to_dev_map[new_lcn]) + return card->u.x.pvc_to_dev_map[new_lcn]; + } + } + return NULL; + } +} + +void bind_lcn_to_dev (sdla_t *card, netdevice_t *dev,unsigned lcn) +{ + x25_channel_t *chan = dev->priv; + + /* Modulo the lcn number by X25_MAX_CHAN (255) + * because the lcn number can be greater than 255 + * + * We need to split svc and pvc since they don't have + * to be contigous. + */ + + if (chan->common.svc){ + card->u.x.svc_to_dev_map[(lcn % X25_MAX_CHAN)] = dev; + }else{ + card->u.x.pvc_to_dev_map[(lcn % X25_MAX_CHAN)] = dev; + } + chan->common.lcn = lcn; +} + + + +/*=============================================================== + * x25api_bh + * + * + *==============================================================*/ + +static void x25api_bh (unsigned long data) +{ + x25_channel_t* chan = (x25_channel_t*)data; + sdla_t* card = chan->card; + struct sk_buff *skb; + int len, err=0,full=0; + + while ((skb=wan_api_dequeue_skb(chan))){ + + len=skb->len; + if (chan->common.usedby == API){ + err=wan_api_rx(chan,skb); + + if (err == 0){ + ++chan->rx_intr_stat.rx_intr_bfr_passed_to_stack; + ++chan->ifstats.rx_packets; + chan->ifstats.rx_bytes += len; + }else if (err == -ENOMEM){ + DEBUG_EVENT("%s:%s: Warning: API socket full!\n",card->devname,chan->common.dev->name); + wan_skb_queue_head(&chan->common.rx_queue,skb); + full=1; + break; + }else{ + ++chan->ifstats.rx_dropped; + wan_skb_free(skb); + } + } + } + + + if (!full){ + if (atomic_read(&chan->common.receive_block)){ + TX25Status status; + + card->hw_iface.peek(card->hw, + card->intr_perm_off, + &status.imask, + sizeof(status.imask)); + atomic_set(&chan->common.receive_block,0); + + if (!(status.imask & INTR_ON_RX_FRAME)){ + DEBUG_EVENT("%s: Disabling x25 flow control!\n",card->devname); + status.imask |= INTR_ON_RX_FRAME; + card->hw_iface.poke(card->hw, + card->intr_perm_off, + &status.imask, + sizeof(status.imask)); + } + } + } + + WAN_TASKLET_END((&chan->common.bh_task)); + + return; +} + +static void wakeup_sk_bh (netdevice_t *dev) +{ + + x25_channel_t *chan = dev->priv; + + if (!chan->common.sk){ + return; + } + + wanpipe_api_poll_wake(chan->common.sk); + return; +} + +/*=============================================================== + * tx_intr_cmd_exec + * + * Called by TX interrupt to execute a command + *===============================================================*/ + +static int tx_intr_cmd_exec (sdla_t* card) +{ + netdevice_t *dev; + unsigned char more_to_exec=0; + volatile x25_channel_t *chan=NULL; + volatile wan_mbox_t* mbox = &card->wan_mbox; + + int i=0,bad_cmd=0,err=0; + + /* This is the very first time we come into + * the tx intr cmd exec routine. Thus, + * the card is ready to receive commands */ + if (!test_and_set_bit(0,&card->u.x.card_ready)){ + DEBUG_EVENT("%s: X25 Driver Connected and Ready\n", + card->devname); + card->u.x.cmd_dev=NULL; + } + + if (card->u.x.cmd_dev == NULL){ + card->u.x.cmd_dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + } + + dev = card->u.x.cmd_dev; + + for (;;){ + + chan = dev->priv; + if (!chan || !(dev->flags&IFF_UP)){ + dev = move_dev_to_next(card,dev); + goto cmd_dev_skip; + } + + if (atomic_read(&chan->common.command)){ + + bad_cmd = check_bad_command(card,dev); + + err = execute_delayed_cmd(card, dev,bad_cmd); + + chan->x25_api_event.hdr.qdm = mbox->wan_x25_qdm; + chan->x25_api_event.hdr.cause = mbox->wan_x25_cause; + chan->x25_api_event.hdr.diagn = mbox->wan_x25_diagn; + chan->x25_api_event.hdr.pktType = mbox->wan_x25_pktType&0x7F; + chan->x25_api_event.hdr.length = 0; + chan->x25_api_event.hdr.result = 0; + chan->x25_api_event.hdr.lcn = mbox->wan_x25_lcn; + chan->x25_api_event.hdr.mtu = card->u.x.x25_conf.defPktSize; + chan->x25_api_event.hdr.mru = card->u.x.x25_conf.defPktSize; + + atomic_set(&chan->cmd_rc,err); + + switch (err){ + + default: + + /* Return the result to the socket without + * delay. NO_WAIT Command */ + atomic_set(&chan->common.command,0); + more_to_exec=0; + break; + + case -EAGAIN: + +#if 0 + /* If command could not be executed for + * some reason (i.e return code 0x33 busy) + * set the more_to_exec bit which will + * indicate that this command must be exectued + * again during next timer interrupt + */ + chan->cmd_timeout=jiffies; +#endif + more_to_exec=1; + break; + } + + bad_cmd=0; + + /* If flags is set, there are no hdlc buffers, + * thus, wait for the next pass and try the + * same command again. Otherwise, start searching + * from next device on the next pass. + */ + if (!more_to_exec){ + dev = move_dev_to_next(card,dev); + } + break; + }else{ + /* This device has nothing to execute, + * go to next. + */ + dev = move_dev_to_next(card,dev); + } +cmd_dev_skip: + if (++i == card->u.x.no_dev){ + if (!more_to_exec){ + DEBUG_TX("%s: Nothing to execute in Timer\n", + card->devname); + } + break; + } + + } //End of FOR + + card->u.x.cmd_dev = dev; + + if (more_to_exec){ + /* If more commands are pending, do not turn off timer + * interrupt */ + return 1; + }else{ + /* No more commands, turn off timer interrupt */ + atomic_dec(&card->u.x.tx_interrupt_cmd); + return 0; + } +} + +/*=============================================================== + * execute_delayed_cmd + * + * Execute an API command which was passed down from the + * sock. Sock is very limited in which commands it can + * execute. Wait and No Wait commands are supported. + * Place Call, Clear Call and Reset wait commands, where + * Accept Call is a no_wait command. + * + *===============================================================*/ +static int execute_delayed_cmd (sdla_t* card, netdevice_t *dev, char bad_cmd) +{ + wan_mbox_t* mbox = &card->wan_mbox; + u8 status; + int err=-EINVAL; + x25_channel_t *chan = dev->priv; + + card->hw_iface.peek(card->hw, card->u.x.hdlc_buf_status_off, &status, 1); + if (!(status & 0x40) && !bad_cmd){ + printk(KERN_INFO "%s: Execute Command Failed, No HDLC Buffers!\n", + card->devname); + return -EAGAIN; + } + + /* If channel is pvc, instead of place call + * run x25_channel configuration. If running LAPB HDLC + * enable communications. + */ + if ((!chan->common.svc) && (atomic_read(&chan->common.command) == X25_PLACE_CALL)){ + + if (card->u.x.LAPB_hdlc){ + DBG_PRINTK(KERN_INFO "LAPB: Connecting\n"); + err=connect(card); + if (err==CMD_OK){ + set_chan_state(dev,WAN_CONNECTING); + return 0; + }else{ + set_chan_state(dev,WAN_DISCONNECTED); + return -ENETDOWN; + } + }else{ + DBG_PRINTK(KERN_INFO "%s: PVC is CONNECTING\n",card->devname); + if (x25_get_chan_conf(card, chan) == CMD_OK){ + set_chan_state(dev, WAN_CONNECTED); + return 0; + }else{ + set_chan_state(dev, WAN_DISCONNECTED); + return -ENETDOWN; + } + } + } + + /* Check if command is bad. We need to copy the cmd into + * the buffer regardless since we return the, mbox to + * the user */ + if (bad_cmd){ + return -EINVAL; + } + + DEBUG_TEST("%s:%s:%s: Executing Command %d Lcn %d\n", + __FUNCTION__,card->devname,dev->name, + atomic_read(&chan->common.command), + chan->common.lcn); + + switch (atomic_read(&chan->common.command)){ + + case X25_PLACE_CALL: + + err=x25_place_call(card,chan); + + switch (err){ + + case CMD_OK: + + DEBUG_TEST("%s: PLACE CALL Binding dev %s to lcn %i\n", + card->devname,dev->name, mbox->wan_x25_lcn); + + bind_lcn_to_dev (card, dev, mbox->wan_x25_lcn); + set_chan_state(dev, WAN_CONNECTING); + break; + + default: + set_chan_state(dev, WAN_DISCONNECTED); + err=-ENETDOWN; + } + break; + + case X25_ACCEPT_CALL: + + err=x25_accept_call(card, + chan->common.lcn, + 0, + chan->call_string, + strlen(chan->call_string)); + + switch (err){ + + case CMD_OK: + + DEBUG_TEST("%s: ACCEPT Binding dev %s to lcn %i\n", + card->devname,dev->name,mbox->wan_x25_lcn); + + bind_lcn_to_dev (card, dev, mbox->wan_x25_lcn); + + if (x25_get_chan_conf(card, chan) == CMD_OK){ + + set_chan_state(dev, WAN_CONNECTED); + }else{ + if (x25_clear_call(card, chan->common.lcn, 0, 0, 0, NULL,0) == CMD_OK){ + set_chan_state(dev, WAN_DISCONNECTING); + err=-ENETDOWN; + }else{ + /* Do not change the state here. If we fail + * the accept the return code is send up + *the stack, which will ether retry + * or clear the call + */ + DEBUG_EVENT("%s: ACCEPT: STATE MAY BE CURRUPTED 2 !!!!!\n", + card->devname); + err=-EINVAL; + } + } + break; + + + case X25RES_ASYNC_PACKET: + case X25RES_NOT_READY: + err = -EAGAIN; + break; + + default: + DBG_PRINTK(KERN_INFO "%s: ACCEPT FAILED\n",card->devname); + if (x25_clear_call(card, chan->common.lcn, 0, 0, 0, NULL,0) == CMD_OK){ + set_chan_state(dev, WAN_DISCONNECTING); + err = -ENETDOWN; + }else{ + /* Do not change the state here. If we fail the accept. The + * return code is send up the stack, which will ether retry + * or clear the call */ + DEBUG_EVENT("%s: ACCEPT: STATE MAY BE CORRUPTED 1 !!!!!\n", + card->devname); + err = -EINVAL; + } + } + break; + + case X25_CLEAR_CALL: + + err=x25_clear_call(card,chan->common.lcn, + chan->x25_api_cmd_hdr.cause, + chan->x25_api_cmd_hdr.diagn, + 0x80, + chan->call_string, + strlen(chan->call_string)); + + switch (err){ + + case CMD_OK: + DEBUG_TEST("%s: CALL CLEAR OK: Dev %s Lcn %i Chan Lcn %i\n", + card->devname,dev->name, + mbox->wan_x25_lcn,chan->common.lcn); + set_chan_state(dev, WAN_DISCONNECTING); + break; + + case X25RES_CHANNEL_IN_USE: + case X25RES_ASYNC_PACKET: + case X25RES_NOT_READY: + err=-EAGAIN; + break; + + case X25RES_LINK_NOT_IN_ABM: + case X25RES_INVAL_LCN: + case X25RES_INVAL_STATE: + + set_chan_state(dev, WAN_DISCONNECTED); + err = -EINVAL; + break; + default: + /* If command did not execute because of user + * fault, do not change the state. This will + * signal the socket that clear command failed. + * User can retry or close the socket. + * When socket gets killed, it will set the + * chan->disconnect which will signal + * driver to clear the call */ + DEBUG_EVENT("%s: Clear Command Failed, Rc %x\n", + card->devname,err); + return -EINVAL; + } + break; + + + case X25_RESET: + + err=x25_reset_call(card,chan->common.lcn, + chan->x25_api_cmd_hdr.cause, + chan->x25_api_cmd_hdr.diagn, + 0); + + switch(err){ + + case CMD_OK: + DEBUG_TEST("%s: RESET CLEAR OK: Dev %s Lcn %i Chan Lcn %i\n", + card->devname,dev->name, + mbox->wan_x25_lcn,chan->common.lcn); + break; + + case X25RES_CHANNEL_IN_USE: + case X25RES_ASYNC_PACKET: + case X25RES_NOT_READY: + err=-EAGAIN; + break; + + + case X25RES_LINK_NOT_IN_ABM: + case X25RES_INVAL_LCN: + case X25RES_INVAL_STATE: + + set_chan_state(dev, WAN_DISCONNECTED); + err = -EINVAL; + break; + + default: + /* If command did not execute because of user + * fault, do not change the state. This will + * signal the socket that clear command failed. + * User can retry or close the socket. + * When socket gets killed, it will set the + * chan->disconnect which will signal + * driver to clear the call */ + DEBUG_EVENT("%s: Clear Command Failed, Rc %x\n", + card->devname,err); + return -EINVAL; + } + break; + + case X25_WP_INTERRUPT: + + err=x25_interrupt(card, + chan->common.lcn, + 0, + chan->call_string, + strlen(chan->call_string)); + + switch(err){ + + case CMD_OK: + DEBUG_TEST("%s: INTERRUPT OK: Dev %s Lcn %i Chan Lcn %i\n", + card->devname,dev->name, + mbox->wan_x25_lcn,chan->common.lcn); + break; + + case X25RES_CHANNEL_IN_USE: + case X25RES_ASYNC_PACKET: + case X25RES_NOT_READY: + err=-EAGAIN; + break; + + + case X25RES_LINK_NOT_IN_ABM: + case X25RES_INVAL_LCN: + case X25RES_INVAL_STATE: + + set_chan_state(dev, WAN_DISCONNECTED); + err = -EINVAL; + break; + + default: + /* If command did not execute because of user + * fault, do not change the state. This will + * signal the socket that clear command failed. + * User can retry or close the socket. + * When socket gets killed, it will set the + * chan->disconnect which will signal + * driver to clear the call */ + DEBUG_EVENT("%s: Clear Command Failed, Rc %x\n", + card->devname,err); + return -EINVAL; + } + break; + } + + return err; +} + +/*=============================================================== + * api_incoming_call + * + * Pass an incoming call request up the listening + * sock. If the API sock is not listening reject the + * call. + * + *===============================================================*/ + +static int api_incoming_call (sdla_t* card, wan_mbox_t *mbox, int lcn) +{ + unsigned char *buf; + x25api_hdr_t *x25_api_hdr; + netdevice_t *dev; + x25_channel_t *chan; + int len = sizeof(x25api_hdr_t)+mbox->wan_data_len; + struct sk_buff *skb; + int err=0; + + if (!card->sk){ + DEBUG_EVENT("%s: X25 Send API call request, no Sk ID\n", + card->devname); + return -ENODEV; + } + + dev=find_free_svc_dev(card); + if (dev == NULL){ + DEBUG_EVENT("%s: Failed incoming call req: no free svc !\n", + card->devname); + return -ENODEV; + } + + chan=dev->priv; + + if (alloc_and_init_skb_buf(card, &skb, len)){ + printk(KERN_INFO "%s: API incoming call, no memory\n",card->devname); + release_svc_dev(card,dev); + return -ENOMEM; + } + + buf = skb_push(skb,sizeof(x25api_hdr_t)); + if (!buf){ + release_svc_dev(card,dev); + wan_skb_free(skb); + return -ENOMEM; + } + + x25_api_hdr = (x25api_hdr_t *)buf; + + x25_api_hdr->qdm = mbox->wan_x25_qdm; + x25_api_hdr->cause = mbox->wan_x25_cause; + x25_api_hdr->diagn = mbox->wan_x25_diagn; + x25_api_hdr->pktType = mbox->wan_x25_pktType&0x7F; + x25_api_hdr->length = mbox->wan_data_len; + x25_api_hdr->result = 0; + x25_api_hdr->lcn = lcn; + x25_api_hdr->mtu = card->u.x.x25_conf.defPktSize; + x25_api_hdr->mru = card->u.x.x25_conf.defPktSize; + + if (mbox->wan_data_len > 0 && mbox->wan_data_len <= X25_CALL_STR_SZ){ + buf = skb_put(skb,mbox->wan_data_len); + if (!buf){ + release_svc_dev(card,dev); + wan_skb_free(skb); + return -ENOMEM; + } + memcpy(buf,mbox->wan_data,mbox->wan_data_len); + } + + memcpy(&chan->x25_api_event,skb->data,skb->len); + + skb->pkt_type = WAN_PACKET_ERR; + dev_hold(dev); + skb->dev=dev; + skb->destructor=wan_skb_destructor; + skb->protocol=htons(ETH_P_X25); + + bind_lcn_to_dev(card, dev, lcn); + set_chan_state(dev, WAN_CONNECTING); + + err=wanpipe_api_listen_rx(skb,card->sk); + + if (err!=0){ + release_svc_dev(card,dev); + wan_skb_free(skb); + set_chan_state(dev, WAN_DISCONNECTED); + } + + return err; +} + +/*=============================================================== + * clear_confirm_event + * + * Pass the clear confirmation event up the sock. The + * API will disconnect only after the clear confirmation + * has been received. + * + * Depending on the state, clear confirmation could + * be an OOB event, or a result of an API command. + *===============================================================*/ + +static int clear_confirm_event (sdla_t *card, wan_mbox_t* mb) +{ + netdevice_t *dev; + x25_channel_t *chan; + unsigned char old_state; + + dev = find_channel(card,mb->wan_x25_lcn); + if (!dev){ + DEBUG_EVENT("%s: Rx X25 Clear confirm on Lcn=%i: No dev!\n", + card->devname, mb->wan_x25_lcn); + return 1; + } + + chan=dev->priv; + DEBUG_EVENT("%s:%s Rx X25 Clear confirm on Lcn=%i\n", + card->devname, dev->name, mb->wan_x25_lcn); + + /* If not API fall through to default. + * If API, send the result to a waiting + * socket. + */ + + old_state = chan->common.state; + set_chan_state(dev, WAN_DISCONNECTED); + api_oob_event (card,mb); + + return 1; +} + +/*=============================================================== + * send_oob_msg + * + * Construct an NEM Message and pass it up the connected + * sock. If the sock is not bounded discard the NEM. + * + *===============================================================*/ + +static int send_oob_msg (sdla_t *card, netdevice_t *dev, wan_mbox_t *mbox) +{ + unsigned char *buf; + int len = sizeof(x25api_hdr_t)+mbox->wan_data_len; + x25api_hdr_t *x25_api_hdr; + x25_channel_t *chan=dev->priv; + struct sk_buff *skb; + int err=0; + + if (chan->common.usedby != API) + return -ENODEV; + + if (!chan->common.sk){ + return -ENODEV; + } + + if (len > sizeof(x25api_t)){ + DEBUG_EVENT("%s: %s: oob len > x25api_t!\n", + card->devname,__FUNCTION__); + return -EINVAL; + } + + if (alloc_and_init_skb_buf(card,&skb,len)){ + return -ENOMEM; + } + + buf = skb_put(skb,sizeof(x25api_hdr_t)); + if (!buf){ + wan_skb_free(skb); + return -ENOMEM; + } + + x25_api_hdr = (x25api_hdr_t *)buf; + + x25_api_hdr->qdm = mbox->wan_x25_qdm; + x25_api_hdr->cause = mbox->wan_x25_cause; + x25_api_hdr->diagn = mbox->wan_x25_diagn; + x25_api_hdr->pktType = mbox->wan_x25_pktType&0x7F; + x25_api_hdr->length = mbox->wan_data_len; + x25_api_hdr->result = 0; + x25_api_hdr->lcn = mbox->wan_x25_lcn; + x25_api_hdr->mtu = card->u.x.x25_conf.defPktSize; + x25_api_hdr->mru = card->u.x.x25_conf.defPktSize; + + if (mbox->wan_data_len > 0 && mbox->wan_data_len <= X25_CALL_STR_SZ){ + buf = skb_put(skb,mbox->wan_data_len); + if (!buf){ + wan_skb_free(skb); + return -ENOMEM; + } + memcpy(buf,mbox->wan_data,mbox->wan_data_len); + } + + memcpy(&chan->x25_api_event,skb->data,skb->len); + + skb->pkt_type = WAN_PACKET_ERR; + skb->protocol=htons(ETH_P_X25); + + if (wan_api_rx(chan,skb)!=0){ + printk(KERN_INFO "%s: Error: No dev for OOB\n", + chan->common.dev->name); + err=0; + wan_skb_free(skb); + } + + return err; +} + + +/*=============================================================== + * alloc_and_init_skb_buf + * + * Allocate and initialize an skb buffer. + * + *===============================================================*/ + +static int alloc_and_init_skb_buf (sdla_t *card, struct sk_buff **skb, int len) +{ + struct sk_buff *new_skb = *skb; + + new_skb = dev_alloc_skb(len + X25_HRDHDR_SZ); + if (new_skb == NULL){ + printk(KERN_INFO "%s: no socket buffers available!\n", + card->devname); + return 1; + } + + if (skb_tailroom(new_skb) < len){ + /* No room for the packet. Call off the whole thing! */ + wan_skb_free(new_skb); + printk(KERN_INFO "%s: Listen: unexpectedly long packet sequence\n" + ,card->devname); + *skb = NULL; + return 1; + } + + *skb = new_skb; + return 0; + +} + +/*=============================================================== + * api_oob_event + * + * Send an OOB event up to the sock + * + *===============================================================*/ + +static void api_oob_event (sdla_t *card,wan_mbox_t *mbox) +{ + netdevice_t *dev = find_channel(card,mbox->wan_x25_lcn); + x25_channel_t *chan; + + if (!dev) + return; + + chan=dev->priv; + + if (chan->common.usedby == API){ + send_oob_msg(card,dev,mbox); + } +} + +#if 0 +static void hdlc_link_down (sdla_t *card) +{ + wan_mbox_t* mbox = &card->wan_mbox; + int retry = 5; + int err=0; + + do { + memset(mbox,0,sizeof(wan_mbox_t)); + mbox->wan_command = X25_HDLC_LINK_DISC; + mbox->wan_data_len = 1; + mbox->wan_data[0]=0; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mbox); + + } while (err && x25_error(card, err, X25_HDLC_LINK_DISC, 0) && retry--); + + if (err) + printk(KERN_INFO "%s: Hdlc Link Down Failed %x\n",card->devname,err); + + disconnect (card); + +} +#endif + +static int check_bad_command (sdla_t* card, netdevice_t *dev) +{ + x25_channel_t *chan = dev->priv; + int bad_cmd = 0; + + switch (atomic_read(&chan->common.command)&0x7F){ + + case X25_PLACE_CALL: + if (chan->common.state != WAN_DISCONNECTED) + bad_cmd=1; + break; + case X25_CLEAR_CALL: + if (chan->common.state == WAN_DISCONNECTED) + bad_cmd=1; + break; + case X25_ACCEPT_CALL: + if (chan->common.state != WAN_CONNECTING) + bad_cmd=1; + break; + case X25_RESET: + if (chan->common.state != WAN_CONNECTED) + bad_cmd=1; + break; + case X25_WP_INTERRUPT: + if (chan->common.state != WAN_CONNECTED) + bad_cmd=1; + break; + default: + bad_cmd=1; + break; + } + + if (bad_cmd){ + printk(KERN_INFO "%s: Invalid State, BAD Command %x, dev %s, lcn %i, st %i\n", + card->devname,atomic_read(&chan->common.command),dev->name, + chan->common.lcn, chan->common.state); + } + + return bad_cmd; +} + + + +/*************************** XPIPEMON FUNCTIONS **************************/ + +/*============================================================================== + * Process UDP call of type XPIPE + */ + +static int process_udp_mgmt_pkt(sdla_t *card,netdevice_t *local_dev) +{ + int c_retry = MAX_CMD_RETRY; + unsigned int len; + struct sk_buff *new_skb; + wan_mbox_t* mbox = &card->wan_mbox; + int err; + int udp_mgmt_req_valid = 1; + netdevice_t *dev; + x25_channel_t *chan; + unsigned short lcn; + struct timeval tv; + wan_udp_pkt_t *wan_udp_pkt = (wan_udp_pkt_t *)&card->u.x.udp_pkt_data; + + if (local_dev){ + dev = local_dev; + }else{ + dev = card->u.x.udp_dev; + } + + if (!dev){ + atomic_set(&card->u.x.udp_pkt_len,0); + return 0; + } + + chan = dev->priv; + lcn = chan->common.lcn; + + switch(wan_udp_pkt->wan_udp_command) { + + /* XPIPE_ENABLE_TRACE */ + case XPIPE_ENABLE_TRACING: + + /* XPIPE_GET_TRACE_INFO */ + case XPIPE_GET_TRACE_INFO: + + /* SET FT1 MODE */ + case XPIPE_SET_FT1_MODE: + + if(card->u.x.udp_pkt_src == UDP_PKT_FRM_NETWORK) { + ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_direction_err; + udp_mgmt_req_valid = 0; + break; + } + + /* XPIPE_FT1_READ_STATUS */ + case XPIPE_FT1_READ_STATUS: + + /* FT1 MONITOR STATUS */ + case XPIPE_FT1_STATUS_CTRL: + // ALEX_TODAY if(card->hw.fwid != SFID_X25_508) { + if (card->type == SDLA_S508){ + ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_adptr_type_err; + udp_mgmt_req_valid = 0; + break; + } + default: + break; + } + + if(!udp_mgmt_req_valid) { + /* set length to 0 */ + wan_udp_pkt->wan_udp_data_len = 0; + /* set return code */ + //ALEX_TODAY wan_udp_pkt->wan_udp_return_code = (card->hw.fwid != SFID_X25_508) ? 0x1F : 0xCD; + wan_udp_pkt->wan_udp_return_code = (card->type != SDLA_S508) ? 0x1F : 0xCD; + + } else { + + switch (wan_udp_pkt->wan_udp_command) { + + + case XPIPE_FLUSH_DRIVER_STATS: + init_x25_channel_struct(chan); + init_global_statistics(card); + mbox->wan_data_len = 0; + break; + + + case XPIPE_DRIVER_STAT_IFSEND: + memcpy(wan_udp_pkt->wan_udp_data, &chan->if_send_stat, sizeof(if_send_stat_t)); + mbox->wan_data_len = sizeof(if_send_stat_t); + wan_udp_pkt->wan_udp_data_len = mbox->wan_data_len; + break; + + case XPIPE_DRIVER_STAT_INTR: + memcpy(&wan_udp_pkt->wan_udp_data[0], &card->statistics, sizeof(global_stats_t)); + memcpy(&wan_udp_pkt->wan_udp_data[sizeof(global_stats_t)], + &chan->rx_intr_stat, sizeof(rx_intr_stat_t)); + + mbox->wan_data_len = sizeof(global_stats_t) + + sizeof(rx_intr_stat_t); + wan_udp_pkt->wan_udp_data_len = mbox->wan_data_len; + break; + + case XPIPE_DRIVER_STAT_GEN: + memcpy(wan_udp_pkt->wan_udp_data, + &chan->pipe_mgmt_stat.UDP_PIPE_mgmt_kmalloc_err, + sizeof(pipe_mgmt_stat_t)); + + memcpy(&wan_udp_pkt->wan_udp_data[sizeof(pipe_mgmt_stat_t)], + &card->statistics, sizeof(global_stats_t)); + + wan_udp_pkt->wan_udp_return_code = 0; + wan_udp_pkt->wan_udp_data_len = sizeof(global_stats_t)+ + sizeof(rx_intr_stat_t); + mbox->wan_data_len = wan_udp_pkt->wan_udp_data_len; + break; + + case XPIPE_ROUTER_UP_TIME: + do_gettimeofday(&tv); + chan->router_up_time = tv.tv_sec - chan->router_start_time; + *(unsigned long *)&wan_udp_pkt->wan_udp_data = chan->router_up_time; + wan_udp_pkt->wan_udp_data_len = mbox->wan_data_len = 4; + wan_udp_pkt->wan_udp_return_code = 0; + break; + + case WAN_GET_PROTOCOL: + wan_udp_pkt->wan_udp_data[0] = card->wandev.config_id; + wan_udp_pkt->wan_udp_return_code = CMD_OK; + mbox->wan_data_len = wan_udp_pkt->wan_udp_data_len = 1; + break; + + case WAN_GET_PLATFORM: + wan_udp_pkt->wan_udp_data[0] = WAN_LINUX_PLATFORM; + wan_udp_pkt->wan_udp_return_code = CMD_OK; + mbox->wan_data_len = wan_udp_pkt->wan_udp_data_len = 1; + break; + + case XPIPE_GET_TRACE_INFO: + + card->u.x.trace_timeout=jiffies; + + new_skb=wan_skb_dequeue(&card->u.x.trace_queue); + if (!new_skb){ + wan_udp_pkt->wan_udp_return_code = 1; + mbox->wan_data_len = wan_udp_pkt->wan_udp_data_len = 0; + break; + } + + memcpy(wan_udp_pkt->wan_udp_data,new_skb->data,new_skb->len); + + wan_udp_pkt->wan_udp_return_code = CMD_OK; + mbox->wan_data_len = wan_udp_pkt->wan_udp_data_len = new_skb->len; + + wan_skb_free(new_skb); + new_skb=NULL; + break; + + case XPIPE_DISABLE_TRACING: + card->u.x.trace_timeout=jiffies; + wan_skb_queue_purge(&card->u.x.trace_queue); + goto x25_udp_cmd; + + + default : +x25_udp_cmd: + if (card->u.x.LAPB_hdlc){ + switch (wan_udp_pkt->wan_udp_command){ + case X25_READ_CONFIGURATION: + wan_udp_pkt->wan_udp_command=X25_HDLC_READ_CONFIG; + break; + } + } + + do { + memcpy(&mbox->wan_command, &wan_udp_pkt->wan_udp_command, sizeof(TX25Cmd)); + if(mbox->wan_data_len){ + memcpy(&mbox->wan_data, + (char *)wan_udp_pkt->wan_udp_data, + mbox->wan_data_len); + } + + err = card->hw_iface.cmd(card->hw, card->mbox_off, mbox); + } while (err && x25_error(card, err, mbox->wan_command, 0) && c_retry--); + + + if ( err == CMD_OK || + (err == 1 && + (mbox->wan_command == 0x06 || + mbox->wan_command == 0x16) ) ){ + + ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_adptr_cmnd_OK; + } else { + ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_adptr_cmnd_timeout; + } + + /* copy the result back to our buffer */ + memcpy(&wan_udp_pkt->wan_udp_command, &mbox->wan_command, sizeof(TX25Cmd)); + + if(mbox->wan_data_len) { + memcpy(&wan_udp_pkt->wan_udp_data, &mbox->wan_data, mbox->wan_data_len); + } + break; + + } //switch + + } + + if (local_dev){ + return 1; + } + + /* Fill UDP TTL */ + + wan_udp_pkt->wan_ip_ttl = card->wandev.ttl; + + len = reply_udp((u8*)&card->u.x.udp_pkt_data, mbox->wan_data_len); + + if(card->u.x.udp_pkt_src == UDP_PKT_FRM_NETWORK) { + + err = x25_send(card, lcn, 0, len, (u8*)&card->u.x.udp_pkt_data); + if (!err) + ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_adptr_send_passed; + else + ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_adptr_send_failed; + + } else { + + /* Allocate socket buffer */ + if((new_skb = dev_alloc_skb(len)) != NULL) { + void *buf; + + /* copy data into new_skb */ + buf = skb_put(new_skb, len); + memcpy(buf, (u8*)&card->u.x.udp_pkt_data, len); + + /* Decapsulate packet and pass it up the protocol + stack */ + new_skb->dev = dev; + + if (chan->common.usedby == API) + new_skb->protocol = htons(X25_PROT); + else + new_skb->protocol = htons(ETH_P_IP); + + new_skb->mac.raw = new_skb->data; + + netif_rx(new_skb); + ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_passed_to_stack; + + } else { + ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_no_socket; + printk(KERN_INFO + "%s: UDP mgmt cmnd, no socket buffers available!\n", + card->devname); + } + } + + atomic_set(&card->u.x.udp_pkt_len,0); + return 1; +} + + +/*============================================================================== + * Determine what type of UDP call it is. DRVSTATS or XPIPE8ND ? + */ +static int udp_pkt_type( struct sk_buff *skb, sdla_t* card ) +{ + wan_udp_pkt_t *wan_udp_pkt = (wan_udp_pkt_t *)skb->data; + + if (skb->len < sizeof(wan_udp_pkt_t)){ + return UDP_INVALID_TYPE; + } + + if((wan_udp_pkt->wan_ip_p == UDPMGMT_UDP_PROTOCOL) && + (wan_udp_pkt->wan_udp_dport == ntohs(card->wandev.udp_port)) && + (wan_udp_pkt->wan_udp_request_reply == UDPMGMT_REQUEST)) { + + if(!strncmp(wan_udp_pkt->wan_udp_signature, + UDPMGMT_XPIPE_SIGNATURE, 8)){ + return UDP_XPIPE_TYPE; + } + + if(!strncmp(wan_udp_pkt->wan_udp_signature, + GLOBAL_UDP_SIGNATURE, 8)){ + return UDP_XPIPE_TYPE; + } + + printk(KERN_INFO "%s: UDP Packet, Failed Signature !\n", + card->devname); + } + + return UDP_INVALID_TYPE; +} + + +/*============================================================================ + * Reply to UDP Management system. + * Return nothing. + */ + +static int reply_udp( unsigned char *data, unsigned int mbox_len ) +{ + unsigned short len, udp_length, temp, ip_length; + unsigned long ip_temp; + int even_bound = 0; + wan_udp_pkt_t *wan_udp_pkt = (wan_udp_pkt_t *)data; + + /* Set length of packet */ + len = //sizeof(fr_encap_hdr_t)+ + sizeof(struct iphdr)+ + sizeof(struct udphdr)+ + sizeof(wan_mgmt_t)+ + sizeof(wan_cmd_t)+ + mbox_len; + + + /* fill in UDP reply */ + wan_udp_pkt->wan_udp_request_reply = UDPMGMT_REPLY; + + /* fill in UDP length */ + udp_length = sizeof(struct udphdr)+ + sizeof(wan_mgmt_t)+ + sizeof(wan_cmd_t)+ + mbox_len; + + + /* put it on an even boundary */ + if ( udp_length & 0x0001 ) { + udp_length += 1; + len += 1; + even_bound = 1; + } + + temp = (udp_length<<8)|(udp_length>>8); + wan_udp_pkt->wan_udp_len = temp; + + /* swap UDP ports */ + temp = wan_udp_pkt->wan_udp_sport; + wan_udp_pkt->wan_udp_sport = + wan_udp_pkt->wan_udp_dport; + wan_udp_pkt->wan_udp_dport = temp; + + + + /* add UDP pseudo header */ + temp = 0x1100; + *((unsigned short *) + (wan_udp_pkt->wan_udp_data+mbox_len+even_bound)) = temp; + temp = (udp_length<<8)|(udp_length>>8); + *((unsigned short *) + (wan_udp_pkt->wan_udp_data+mbox_len+even_bound+2)) = temp; + + /* calculate UDP checksum */ + wan_udp_pkt->wan_udp_sum = 0; + + wan_udp_pkt->wan_udp_sum = + calc_checksum(&data[UDP_OFFSET/*+sizeof(fr_encap_hdr_t)*/], + udp_length+UDP_OFFSET); + + /* fill in IP length */ + ip_length = udp_length + sizeof(struct iphdr); + temp = (ip_length<<8)|(ip_length>>8); + wan_udp_pkt->wan_ip_len = temp; + + /* swap IP addresses */ + ip_temp = wan_udp_pkt->wan_ip_src; + wan_udp_pkt->wan_ip_src = + wan_udp_pkt->wan_ip_dst; + wan_udp_pkt->wan_ip_dst = ip_temp; + + + /* fill in IP checksum */ + wan_udp_pkt->wan_ip_sum = 0; + wan_udp_pkt->wan_ip_sum = + calc_checksum(&data[0], + sizeof(struct iphdr)); + + return len; +} /* reply_udp */ + + +unsigned short calc_checksum (char *data, int len) +{ + unsigned short temp; + unsigned long sum=0; + int i; + + for( i = 0; i > 16 ) { + sum = (sum & 0xffffUL) + (sum >> 16); + } + + temp = (unsigned short)sum; + temp = ~temp; + + if( temp == 0 ) + temp = 0xffff; + + return temp; +} + +/*============================================================================= + * Store a UDP management packet for later processing. + */ + +static int store_udp_mgmt_pkt(int udp_type, char udp_pkt_src, sdla_t* card, + netdevice_t *dev, struct sk_buff *skb, int lcn) +{ + int udp_pkt_stored = 0; + + if(!atomic_read(&card->u.x.udp_pkt_len) && (skb->len <= sizeof(card->u.x.udp_pkt_data))){ + atomic_set(&card->u.x.udp_pkt_len,skb->len); + card->u.x.udp_type = udp_type; + card->u.x.udp_pkt_src = udp_pkt_src; + card->u.x.udp_lcn = lcn; + card->u.x.udp_dev = dev; + memcpy((u8*)&card->u.x.udp_pkt_data, skb->data, skb->len); + card->u.x.timer_int_enabled |= TMR_INT_ENABLED_UDP_PKT; + udp_pkt_stored = 1; + + }else{ + printk(KERN_INFO "%s: ERROR: UDP packet not stored for LCN %d\n", + card->devname,lcn); + } + + wan_skb_free(skb); + + return(udp_pkt_stored); +} + + + +/*============================================================================= + * Initial the ppp_private_area structure. + */ +static void init_x25_channel_struct( x25_channel_t *chan ) +{ + memset(&chan->if_send_stat.if_send_entry,0,sizeof(if_send_stat_t)); + memset(&chan->rx_intr_stat.rx_intr_no_socket,0,sizeof(rx_intr_stat_t)); + memset(&chan->pipe_mgmt_stat.UDP_PIPE_mgmt_kmalloc_err,0,sizeof(pipe_mgmt_stat_t)); +} + +/*============================================================================ + * Initialize Global Statistics + */ +static void init_global_statistics( sdla_t *card ) +{ + memset(&card->statistics.isr_entry,0,sizeof(global_stats_t)); +} + + +/*=============================================================== + * SMP Support + * ==============================================================*/ + +static void S508_S514_lock(sdla_t *card, unsigned long *smp_flags) +{ + spin_lock_irqsave(&card->wandev.lock, *smp_flags); +} +static void S508_S514_unlock(sdla_t *card, unsigned long *smp_flags) +{ + spin_unlock_irqrestore(&card->wandev.lock, *smp_flags); +} + +/*=============================================================== + * x25_timer_routine + * + * A more efficient polling routine. Each half a second + * queue a polling task. We want to do the polling in a + * task not timer, because timer runs in interrupt time. + * + * FIXME Polling should be rethinked. + *==============================================================*/ + +static void x25_timer_routine(unsigned long data) +{ + sdla_t *card = (sdla_t*)data; + + if (test_bit(PERI_CRIT,&card->wandev.critical)){ + printk(KERN_INFO "%s: Stopping the X25 Poll Timer: Shutting down.\n", + card->devname); + return; + } + + if (card->open_cnt != card->u.x.num_of_ch){ + printk(KERN_INFO "%s: Stopping the X25 Poll Timer: Interface down.\n", + card->devname); + return; + } + + if (!WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head))){ + printk(KERN_INFO "%s: Stopping the X25 Poll Timer: No Dev.\n", + card->devname); + return; + } + + if (!test_and_set_bit(POLL_CRIT,&card->wandev.critical)){ + trigger_x25_poll(card); + } + + card->u.x.x25_timer.expires=jiffies+(HZ>>1); + add_timer(&card->u.x.x25_timer); + return; +} + +void disable_comm_shutdown(sdla_t *card) +{ + wan_mbox_t* mbox = &card->wan_mbox; + int err; + + /* Turn of interrutps */ + mbox->wan_data[0] = 0; + // ALEX_TODAY if (card->hw.fwid == SFID_X25_508){ + if (card->type == SDLA_S508){ + mbox->wan_data[1] = card->wandev.irq; // ALEX_TODAY card->hw.irq; + mbox->wan_data[2] = 2; + mbox->wan_data_len = 3; + }else { + mbox->wan_data_len = 1; + } + mbox->wan_command = X25_SET_INTERRUPT_MODE; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mbox); + if (err) + printk(KERN_INFO "INTERRUPT OFF FAIED %x\n",err); + + /* Bring down HDLC */ + mbox->wan_command = X25_HDLC_LINK_CLOSE; + mbox->wan_data_len = 0; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mbox); + if (err) + printk(KERN_INFO "LINK CLOSED FAILED %x\n",err); + + + /* Brind down DTR */ + mbox->wan_data[0] = 0; + mbox->wan_data[2] = 0; + mbox->wan_data[1] = 0x01; + mbox->wan_data_len = 3; + mbox->wan_command = X25_SET_GLOBAL_VARS; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mbox); + if (err) + printk(KERN_INFO "DTR DOWN FAILED %x\n",err); + +} + +static void x25_clear_cmd_update(sdla_t* card, unsigned lcn, wan_mbox_t* mb) +{ + netdevice_t* dev = find_channel(card, lcn); + x25_channel_t* chan = NULL; + x25_call_info_t info; + struct timeval tv; + + if (dev == NULL || dev->priv == NULL) + return; + + chan=dev->priv; + do_gettimeofday(&tv); + chan->chan_clear_time = tv.tv_sec; + chan->chan_clear_cause = mb->wan_x25_cause; + chan->chan_clear_diagn = mb->wan_x25_diagn; + + if (mb->wan_data_len){ + parse_call_info(mb->wan_data, &info); + memcpy(chan->cleared_called_addr, info.src, MAX_X25_ADDR_SIZE); + memcpy(chan->cleared_calling_addr, info.dest, MAX_X25_ADDR_SIZE); + memcpy(chan->cleared_facil, info.facil, MAX_X25_FACL_SIZE); + } + return; +} + +/* + ******************************************************************** + * Proc FS function + */ +#define PROC_CFG_FRM "%-15s| %-12s| %-5u| %-9s| %-13s| %-13s|\n" +#define PROC_STAT_FRM "%-15s| %-12s| %-5u| %-14s|\n" +static char x25_config_hdr[] = + "Interface name | Device name | LCN | Src Addr | Accept DAddr | Accept UData |\n"; +static char x25_status_hdr[] = + "Interface name | Device name | LCN | Status |\n"; + +static int x25_get_config_info(void* priv, struct seq_file* m, int* stop_cnt) +{ + x25_channel_t* chan = (x25_channel_t*)priv; + sdla_t* card = chan->card; + + if (chan == NULL) + return m->count; + if ((m->from == 0 && m->count == 0) || (m->from && m->from == *stop_cnt)){ + PROC_ADD_LINE(m, + "%s", x25_config_hdr); + } + + PROC_ADD_LINE(m, + PROC_CFG_FRM, chan->name, card->devname, chan->ch_idx, + chan->x25_src_addr, chan->accept_dest_addr, chan->accept_usr_data); + return m->count; +} + +static int x25_get_status_info(void* priv, struct seq_file* m, int* stop_cnt) +{ + x25_channel_t* chan = (x25_channel_t*)priv; + sdla_t* card = chan->card; + + if (chan == NULL) + return m->count; + if ((m->from == 0 && m->count == 0) || (m->from && m->from == *stop_cnt)){ + PROC_ADD_LINE(m, + "%s", x25_status_hdr); + } + + PROC_ADD_LINE(m, + PROC_STAT_FRM, chan->name, card->devname, + chan->ch_idx, STATE_DECODE(chan->common.state)); + return m->count; +} + +#define PROC_DEV_FR_SS_FRM "%-20s| %-12s|%-20s| %-12s|\n" +#define PROC_DEV_FR_SD_FRM "%-20s| %-12s|%-20s| %-12d|\n" +#define PROC_DEV_FR_DD_FRM "%-20s| %-12d|%-20s| %-12d|\n" +#define PROC_DEV_FR_XD_FRM "%-20s| 0x%-10X|%-20s| %-12d|\n" +#define PROC_DEV_SEPARATE "===================================" +#define PROC_DEV_TITLE " Parameters | Value |" + + +static int x25_set_dev_config(struct file *file, + const char *buffer, + unsigned long count, + void *data) +{ + wan_device_t* wandev = (void*)data; + sdla_t* card = NULL; + + if (wandev == NULL) + return count; + + card = (sdla_t*)wandev->private; + + printk(KERN_INFO "%s: New device config (%s)\n", + wandev->name, buffer); + /* Parse string */ + + return count; +} + +/* SNMP + ****************************************************************************** + * x25_snmp_data() + * + * Description: Save snmp request and parameters in private structure, enable + * TIMER interrupt, put current process in sleep. + * Arguments: + * Returns: + ****************************************************************************** + */ +#define X25ADMNINDEX 3 +#define X25ADMNINTERFACEMODE 4 +#define X25ADMNMAXACTIVECIRCUITS 5 +#define X25ADMNPACKETSEQUENCING 6 +#define X25ADMNRESTARTTIMER 7 +#define X25ADMNCALLTIMER 8 +#define X25ADMNRESETTIMER 9 +#define X25ADMNCLEARTIMER 10 +#define X25ADMNWINDOWTIMER 11 +#define X25ADMNDATARXMTTIMER 12 +#define X25ADMNINTERRUPTTIMER 13 +#define X25ADMNREJECTTIMER 14 +#define X25ADMNREGISTRATIONREQUESTTIMER 15 +#define X25ADMNMINIMUMRECALLTIMER 16 +#define X25ADMNRESTARTCOUNT 17 +#define X25ADMNRESETCOUNT 18 +#define X25ADMNCLEARCOUNT 19 +#define X25ADMNDATARXMTCOUNT 20 +#define X25ADMNREJECTCOUNT 21 +#define X25ADMNREGISTRATIONREQUESTCOUNT 22 +#define X25ADMNNUMBERPVCS 23 +#define X25ADMNDEFCALLPARAMID 24 +#define X25ADMNLOCALADDRESS 25 +#define X25ADMNPROTOCOLVERSIONSUPPORTED 26 +#define X25OPERINDEX 29 +#define X25OPERINTERFACEMODE 30 +#define X25OPERMAXACTIVECIRCUITS 31 +#define X25OPERPACKETSEQUENCING 32 +#define X25OPERRESTARTTIMER 33 +#define X25OPERCALLTIMER 34 +#define X25OPERRESETTIMER 35 +#define X25OPERCLEARTIMER 36 +#define X25OPERWINDOWTIMER 37 +#define X25OPERDATARXMTTIMER 38 +#define X25OPERINTERRUPTTIMER 39 +#define X25OPERREJECTTIMER 40 +#define X25OPERREGISTRATIONREQUESTTIMER 41 +#define X25OPERMINIMUMRECALLTIMER 42 +#define X25OPERRESTARTCOUNT 43 +#define X25OPERRESETCOUNT 44 +#define X25OPERCLEARCOUNT 45 +#define X25OPERDATARXMTCOUNT 46 +#define X25OPERREJECTCOUNT 47 +#define X25OPERREGISTRATIONREQUESTCOUNT 48 +#define X25OPERNUMBERPVCS 49 +#define X25OPERDEFCALLPARAMID 50 +#define X25OPERLOCALADDRESS 51 +#define X25OPERDATALINKID 52 +#define X25OPERPROTOCOLVERSIONSUPPORTED 53 +#define X25STATINDEX 56 +#define X25STATINCALLS 57 +#define X25STATINCALLREFUSALS 58 +#define X25STATINPROVIDERINITIATEDCLEARS 59 +#define X25STATINREMOTELYINITIATEDRESETS 60 +#define X25STATINPROVIDERINITIATEDRESETS 61 +#define X25STATINRESTARTS 62 +#define X25STATINDATAPACKETS 63 +#define X25STATINACCUSEDOFPROTOCOLERRORS 64 +#define X25STATININTERRUPTS 65 +#define X25STATOUTCALLATTEMPTS 66 +#define X25STATOUTCALLFAILURES 67 +#define X25STATOUTINTERRUPTS 68 +#define X25STATOUTDATAPACKETS 69 +#define X25STATOUTGOINGCIRCUITS 70 +#define X25STATINCOMINGCIRCUITS 71 +#define X25STATTWOWAYCIRCUITS 72 +#define X25STATRESTARTTIMEOUTS 73 +#define X25STATCALLTIMEOUTS 74 +#define X25STATRESETTIMEOUTS 75 +#define X25STATCLEARTIMEOUTS 76 +#define X25STATDATARXMTTIMEOUTS 77 +#define X25STATINTERRUPTTIMEOUTS 78 +#define X25STATRETRYCOUNTEXCEEDEDS 79 +#define X25STATCLEARCOUNTEXCEEDEDS 80 +#define X25CHANNELINDEX 83 +#define X25CHANNELLIC 84 +#define X25CHANNELHIC 85 +#define X25CHANNELLTC 86 +#define X25CHANNELHTC 87 +#define X25CHANNELLOC 88 +#define X25CHANNELHOC 89 +#define X25CIRCUITINDEX 92 +#define X25CIRCUITCHANNEL 93 +#define X25CIRCUITSTATUS 94 +#define X25CIRCUITESTABLISHTIME 95 +#define X25CIRCUITDIRECTION 96 +#define X25CIRCUITINOCTETS 97 +#define X25CIRCUITINPDUS 98 +#define X25CIRCUITINREMOTELYINITIATEDRESETS 99 +#define X25CIRCUITINPROVIDERINITIATEDRESETS 100 +#define X25CIRCUITININTERRUPTS 101 +#define X25CIRCUITOUTOCTETS 102 +#define X25CIRCUITOUTPDUS 103 +#define X25CIRCUITOUTINTERRUPTS 104 +#define X25CIRCUITDATARETRANSMISSIONTIMEOUTS 105 +#define X25CIRCUITRESETTIMEOUTS 106 +#define X25CIRCUITINTERRUPTTIMEOUTS 107 +#define X25CIRCUITCALLPARAMID 108 +#define X25CIRCUITCALLEDDTEADDRESS 109 +#define X25CIRCUITCALLINGDTEADDRESS 110 +#define X25CIRCUITORIGINALLYCALLEDADDRESS 111 +#define X25CIRCUITDESCR 112 +#define X25CLEAREDCIRCUITENTRIESREQUESTED 113 +#define X25CLEAREDCIRCUITENTRIESGRANTED 114 +#define X25CLEAREDCIRCUITINDEX 117 +#define X25CLEAREDCIRCUITPLEINDEX 118 +#define X25CLEAREDCIRCUITTIMEESTABLISHED 119 +#define X25CLEAREDCIRCUITTIMECLEARED 120 +#define X25CLEAREDCIRCUITCHANNEL 121 +#define X25CLEAREDCIRCUITCLEARINGCAUSE 122 +#define X25CLEAREDCIRCUITDIAGNOSTICCODE 123 +#define X25CLEAREDCIRCUITINPDUS 124 +#define X25CLEAREDCIRCUITOUTPDUS 125 +#define X25CLEAREDCIRCUITCALLEDADDRESS 126 +#define X25CLEAREDCIRCUITCALLINGADDRESS 127 +#define X25CLEAREDCIRCUITCLEARFACILITIES 128 +#define X25CALLPARMINDEX 131 +#define X25CALLPARMSTATUS 132 +#define X25CALLPARMREFCOUNT 133 +#define X25CALLPARMINPACKETSIZE 134 +#define X25CALLPARMOUTPACKETSIZE 135 +#define X25CALLPARMINWINDOWSIZE 136 +#define X25CALLPARMOUTWINDOWSIZE 137 +#define X25CALLPARMACCEPTREVERSECHARGING 138 +#define X25CALLPARMPROPOSEREVERSECHARGING 139 +#define X25CALLPARMFASTSELECT 140 +#define X25CALLPARMINTHRUPUTCLASSIZE 141 +#define X25CALLPARMOUTTHRUPUTCLASSIZE 142 +#define X25CALLPARMCUG 143 +#define X25CALLPARMCUGOA 144 +#define X25CALLPARMBCUG 145 +#define X25CALLPARMNUI 146 +#define X25CALLPARMCHARGINGINFO 147 +#define X25CALLPARMRPOA 148 +#define X25CALLPARMTRNSTDLY 149 +#define X25CALLPARMCALLINGEXT 150 +#define X25CALLPARMCALLEDEXT 151 +#define X25CALLPARMINMINTHUPUTCLS 152 +#define X25CALLPARMOUTMINTHUPUTCLS 153 +#define X25CALLPARMENDTRNSDLY 154 +#define X25CALLPARMPRIORITY 155 +#define X25CALLPARMPROTECTION 156 +#define X25CALLPARMEXPTDATA 157 +#define X25CALLPARMUSERDATA 158 +#define X25CALLPARMCALLINGNETWORKFACILITIES 159 +#define X25CALLPARMCALLEDNETWORKFACILITIES 160 + +static int x25_snmp_data(sdla_t* card, netdevice_t *dev, void* data) +{ + x25_channel_t* chan = NULL; + wanpipe_snmp_t* snmp; + + if (dev == NULL || dev->priv == NULL) + return -EFAULT; + chan = (x25_channel_t*)dev->priv; + /* Update device statistics */ + if (card->wandev.update) { + int rslt = 0; + rslt = card->wandev.update(&card->wandev); + if(rslt) { + return (rslt) ? (-EBUSY) : (-EINVAL); + } + } + + snmp = (wanpipe_snmp_t*)data; + + switch(snmp->snmp_magic){ + /********** X.25 Administration Table *********/ + case X25ADMNINDEX: + break; + + case X25ADMNINTERFACEMODE: + snmp->snmp_val = + (card->wandev.station == WANOPT_DTE) ? SNMP_X25_DTE: + (card->wandev.station == WANOPT_DCE) ? SNMP_X25_DCE:SNMP_X25_DXE; + break; + + case X25ADMNMAXACTIVECIRCUITS: + snmp->snmp_val = card->u.x.num_of_ch; + break; + + case X25ADMNPACKETSEQUENCING: + snmp->snmp_val = SNMP_X25_MODULO8; + break; + + case X25ADMNRESTARTTIMER: + snmp->snmp_val = card->u.x.x25_adm_conf.t10_t20; + break; + + case X25ADMNCALLTIMER: + snmp->snmp_val = card->u.x.x25_adm_conf.t11_t21; + break; + + case X25ADMNRESETTIMER: + snmp->snmp_val = card->u.x.x25_adm_conf.t12_t22; + break; + + case X25ADMNCLEARTIMER: + snmp->snmp_val = card->u.x.x25_adm_conf.t13_t23; + break; + + case X25ADMNWINDOWTIMER: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25ADMNDATARXMTTIMER: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25ADMNINTERRUPTTIMER: + snmp->snmp_val = card->u.x.x25_adm_conf.t16_t26; + break; + + case X25ADMNREJECTTIMER: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25ADMNREGISTRATIONREQUESTTIMER: + snmp->snmp_val = card->u.x.x25_adm_conf.t28; + break; + + case X25ADMNMINIMUMRECALLTIMER: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25ADMNRESTARTCOUNT: + snmp->snmp_val = card->u.x.x25_adm_conf.r10_r20; + break; + + case X25ADMNRESETCOUNT: + snmp->snmp_val = card->u.x.x25_adm_conf.r12_r22; + break; + + case X25ADMNCLEARCOUNT: + snmp->snmp_val = card->u.x.x25_adm_conf.r13_r23; + break; + + case X25ADMNDATARXMTCOUNT: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25ADMNREJECTCOUNT: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25ADMNREGISTRATIONREQUESTCOUNT: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25ADMNNUMBERPVCS: + snmp->snmp_val = card->u.x.x25_adm_conf.hi_pvc; + break; + + case X25ADMNDEFCALLPARAMID: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25ADMNLOCALADDRESS: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25ADMNPROTOCOLVERSIONSUPPORTED: /* FIXME */ + snmp->snmp_val = 0; + break; + + /********** X.25 Operational Table *********/ + case X25OPERINDEX: + break; + + case X25OPERINTERFACEMODE: + snmp->snmp_val = (card->wandev.station == WANOPT_DTE) ? SNMP_X25_DTE: + (card->wandev.station == WANOPT_DCE) ? SNMP_X25_DCE:SNMP_X25_DXE; + break; + + case X25OPERMAXACTIVECIRCUITS: + snmp->snmp_val = card->u.x.num_of_ch; + break; + + case X25OPERPACKETSEQUENCING: + snmp->snmp_val = SNMP_X25_MODULO8; + break; + + case X25OPERRESTARTTIMER: + snmp->snmp_val = card->u.x.x25_conf.t10_t20; + break; + + case X25OPERCALLTIMER: + snmp->snmp_val = card->u.x.x25_conf.t11_t21; + break; + + case X25OPERRESETTIMER: + snmp->snmp_val = card->u.x.x25_conf.t12_t22; + break; + + case X25OPERCLEARTIMER: + snmp->snmp_val = card->u.x.x25_conf.t13_t23; + break; + + case X25OPERWINDOWTIMER: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25OPERDATARXMTTIMER: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25OPERINTERRUPTTIMER: + snmp->snmp_val = card->u.x.x25_conf.t16_t26; + break; + + case X25OPERREJECTTIMER: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25OPERREGISTRATIONREQUESTTIMER: + snmp->snmp_val = card->u.x.x25_conf.t28; + break; + + case X25OPERMINIMUMRECALLTIMER: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25OPERRESTARTCOUNT: + snmp->snmp_val = card->u.x.x25_conf.r10_r20; + break; + + case X25OPERRESETCOUNT: + snmp->snmp_val = card->u.x.x25_conf.r12_r22; + break; + + case X25OPERCLEARCOUNT: + snmp->snmp_val = card->u.x.x25_conf.r13_r23; + break; + + case X25OPERDATARXMTCOUNT: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25OPERREJECTCOUNT: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25OPERREGISTRATIONREQUESTCOUNT: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25OPERNUMBERPVCS: + snmp->snmp_val = card->u.x.x25_conf.hi_pvc; + break; + + case X25OPERDEFCALLPARAMID: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25OPERLOCALADDRESS: /* FIXME */ + strcpy((void*)snmp->snmp_data, "N/A"); + break; + + case X25OPERDATALINKID: /* FIXME */ + strcpy((void*)snmp->snmp_data, "N/A"); + break; + + case X25OPERPROTOCOLVERSIONSUPPORTED: /* FIXME */ + strcpy((void*)snmp->snmp_data, "N/A"); + break; + + + + /********** X.25 Statistics Table *********/ + case X25STATINDEX: + break; + + case X25STATINCALLS: + snmp->snmp_val = X25Stats.rxCallRequest; + break; + + case X25STATINCALLREFUSALS: + snmp->snmp_val = X25Stats.txClearRqst; + break; + + case X25STATINPROVIDERINITIATEDCLEARS: + snmp->snmp_val = (card->wandev.station == WANOPT_DTE) ? + X25Stats.rxClearRqst: + X25Stats.txClearRqst; + break; + + case X25STATINREMOTELYINITIATEDRESETS: + snmp->snmp_val = (card->wandev.station == WANOPT_DTE) ? + X25Stats.txResetRqst: + X25Stats.rxResetRqst; + break; + + case X25STATINPROVIDERINITIATEDRESETS: + snmp->snmp_val = (card->wandev.station == WANOPT_DTE) ? + X25Stats.rxResetRqst: + X25Stats.txResetRqst; + break; + + case X25STATINRESTARTS: + snmp->snmp_val = X25Stats.rxRestartRqst; + break; + + case X25STATINDATAPACKETS: + snmp->snmp_val = X25Stats.rxData; + break; + + case X25STATINACCUSEDOFPROTOCOLERRORS: + snmp->snmp_val = X25Stats.rxClearRqst+X25Stats.rxResetRqst+ + X25Stats.rxRestartRqst+X25Stats.rxDiagnostic; + break; + + case X25STATININTERRUPTS: + snmp->snmp_val = X25Stats.rxInterrupt; + break; + + case X25STATOUTCALLATTEMPTS: + snmp->snmp_val = X25Stats.txCallRequest; + break; + + case X25STATOUTCALLFAILURES: + snmp->snmp_val = X25Stats.rxClearRqst; + break; + + case X25STATOUTINTERRUPTS: + snmp->snmp_val = X25Stats.txInterrupt; + break; + + case X25STATOUTDATAPACKETS: + snmp->snmp_val = X25Stats.txData; + break; + + case X25STATOUTGOINGCIRCUITS: + snmp->snmp_val = X25Stats.txCallRequest-X25Stats.rxClearRqst; + break; + + case X25STATINCOMINGCIRCUITS: + snmp->snmp_val = X25Stats.rxCallRequest-X25Stats.txClearRqst; + break; + + case X25STATTWOWAYCIRCUITS: + snmp->snmp_val = X25Stats.txCallRequest-X25Stats.rxClearRqst; + break; + + case X25STATRESTARTTIMEOUTS: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25STATCALLTIMEOUTS: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25STATRESETTIMEOUTS: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25STATCLEARTIMEOUTS: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25STATDATARXMTTIMEOUTS: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25STATINTERRUPTTIMEOUTS: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25STATRETRYCOUNTEXCEEDEDS: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25STATCLEARCOUNTEXCEEDEDS: /* FIXME */ + snmp->snmp_val = 0; + break; + + /********** X.25 Channel Table *********/ + case X25CHANNELINDEX: + break; + + case X25CHANNELLIC: + snmp->snmp_val = card->u.x.x25_conf.lo_svc; + break; + + case X25CHANNELHIC: + snmp->snmp_val = card->u.x.x25_conf.hi_svc; + break; + + case X25CHANNELLTC: + snmp->snmp_val = card->u.x.x25_conf.lo_svc; + break; + + case X25CHANNELHTC: + snmp->snmp_val = card->u.x.x25_conf.hi_svc; + break; + + case X25CHANNELLOC: + snmp->snmp_val = card->u.x.x25_conf.lo_svc; + break; + + case X25CHANNELHOC: + snmp->snmp_val = card->u.x.x25_conf.hi_svc; + break; + + /********** X.25 Per Circuits Information Table *********/ + case X25CIRCUITINDEX: + break; + + case X25CIRCUITCHANNEL: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25CIRCUITSTATUS: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25CIRCUITESTABLISHTIME: + snmp->snmp_val = chan->chan_establ_time; + break; + + case X25CIRCUITDIRECTION: + snmp->snmp_val = chan->chan_direct; + break; + + case X25CIRCUITINOCTETS: + snmp->snmp_val = chan->ifstats.rx_bytes; + break; + + case X25CIRCUITINPDUS: + snmp->snmp_val = chan->ifstats.rx_packets; + break; + + case X25CIRCUITINREMOTELYINITIATEDRESETS: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25CIRCUITINPROVIDERINITIATEDRESETS: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25CIRCUITININTERRUPTS: + snmp->snmp_val = X25Stats.rxInterrupt; + break; + + case X25CIRCUITOUTOCTETS: + snmp->snmp_val = chan->ifstats.tx_bytes; + break; + + case X25CIRCUITOUTPDUS: + snmp->snmp_val = chan->ifstats.tx_packets; + break; + + case X25CIRCUITOUTINTERRUPTS: + snmp->snmp_val = X25Stats.txInterrupt; + break; + + case X25CIRCUITDATARETRANSMISSIONTIMEOUTS: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25CIRCUITRESETTIMEOUTS: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25CIRCUITINTERRUPTTIMEOUTS: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25CIRCUITCALLPARAMID: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25CIRCUITCALLEDDTEADDRESS: /* FIXME */ + strcpy((void*)snmp->snmp_data, + (chan->chan_direct == SNMP_X25_INCOMING) ? chan->accept_src_addr : "N/A"); + break; + + case X25CIRCUITCALLINGDTEADDRESS: /* FIXME */ + strcpy((void*)snmp->snmp_data, + (chan->chan_direct == SNMP_X25_INCOMING) ? chan->accept_dest_addr : "N/A"); + break; + + case X25CIRCUITORIGINALLYCALLEDADDRESS: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25CIRCUITDESCR: /* FIXME */ + strcpy((void*)snmp->snmp_data, "N/A"); + break; + + + case X25CLEAREDCIRCUITENTRIESREQUESTED: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25CLEAREDCIRCUITENTRIESGRANTED: /* FIXME */ + snmp->snmp_val = 0; + break; + + /********** X.25 The Cleared Circuit Table *********/ + case X25CLEAREDCIRCUITINDEX: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25CLEAREDCIRCUITPLEINDEX: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25CLEAREDCIRCUITTIMEESTABLISHED: + snmp->snmp_val = chan->chan_establ_time; + break; + + case X25CLEAREDCIRCUITTIMECLEARED: + snmp->snmp_val = chan->chan_clear_time; + break; + + case X25CLEAREDCIRCUITCHANNEL: + snmp->snmp_val = chan->ch_idx; + break; + + case X25CLEAREDCIRCUITCLEARINGCAUSE: + snmp->snmp_val = chan->chan_clear_cause; + break; + + case X25CLEAREDCIRCUITDIAGNOSTICCODE: + snmp->snmp_val = chan->chan_clear_diagn; + break; + + case X25CLEAREDCIRCUITINPDUS: + snmp->snmp_val = chan->ifstats.rx_packets; + break; + + case X25CLEAREDCIRCUITOUTPDUS: + snmp->snmp_val = chan->ifstats.tx_packets; + break; + + case X25CLEAREDCIRCUITCALLEDADDRESS: + strcpy((void*)snmp->snmp_data, + (chan->cleared_called_addr[0] != '\0') ? + chan->cleared_called_addr : "N/A"); + break; + + case X25CLEAREDCIRCUITCALLINGADDRESS: + strcpy((void*)snmp->snmp_data, + (chan->cleared_calling_addr[0] != '\0') ? + chan->cleared_calling_addr : "N/A"); + break; + + case X25CLEAREDCIRCUITCLEARFACILITIES: + strcpy((void*)snmp->snmp_data, + (chan->cleared_facil[0] != '\0') ? chan->cleared_facil : "N/A"); + break; + + + + /********** X.25 The Call Parameter Table *********/ + case X25CALLPARMINDEX: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25CALLPARMSTATUS: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25CALLPARMREFCOUNT: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25CALLPARMINPACKETSIZE: + snmp->snmp_val = 0; // default size + break; + + case X25CALLPARMOUTPACKETSIZE: + snmp->snmp_val = 0; // default size + break; + + case X25CALLPARMINWINDOWSIZE: + snmp->snmp_val = (card->u.x.x25_conf.pkt_window != X25_PACKET_WINDOW) ? + card->u.x.x25_conf.pkt_window : 0; + break; + + case X25CALLPARMOUTWINDOWSIZE: + snmp->snmp_val = (card->u.x.x25_conf.pkt_window != X25_PACKET_WINDOW) ? + card->u.x.x25_conf.pkt_window : 0; + break; + + case X25CALLPARMACCEPTREVERSECHARGING: /* FIXME */ + snmp->snmp_val = SNMP_X25_ARC_DEFAULT; + break; + + case X25CALLPARMPROPOSEREVERSECHARGING: /* FIXME */ + snmp->snmp_val = SNMP_X25_PRC_DEFAULT; + break; + + case X25CALLPARMFASTSELECT: /* FIXME */ + snmp->snmp_val = SNMP_X25_FS_DEFAULT; + break; + + case X25CALLPARMINTHRUPUTCLASSIZE: /* FIXME */ + snmp->snmp_val = SNMP_X25_THRUCLASS_TCDEF; + break; + + case X25CALLPARMOUTTHRUPUTCLASSIZE: /* FIXME */ + snmp->snmp_val = SNMP_X25_THRUCLASS_TCDEF; + break; + + case X25CALLPARMCUG: /* FIXME */ + strcpy((void*)snmp->snmp_data, "N/A"); + break; + + case X25CALLPARMCUGOA: /* FIXME */ + strcpy((void*)snmp->snmp_data, "N/A"); + break; + + case X25CALLPARMBCUG: /* FIXME */ + strcpy((void*)snmp->snmp_data, "N/A"); + break; + + case X25CALLPARMNUI: /* FIXME */ + strcpy((void*)snmp->snmp_data, "N/A"); + break; + + case X25CALLPARMCHARGINGINFO: /* FIXME */ + snmp->snmp_val = SNMP_X25_CHARGINGINFO_DEF; + break; + + case X25CALLPARMRPOA: /* FIXME */ + strcpy((void*)snmp->snmp_data, "N/A"); + break; + + case X25CALLPARMTRNSTDLY: /* FIXME */ + snmp->snmp_val = 0; + break; + + case X25CALLPARMCALLINGEXT: /* FIXME */ + strcpy((void*)snmp->snmp_data, "N/A"); + break; + + case X25CALLPARMCALLEDEXT: /* FIXME */ + strcpy((void*)snmp->snmp_data, "N/A"); + break; + + case X25CALLPARMINMINTHUPUTCLS: /* FIXME */ + snmp->snmp_val = SNMP_X25_THRUCLASS_TCDEF; + break; + + case X25CALLPARMOUTMINTHUPUTCLS: /* FIXME */ + snmp->snmp_val = SNMP_X25_THRUCLASS_TCDEF; + break; + + case X25CALLPARMENDTRNSDLY: /* FIXME */ + strcpy((void*)snmp->snmp_data, "N/A"); + break; + + case X25CALLPARMPRIORITY: /* FIXME */ + strcpy((void*)snmp->snmp_data, "N/A"); + break; + + case X25CALLPARMPROTECTION: /* FIXME */ + strcpy((void*)snmp->snmp_data, "N/A"); + break; + + case X25CALLPARMEXPTDATA: /* FIXME */ + snmp->snmp_val = SNMP_X25_EXPTDATA_DEFULT; + break; + + case X25CALLPARMUSERDATA: + strcpy((void*)snmp->snmp_data, chan->accept_usr_data); + break; + + case X25CALLPARMCALLINGNETWORKFACILITIES: /* FIXME */ + strcpy((void*)snmp->snmp_data, "N/A"); + break; + + case X25CALLPARMCALLEDNETWORKFACILITIES: /* FIXME */ + strcpy((void*)snmp->snmp_data, "N/A"); + break; + + default: + return -EAFNOSUPPORT; + } + + return 0; + +} + +#define PROC_IF_X25_S_FRM "%-40s %-14s\n" +#define PROC_IF_X25_D_FRM "%-40s %-14d\n" +#define PROC_IF_X25_L_FRM "%-40s %-14ld\n" +#define PROC_IF_SEPARATE "====================================================\n" + +static int x25_set_if_info(struct file *file, + const char *buffer, + unsigned long count, + void *data) +{ + netdevice_t* dev = (void*)data; + x25_channel_t* chan = NULL; + sdla_t* card = NULL; + + if (dev == NULL || dev->priv == NULL) + return count; + chan = (x25_channel_t*)dev->priv; + if (chan->card == NULL) + return count; + card = chan->card; + + printk(KERN_INFO "%s: New interface config (%s)\n", + chan->name, buffer); + /* Parse string */ + + return count; +} + +static int baud_rate_check (int baud) +{ + switch (baud){ + + case 1024: + case 512: + case 256: + case 128: + case 64: + case 16: + return 0; + + default: + return -EINVAL; + } + + return -EINVAL; +} + + +static void release_svc_dev(sdla_t *card, netdevice_t *dev) +{ + x25_channel_t *chan = dev->priv; + clear_bit(0,(void *)&chan->common.rw_bind); +} + +static netdevice_t *find_free_svc_dev(sdla_t *card) +{ + struct wan_dev_le *devle; + netdevice_t *dev; + x25_channel_t *chan; + + WAN_LIST_FOREACH(devle, &card->wandev.dev_head, dev_link){ + dev = WAN_DEVLE2DEV(devle); + if (!dev || !wan_netif_priv(dev) || !(dev->flags&IFF_UP)){ + continue; + } + + chan = wan_netif_priv(dev); + if (chan->common.usedby == API && chan->common.svc){ + if (!test_and_set_bit(0,(void *)&chan->common.rw_bind)){ + + if (chan->common.state != WANSOCK_DISCONNECTED){ + clear_bit(0,(void *)&chan->common.rw_bind); + } + + return dev; + } + } + } + + return NULL; +} + + + +/*============================================================== + * bind_api_to_svc + * + * Description: + * The api socket layer uses this function to bind + * the SVC data socket to the x25_lcn link. + * + * All data received by the svc will be passed up + * to the socket via bounded sk_id. + * + * Used by: + * api socket layer. + * + */ + +static int bind_api_to_svc(sdla_t *card, void *sk_id) +{ + netdevice_t *dev; + x25_channel_t *chan; + + WAN_ASSERT2((sk_id==NULL),-ENODEV); + + dev=find_free_svc_dev(card); + if (!dev){ + DEBUG_EVENT("%s NO DEV\n",__FUNCTION__); + return -ENODEV; + } + + chan = dev->priv; + + sock_hold(sk_id); + chan->common.sk=sk_id; + set_bit(LCN_SK_ID,&chan->common.used); + + return dev->ifindex; +} + +static int x25_api_cmd_setup(x25_channel_t *chan, struct ifreq *ifr) +{ + x25api_t *x25api; + int err; + + memset(&chan->x25_api_cmd_hdr,0,sizeof(x25api_hdr_t)); + memset(chan->call_string,0,sizeof(chan->call_string)); + + if (!ifr){ + DEBUG_EVENT("%s: No ifr ptr!\n",__FUNCTION__); + return -EINVAL; + } + + x25api = (x25api_t*)ifr->ifr_data; + if (!x25api){ + DEBUG_EVENT("%s: No ifr->ifr_data ptr!\n",__FUNCTION__); + return -EINVAL; + } + + err = copy_from_user(&chan->x25_api_cmd_hdr,x25api,sizeof(x25api_hdr_t)); + if (err){ + return err; + } + + if (x25api->hdr.length > 0 && x25api->hdr.length <= X25_CALL_STR_SZ){ + err = copy_from_user(chan->call_string,x25api->data,x25api->hdr.length); + }else{ + printk(KERN_INFO "%s: Invalid Place Call string: %s!\n", + chan->common.dev->name, + x25api->hdr.length ? "Call string too big" : + "Call string size is zero"); + err = -EINVAL; + } + return err; +} + +static int x25_api_get_cmd_result(x25_channel_t *chan, struct ifreq *ifr) +{ + x25api_t *x25api; + int err=0; + + if (!ifr){ + DEBUG_EVENT("%s: No ifr ptr!\n",__FUNCTION__); + return -EINVAL; + } + + x25api = (x25api_t*)ifr->ifr_data; + + if (!x25api){ + DEBUG_EVENT("%s: No ifr->ifr_data ptr!\n",__FUNCTION__); + return -EINVAL; + } + + err=copy_to_user(x25api,&chan->x25_api_event,sizeof(x25api_t)); + + return err; +} + +static int x25_api_setup_cmd_hdr(x25_channel_t *chan, struct ifreq *ifr) +{ + x25api_t *x25api; + int err; + + memset(&chan->x25_api_cmd_hdr,0,sizeof(x25api_hdr_t)); + + if (ifr && ifr->ifr_data){ + x25api = (x25api_t*)ifr->ifr_data; + err=copy_from_user(&chan->x25_api_cmd_hdr, + x25api, + sizeof(x25api_hdr_t)); + if (err) + return err; + } + + return 0; +} + +static int x25_api_setup_call_string(x25_channel_t *chan, struct ifreq *ifr) +{ + x25api_t *x25api; + int err; + + memset(chan->call_string,0,sizeof(chan->call_string)); + + if (ifr && ifr->ifr_data){ + x25api = (x25api_t*)ifr->ifr_data; + if (x25api->hdr.length > 0 && x25api->hdr.length <= X25_CALL_STR_SZ){ + err = copy_from_user(chan->call_string, + x25api->data, + x25api->hdr.length); + if (err) + return err; + } + } + + return 0; +} + +static void x25_update_api_state(sdla_t *card,x25_channel_t *chan) +{ + int err=0; + + /* If the LCN state changes from Connected to Disconnected, and + * we are in the API mode, then notify the socket that the + * connection has been lost */ + + if (chan->common.usedby == API && chan->common.sk){ + + if (chan->common.state != WAN_CONNECTED && test_bit(0,&chan->api_state)){ + clear_bit(0,&chan->api_state); + protocol_disconnected (chan->common.sk); + wan_unbind_api_from_svc(chan,chan->common.sk); + return; + } + + + if (chan->common.state == WAN_CONNECTED && !test_bit(0,&chan->api_state)){ + + set_bit(0,&chan->api_state); + err=protocol_connected (chan->common.dev,chan->common.sk); + if (err == -EINVAL){ + int lcn=chan->common.lcn; + printk(KERN_INFO "%s:Major Error in Socket Above: CONN!!!\n", + chan->common.dev->name); + + wan_unbind_api_from_svc(chan,chan->common.sk); + x25_clear_call(card,lcn,0,0,0,NULL,0); + } + return; + } + + if (chan->common.state == WAN_DISCONNECTED){ + err = protocol_disconnected (chan->common.sk); + wan_unbind_api_from_svc(chan,chan->common.sk); + } + } + + if (chan->common.state != WAN_CONNECTED){ + clear_bit(0,&chan->api_state); + } +} + + +static int test_chan_command_busy(sdla_t *card,x25_channel_t *chan) +{ + + if (card->wandev.state != WAN_CONNECTED){ + return -ENOTCONN; + } + + if (atomic_read(&chan->common.command)){ + DEBUG_EVENT("%s: Chan Command busy %x\n", + card->devname, + atomic_read(&chan->common.command)); + return -EBUSY; + } + + return 0; +} + + +static int wait_for_cmd_rc(sdla_t *card, x25_channel_t *chan) +{ + chan->cmd_timeout=jiffies; + + while((jiffies-chan->cmd_timeout) < (card->u.x.x25_conf.cmd_retry_timeout*HZ)){ + if (!atomic_read(&chan->common.command)){ + return atomic_read(&chan->cmd_rc); + } + schedule(); + } + + DEBUG_EVENT("%s: Warning: Delayed Command %x Timed out !\n", + card->devname,atomic_read(&chan->common.command)); + + atomic_set(&chan->common.command,0); + return -EFAULT; +} + + +static int lapb_connect(sdla_t *card, x25_channel_t *chan ) +{ + int err; + netdevice_t *dev=chan->common.dev; + + err=connect(card); + if (err==0){ + wanpipe_set_state(card, WAN_CONNECTING); + set_chan_state(dev,WAN_CONNECTING); + + del_timer(&card->u.x.x25_timer); + card->u.x.x25_timer.expires=jiffies+HZ; + add_timer(&card->u.x.x25_timer); + + err=0; + }else{ + wanpipe_set_state(card, WAN_DISCONNECTED); + set_chan_state(dev,WAN_DISCONNECTED); + err=-ENETDOWN; + } + + return err; +} +/****** End *****************************************************************/ diff -Nur linux.org/drivers/net/wan/sdla_xilinx.c linux-2.6.17/drivers/net/wan/sdla_xilinx.c --- linux.org/drivers/net/wan/sdla_xilinx.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/drivers/net/wan/sdla_xilinx.c 2006-08-30 10:07:17.000000000 +0000 @@ -0,0 +1,7361 @@ +/***************************************************************************** +* sdla_xilinx.c WANPIPE(tm) S51XX Xilinx Hardware Support +* +* Authors: Nenad Corbic +* +* Copyright: (c) 2003-2004 Sangoma Technologies Inc. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version +* 2 of the License, or (at your option) any later version. +* ============================================================================ +* Jan 07, 2003 Nenad Corbic Initial version. +*****************************************************************************/ + +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) +# include +# include +# include +# include /* Socket Driver common area */ +# include +# include +# include +#else +# include +# include +# include +# include +# include +# include /* Socket Driver common area */ +# include +# include +# include +# include +# include +#endif + +/* #define XILINX_A010 1 */ + +/****** Defines & Macros ****************************************************/ + +/* Private critical flags */ +enum { + POLL_CRIT = PRIV_CRIT, + TX_BUSY, + RX_BUSY, + TASK_POLL, + CARD_DOWN +}; + +enum wp_device_down_states{ + LINK_DOWN, + DEVICE_DOWN +}; + +enum { + AFT_FE_CFG_ERR, + AFT_FE_CFG, + AFT_FE_INTR, + AFT_FE_POLL, + AFT_FE_TDM_RBS +}; + + +#define MAX_IP_ERRORS 10 + +#define PORT(x) (x == 0 ? "PRIMARY" : "SECONDARY" ) +#define MAX_TX_BUF 10 +#define MAX_RX_BUF 10 + +#undef DEB_XILINX + +#if 1 +# define TRUE_FIFO_SIZE 1 +#else +# undef TRUE_FIFO_SIZE +# define HARD_FIFO_CODE 0x01 +#endif + +#if defined(__LINUX__) +#define AFT_TDM_API_SUPPORT 1 +#else +#undef AFT_TDM_API_SUPPORT +#endif + +#define AFT_MAX_CHIP_SECURITY_CNT 100 + +#define AFT_MIN_FRMW_VER 24 + + + + +static int aft_rx_copyback=1000; + +/******Data Structures*****************************************************/ + +/* This structure is placed in the private data area of the device structure. + * The card structure used to occupy the private area but now the following + * structure will incorporate the card structure along with Protocol specific data + */ + +typedef struct private_area +{ + wanpipe_common_t common; + + wan_skb_queue_t wp_tx_free_list; + wan_skb_queue_t wp_tx_pending_list; + wan_skb_queue_t wp_tx_complete_list; + netskb_t *tx_dma_skb; + u8 tx_dma_cnt; + + wan_skb_queue_t wp_rx_free_list; + wan_skb_queue_t wp_rx_complete_list; + netskb_t *rx_dma_skb; + + u32 time_slot_map; + unsigned char num_of_time_slots; + long logic_ch_num; + + unsigned char hdlc_eng; + unsigned char dma_status; + unsigned char ignore_modem; + + struct net_device_stats if_stats; + + int tracing_enabled; /* For enabling Tracing */ + unsigned long router_start_time; + unsigned long trace_timeout; + + unsigned char route_removed; + unsigned long tick_counter; /* For 5s timeout counter */ + unsigned long router_up_time; + + unsigned char mc; /* Mulitcast support on/off */ + unsigned char udp_pkt_src; /* udp packet processing */ + unsigned short timer_int_enabled; + + unsigned char interface_down; + + /* Polling task queue. Each interface + * has its own task queue, which is used + * to defer events from the interrupt */ + wan_taskq_t poll_task; + wan_timer_info_t poll_delay_timer; + + u8 gateway; + u8 true_if_encoding; + + + /* Entry in proc fs per each interface */ + struct proc_dir_entry *dent; + + unsigned char udp_pkt_data[sizeof(wan_udp_pkt_t)+10]; + atomic_t udp_pkt_len; + + char if_name[WAN_IFNAME_SZ+1]; + + u8 idle_flag; + u16 max_idle_size; + u8 idle_start; + + u8 pkt_error; + u8 rx_fifo_err_cnt; + + int first_time_slot; + + netskb_t *tx_idle_skb; + u32 tx_dma_addr; + u32 tx_dma_len; + unsigned char rx_dma; + unsigned char pci_retry; + + unsigned char fifo_size_code; + unsigned char fifo_base_addr; + unsigned char fifo_size; + + int dma_mru; + int mru; + int mtu; + + void * prot_ch; + int prot_state; + + wan_trace_t trace_info; + + int tdmv_sync; + unsigned char lip_atm; + + unsigned long up; + unsigned char *tx_realign_buf; + + aft_op_stats_t opstats; + aft_comm_err_stats_t errstats; + + wan_xilinx_conf_if_t cfg; + + unsigned int channelized_cfg; + +#ifdef AFT_TDM_API_SUPPORT + wanpipe_tdm_api_dev_t wp_tdm_api_dev_idx[32]; +#endif + unsigned int tdmv_chan; + unsigned char tdm_api; + unsigned int tdmv_zaptel_cfg; + unsigned int tdmapi_timeslots; + + struct private_area *next; +}private_area_t; + +/* Route Status options */ +#define NO_ROUTE 0x00 +#define ADD_ROUTE 0x01 +#define ROUTE_ADDED 0x02 +#define REMOVE_ROUTE 0x03 + +#define WP_WAIT 0 +#define WP_NO_WAIT 1 + +/* Function interface between WANPIPE layer and kernel */ +extern wan_iface_t wan_iface; + +/* variable for keeping track of enabling/disabling FT1 monitor status */ +/* static int rCount; */ + +extern void disable_irq(unsigned int); +extern void enable_irq(unsigned int); + +/**SECTOIN************************************************** + * + * Function Prototypes + * + ***********************************************************/ + +int wp_xilinx_default_devcfg(sdla_t* card, wandev_conf_t* conf); +int wp_xilinx_default_ifcfg(sdla_t* card, wanif_conf_t* conf); + +/* WAN link driver entry points. These are called by the WAN router module. */ +static int update (wan_device_t* wandev); +static int new_if (wan_device_t* wandev, netdevice_t* dev, wanif_conf_t* conf); +static int del_if(wan_device_t *wandev, netdevice_t *dev); + +/* Network device interface */ +static int if_init (netdevice_t* dev); +static int wanpipe_xilinx_open (netdevice_t* dev); +static int wanpipe_xilinx_close (netdevice_t* dev); +static int wanpipe_xilinx_ioctl(netdevice_t *dev, struct ifreq *ifr, int cmd); +static struct net_device_stats* wanpipe_xilinx_ifstats (netdevice_t* dev); + +#if defined(__LINUX__) +static int wanpipe_xilinx_send (netskb_t* skb, netdevice_t* dev); +#else +static int wan_aft_output(netdevice_t*, netskb_t*, struct sockaddr*, + struct rtentry*); +#endif + +static void handle_front_end_state(void* card_id); +static void enable_timer(void* card_id); +static void wanpipe_xilinx_tx_timeout (netdevice_t* dev); + +/* Miscellaneous Functions */ +static void port_set_state (sdla_t *card, int); + +static void disable_comm (sdla_t *card); + +/* Interrupt handlers */ +static void wp_xilinx_isr (sdla_t* card); + +/* Bottom half handlers */ +#if defined(__LINUX__) +static void wp_bh (unsigned long); +#else +static void wp_bh(void *data, int pending); +#endif + +/* Miscellaneous functions */ +static int process_udp_mgmt_pkt(sdla_t* card, netdevice_t* dev, + private_area_t*, + int local_dev); + +static int xilinx_chip_configure(sdla_t *card); +static int xilinx_chip_unconfigure(sdla_t *card); +static int xilinx_dev_configure(sdla_t *card, private_area_t *chan); +static void xilinx_dev_unconfigure(sdla_t *card, private_area_t *chan); +static int xilinx_dma_rx(sdla_t *card, private_area_t *chan); +static void xilinx_dev_enable(sdla_t *card, private_area_t *chan); +static void xilinx_dev_close(sdla_t *card, private_area_t *chan); +static int xilinx_dma_tx (sdla_t *card, private_area_t *chan); +static void xilinx_dma_tx_complete (sdla_t *card, private_area_t *chan); +static void xilinx_dma_rx_complete (sdla_t *card, private_area_t *chan); +static void xilinx_dma_max_logic_ch(sdla_t *card); +static int xilinx_init_rx_dev_fifo(sdla_t *card, private_area_t *chan, + unsigned char); +static void xilinx_init_tx_dma_descr(sdla_t *card, private_area_t *chan); +static int xilinx_init_tx_dev_fifo(sdla_t *card, + private_area_t *chan, unsigned char); +static void xilinx_tx_post_complete (sdla_t *card, + private_area_t *chan, netskb_t *skb); +static void xilinx_rx_post_complete (sdla_t *card, private_area_t *chan, + netskb_t *skb, + netskb_t **new_skb, + unsigned char *pkt_error); + + +static char request_xilinx_logical_channel_num (sdla_t *card, + private_area_t *chan, long *free_ch); +static void free_xilinx_logical_channel_num (sdla_t *card, int logic_ch); + + +static unsigned char read_cpld(sdla_t *card, unsigned short cpld_off); +static unsigned char write_cpld(sdla_t *card, unsigned short cpld_off, + unsigned char cpld_data); + +static int aft_devel_ioctl(sdla_t *card,struct ifreq *ifr); +static int xilinx_write_bios(sdla_t *card,wan_cmd_api_t *api_cmd); +static int xilinx_write(sdla_t *card,wan_cmd_api_t *api_cmd); +static int xilinx_fe_write(sdla_t *card,wan_cmd_api_t *api_cmd); +static int xilinx_read(sdla_t *card,wan_cmd_api_t *api_cmd); +static int xilinx_fe_read(sdla_t *card,wan_cmd_api_t *api_cmd); + +static void front_end_interrupt(sdla_t *card, unsigned long reg, int lock); +static void enable_data_error_intr(sdla_t *card); +static void disable_data_error_intr(sdla_t *card, enum wp_device_down_states state); + +static void xilinx_tx_fifo_under_recover (sdla_t *card, private_area_t *chan); + +static int xilinx_write_ctrl_hdlc(sdla_t *card, u32 timeslot, u8 reg_off, u32 data); + +static int set_chan_state(sdla_t* card, netdevice_t* dev, int state); + +static int fifo_error_interrupt(sdla_t *card, u32 reg, u32 tx_err, u32 rx_err); +static int request_fifo_baddr_and_size(sdla_t *card, private_area_t *chan); +static int map_fifo_baddr_and_size(sdla_t *card, + unsigned char fifo_size, + unsigned char *addr); +static int free_fifo_baddr_and_size (sdla_t *card, private_area_t *chan); + +static int update_comms_stats(sdla_t* card); + +static void aft_red_led_ctrl(sdla_t *card, int mode); + +static int protocol_init (sdla_t*card,netdevice_t *dev, + private_area_t *chan, + wanif_conf_t* conf); + +static int protocol_stop (sdla_t *card, netdevice_t *dev); +static int protocol_start (sdla_t *card, netdevice_t *dev); +static int protocol_shutdown (sdla_t *card, netdevice_t *dev); +static void protocol_recv(sdla_t *card, private_area_t *chan, netskb_t *skb); + +static int aft_alloc_rx_dma_buff(sdla_t *card, private_area_t *chan, int num); +static int aft_init_requeue_free_skb(private_area_t *chan, netskb_t *skb); +#if 0 +static int aft_reinit_pending_rx_bufs(private_area_t *chan); +#endif +static int aft_core_ready(sdla_t *card); +static void aft_unmap_tx_dma(sdla_t *card, private_area_t *chan); + +static int channel_timeslot_sync_ctrl(sdla_t *card, private_area_t * chan, int enable); +static int rx_chan_timeslot_sync_ctrl(sdla_t *card,int start); +static void aft_report_rbsbits(void* pcard, int channel, unsigned char status); + +static int aft_realign_skb_pkt(private_area_t *chan, netskb_t *skb); +#if defined(__LINUX__) +static void aft_port_task (void * card_ptr); +#else +static void aft_port_task (void * card_ptr, int arg); +#endif +static void aft_fe_intr_ctrl(sdla_t *card, int status); +static void __aft_fe_intr_ctrl(sdla_t *card, int status); + +static int aft_dev_open(sdla_t *card, private_area_t *chan); +static void aft_dev_close(sdla_t *card, private_area_t *chan); + +static int aft_dma_rx_tdmv(sdla_t *card, private_area_t *chan, netskb_t *skb); + + +/* TE1 Control registers */ +static WRITE_FRONT_END_REG_T write_front_end_reg; +static READ_FRONT_END_REG_T read_front_end_reg; + +/* Procfs functions */ +static int wan_aft_get_info(void* pcard, struct seq_file* m, int* stop_cnt); + +static int aft_tdmv_init(sdla_t *card, wandev_conf_t *conf); +static int aft_tdmv_free(sdla_t *card); +static int aft_tdmv_if_init(sdla_t *card, private_area_t *chan, wanif_conf_t *conf); +static int aft_tdmv_if_free(sdla_t *card, private_area_t *chan); + +#ifdef AFT_TDM_API_SUPPORT +static int aft_read_rbs_bits(void *chan_ptr, u32 ch, u8 *rbs_bits); +static int aft_write_rbs_bits(void *chan_ptr, u32 ch, u8 rbs_bits); +static int aft_write_hdlc_frame(void *chan_ptr, netskb_t *skb); +static int aft_tdm_api_rx_tx_channelized(sdla_t *card, private_area_t *chan, netskb_t *skb); +static int aft_tdm_api_update_state_channelized(sdla_t *card, private_area_t *chan, int state); +static int aft_tdm_api_free_channelized(sdla_t *card, private_area_t *chan); +#endif + +static void xilinx_delay(int sec) +{ +#if 0 + unsigned long timeout=SYSTEM_TICKS; + while ((SYSTEM_TICKS-timeout)<(sec*HZ)){ + schedule(); + } +#endif +} + +/**SECTION********************************************************* + * + * Public Functions + * + ******************************************************************/ + +int wp_xilinx_default_devcfg(sdla_t* card, wandev_conf_t* conf) +{ + conf->config_id = WANCONFIG_AFT; + conf->u.aft.dma_per_ch = 10; + conf->u.aft.mru = 1500; + return 0; +} + +int wp_xilinx_default_ifcfg(sdla_t* card, wanif_conf_t* conf) +{ + memcpy(conf->usedby, "WANPIPE", 7); + conf->if_down = 0; + conf->ignore_dcd = WANOPT_NO; + conf->ignore_cts = WANOPT_NO; + conf->hdlc_streaming = WANOPT_YES; + conf->mc = 0; + conf->gateway = 0; + conf->active_ch = ENABLE_ALL_CHANNELS; + + return 0; +} + + +/*============================================================================ + * wp_xilinx_init - Cisco HDLC protocol initialization routine. + * + * @card: Wanpipe card pointer + * @conf: User hardware/firmware/general protocol configuration + * pointer. + * + * This routine is called by the main WANPIPE module + * during setup: ROUTER_SETUP ioctl(). + * + * At this point adapter is completely initialized + * and firmware is running. + * o read firmware version (to make sure it's alive) + * o configure adapter + * o initialize protocol-specific fields of the adapter data space. + * + * Return: 0 o.k. + * < 0 failure. + */ + +int wp_xilinx_init (sdla_t* card, wandev_conf_t* conf) +{ +#if !defined(CONFIG_PRODUCT_WANPIPE_GENERIC) + int err; +#endif + + /* Verify configuration ID */ + wan_clear_bit(CARD_DOWN,&card->wandev.critical); + if (card->wandev.config_id != WANCONFIG_AFT) { + DEBUG_EVENT( "%s: invalid configuration ID %u!\n", + card->devname, card->wandev.config_id); + return -EINVAL; + } + + if (conf == NULL){ + DEBUG_EVENT("%s: Bad configuration structre!\n", + card->devname); + return -EINVAL; + } + +#if defined(WAN_DEBUG_MEM) + DEBUG_EVENT("%s: Total Mem %d\n", + __FUNCTION__,wan_atomic_read(&wan_debug_mem)); +#endif + + /* Obtain hardware configuration parameters */ + card->wandev.clocking = conf->clocking; + card->wandev.ignore_front_end_status = conf->ignore_front_end_status; + card->wandev.ttl = conf->ttl; + card->wandev.interface = conf->interface; + card->wandev.comm_port = conf->comm_port; + card->wandev.udp_port = conf->udp_port; + card->wandev.new_if_cnt = 0; + wan_atomic_set(&card->wandev.if_cnt,0); + card->u.aft.chip_security_cnt=0; + + card->hw_iface.getcfg(card->hw, SDLA_COREREV, &card->u.aft.firm_ver); + if (card->u.aft.firm_ver < AFT_MIN_FRMW_VER){ + DEBUG_EVENT( "%s: Invalid/Obselete AFT A101/2 firmware ver %i (not >= %d)!\n", + card->devname, card->u.aft.firm_ver,AFT_MIN_FRMW_VER); + DEBUG_EVENT( "%s Refer to /usr/share/doc/wanpipe/README.aft_firm_update\n", + card->devname); + DEBUG_EVENT( "%s: Please contact Sangoma Technologies for more info.\n", + card->devname); + return -EINVAL; + } + + memcpy(&card->u.aft.cfg,&conf->u.aft,sizeof(wan_xilinx_conf_t)); + + card->u.aft.cfg.dma_per_ch = 10; + if (conf->u.aft.dma_per_ch){ + card->u.aft.cfg.dma_per_ch=conf->u.aft.dma_per_ch; + if (card->u.aft.cfg.dma_per_ch > MAX_DMA_PER_CH || + card->u.aft.cfg.dma_per_ch < MIN_DMA_PER_CH){ + DEBUG_EVENT("%s: Error invalid DMA Per Ch %d (Min=%d Max=%d)\n", + card->devname,card->u.aft.cfg.dma_per_ch, + MIN_DMA_PER_CH,MAX_DMA_PER_CH); + return -EINVAL; + } + } + + /* TE1 Make special hardware initialization for T1/E1 board */ + if (IS_TE1_MEDIA(&conf->fe_cfg)){ + + if (conf->fe_cfg.cfg.te_cfg.active_ch == 0){ + conf->fe_cfg.cfg.te_cfg.active_ch = -1; + } + + memcpy(&card->fe.fe_cfg, &conf->fe_cfg, sizeof(sdla_fe_cfg_t)); + sdla_te_iface_init(&card->wandev.fe_iface); + card->fe.name = card->devname; + card->fe.card = card; + card->fe.write_fe_reg = write_front_end_reg; + card->fe.read_fe_reg = read_front_end_reg; + + card->wandev.te_report_rbsbits = aft_report_rbsbits; + card->wandev.fe_enable_timer = enable_timer; + card->wandev.te_link_state = handle_front_end_state; + + if (card->fe.fe_cfg.cfg.te_cfg.te_clock == WAN_NORMAL_CLK){ + /* If using normal clocking disable + * reference clock configuration */ + card->fe.fe_cfg.cfg.te_cfg.te_ref_clock = WAN_TE1_REFCLK_OSC; + } + + conf->interface = + IS_T1_CARD(card) ? WANOPT_V35 : WANOPT_RS232; + + if (card->wandev.comm_port == WANOPT_PRI){ + conf->clocking = WANOPT_EXTERNAL; + } + + }else{ + DEBUG_EVENT("%s: Error: Unknown Front end cfg 0x%X (T1/E1)\n", + card->devname,conf->fe_cfg.media); + return -EINVAL; + } + + if (card->wandev.ignore_front_end_status == WANOPT_NO){ + DEBUG_EVENT( + "%s: Enabling front end link monitor\n", + card->devname); + }else{ + DEBUG_EVENT( + "%s: Disabling front end link monitor\n", + card->devname); + } + + /* WARNING: After this point the init function + * must return with 0. The following bind + * functions will cause problems if structures + * below are not initialized */ + + card->wandev.update = &update; + card->wandev.new_if = &new_if; + card->wandev.del_if = &del_if; + + card->disable_comm = NULL; + +#ifdef WANPIPE_ENABLE_PROC_FILE_HOOKS + /* Proc fs functions hooks */ + card->wandev.get_config_info = &get_config_info; + card->wandev.get_status_info = &get_status_info; + card->wandev.get_dev_config_info= &get_dev_config_info; + card->wandev.get_if_info = &get_if_info; + card->wandev.set_dev_config = &set_dev_config; + card->wandev.set_if_info = &set_if_info; +#endif + card->wandev.get_info = &wan_aft_get_info; + + /* Setup Port Bps */ + if(card->wandev.clocking) { + card->wandev.bps = conf->bps; + }else{ + card->wandev.bps = 0; + } + +#ifdef CONFIG_PRODUCT_WANPIPE_TDM_VOICE + card->wandev.mtu = conf->mtu; + card->wan_tdmv.sc = NULL; +#else + + card->wandev.mtu=conf->mtu; + if (card->wandev.mtu > MAX_WP_PRI_MTU || + card->wandev.mtu < MIN_WP_PRI_MTU){ + DEBUG_EVENT("%s: Error Invalid Global MTU %d (Min=%d, Max=%d)\n", + card->devname,card->wandev.mtu, + MIN_WP_PRI_MTU,MAX_WP_PRI_MTU); + + return -EINVAL; + } +#endif + + card->u.aft.cfg.mru=conf->u.aft.mru; + if (!card->u.aft.cfg.mru){ + card->u.aft.cfg.mru = card->wandev.mtu; + } + + if (card->u.aft.cfg.mru > MAX_WP_PRI_MTU || + card->u.aft.cfg.mru < MIN_WP_PRI_MTU){ + DEBUG_EVENT("%s: Error Invalid Global MRU %d (Min=%d, Max=%d)\n", + card->devname,card->u.aft.cfg.mru, + MIN_WP_PRI_MTU,MAX_WP_PRI_MTU); + + return -EINVAL; + } + + write_cpld(card,LED_CONTROL_REG,0x0E); + + + card->hw_iface.getcfg(card->hw, SDLA_BASEADDR, &card->u.aft.bar); + + WAN_TASKQ_INIT((&card->u.aft.port_task),0,aft_port_task,card); + + xilinx_delay(1); +#if !defined(CONFIG_PRODUCT_WANPIPE_GENERIC) + err=xilinx_chip_configure(card); + if (err){ + xilinx_chip_unconfigure(card); + return err; + } + card->isr = &wp_xilinx_isr; +#endif + + xilinx_delay(1); + + /* Set protocol link state to disconnected, + * After seting the state to DISCONNECTED this + * function must return 0 i.e. success */ + port_set_state(card,WAN_CONNECTING); + + DEBUG_EVENT("%s: Configuring Device :%s FrmVr=%02X\n", + card->devname,card->devname,card->u.aft.firm_ver); + DEBUG_EVENT("%s: Global MTU = %d\n", + card->devname, + card->wandev.mtu); + DEBUG_EVENT("%s: Global MRU = %d\n", + card->devname, + card->u.aft.cfg.mru); + DEBUG_EVENT("%s: RBS Signal = %s\n", + card->devname, + card->u.aft.cfg.rbs?"On":"Off"); + DEBUG_EVENT("%s: FE Ref Clock = %s\n", + card->devname, + WAN_TE1_REFCLK(&card->fe) == WAN_TE1_REFCLK_OSC?"Osc":"Line"); + + + DEBUG_EVENT("\n"); + + err=aft_tdmv_init(card,conf); + if (err){ + disable_comm(card); + return err; + } + + card->disable_comm = &disable_comm; + + return 0; +} + + + + +/**SECTION************************************************************** + * + * WANPIPE Device Driver Entry Points + * + * *********************************************************************/ + + + +/*============================================================================ + * update - Update wanpipe device status & statistics + * + * @wandev: Wanpipe device pointer + * + * This procedure is called when updating the PROC file system. + * It returns various communications statistics. + * + * cat /proc/net/wanrouter/wanpipe# (where #=1,2,3...) + * + * These statistics are accumulated from 3 + * different locations: + * 1) The 'if_stats' recorded for the device. + * 2) Communication error statistics on the adapter. + * 3) Operational statistics on the adapter. + * + * The board level statistics are read during a timer interrupt. + * Note that we read the error and operational statistics + * during consecitive timer ticks so as to minimize the time + * that we are inside the interrupt handler. + * + */ +static int update (wan_device_t* wandev) +{ + sdla_t *card = wandev->private; + netdevice_t *dev; + volatile private_area_t *chan; + wan_smp_flag_t smp_flags; + + /* sanity checks */ + if((wandev == NULL) || (wandev->private == NULL)) + return -EFAULT; + + if(wandev->state == WAN_UNCONFIGURED) + return -ENODEV; + + if(wan_test_bit(PERI_CRIT, (void*)&card->wandev.critical)) + return -EAGAIN; + + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + if (!dev || !wan_netif_priv(dev)) + return -ENODEV; + + chan=wan_netif_priv(dev); + + if(card->update_comms_stats){ + return -EAGAIN; + } + +#if 0 + { + private_area_t* chan; + DEBUG_EVENT("%s: Starting up Interfaces\n",card->devname); + for (dev=card->wandev.dev;dev;dev=wan_next_dev(dev)){ + chan=dev->priv; + if (WAN_NETIF_QUEUE_STOPPED(dev)){ + DEBUG_EVENT("%s: Waking up device! Q=%d\n", + wan_netif_name(dev), + wan_skb_queue_len(&chan->wp_tx_pending_list)); + WAN_NETIF_START_QUEUE(dev); /*start_net_queue(dev);*/ + } + } + } +#endif + + wan_spin_lock_irq(&card->wandev.lock, &smp_flags); + update_comms_stats(card); + wan_spin_unlock_irq(&card->wandev.lock, &smp_flags); + + + return 0; +} + +#if defined(__LINUX__) + +static int aft_event_ctrl(void *chan_ptr, wan_event_ctrl_t *event_ctrl) +{ + /* There are no events for A101/2 cards */ + return -EINVAL; +} + +static int aft_tdm_api_init(sdla_t *card, private_area_t *chan, int logic_ch, wanif_conf_t *conf) +{ + +#ifdef AFT_TDM_API_SUPPORT + int err=0; + wanpipe_tdm_api_dev_t *wp_tdm_api_dev = &chan->wp_tdm_api_dev_idx[logic_ch]; + + if (chan->common.usedby != TDM_VOICE_API && + chan->common.usedby != TDM_VOICE_DCHAN) { + return 0; + } + + if (chan->tdmv_zaptel_cfg) { + return 0; + } + + /* Initilaize TDM API Parameters */ + wp_tdm_api_dev->chan = chan; + wp_tdm_api_dev->card = card; + wan_spin_lock_init(&wp_tdm_api_dev->lock); + strncpy(wp_tdm_api_dev->name,chan->if_name,WAN_IFNAME_SZ); + + if (conf->hdlc_streaming) { + wp_tdm_api_dev->hdlc_framing=1; + } + + wp_tdm_api_dev->event_ctrl = aft_event_ctrl; + wp_tdm_api_dev->read_rbs_bits = aft_read_rbs_bits; + wp_tdm_api_dev->write_rbs_bits = aft_write_rbs_bits; + wp_tdm_api_dev->write_hdlc_frame = aft_write_hdlc_frame; + + wp_tdm_api_dev->cfg.rx_disable = 0; + wp_tdm_api_dev->cfg.tx_disable = 0; + + if (IS_T1_CARD(card)) { + wp_tdm_api_dev->cfg.hw_tdm_coding=WP_MULAW; + }else{ + wp_tdm_api_dev->cfg.hw_tdm_coding=WP_ALAW; + } + + wp_tdm_api_dev->cfg.idle_flag = conf->u.aft.idle_flag; + wp_tdm_api_dev->cfg.rbs_tx_bits = conf->u.aft.rbs_cas_idle; + + wp_tdm_api_dev->tdm_span = card->u.aft.cfg.tdmv_span_no; + wp_tdm_api_dev->tdm_chan = logic_ch+1; + + if (IS_T1_CARD(card)){ + /* Convert active_ch bit map to user */ + wp_tdm_api_dev->active_ch = conf->active_ch << 1; + }else{ + wp_tdm_api_dev->active_ch = conf->active_ch; + } + + err=wanpipe_tdm_api_reg(wp_tdm_api_dev); + if (err){ + return err; + } + + wan_set_bit(0,&wp_tdm_api_dev->init); + return err; +#else + DEBUG_EVENT("%s: TDM API support not compiled in\n", + card->devname); + return -EINVAL; +#endif +} + +static int aft_tdm_api_free(sdla_t *card, private_area_t *chan, int logic_ch) +{ +#ifdef AFT_TDM_API_SUPPORT + wanpipe_tdm_api_dev_t *wp_tdm_api_dev = &chan->wp_tdm_api_dev_idx[logic_ch]; + int err=0; + + if (wan_test_bit(0,&wp_tdm_api_dev->init)){ + wan_clear_bit(0,&wp_tdm_api_dev->init); + err=wanpipe_tdm_api_unreg(wp_tdm_api_dev); + if (err){ + wan_set_bit(0,&wp_tdm_api_dev->init); + return err; + } + + } +#endif + return 0; +} + + +static int aft_tdm_api_init_channelized(sdla_t *card, private_area_t *chan, wanif_conf_t *conf) +{ +#ifdef AFT_TDM_API_SUPPORT + int i; + int err=-EINVAL; + u32 active_ch=conf->active_ch; + + if (IS_E1_CARD(card)){ + active_ch=active_ch>>1; + } + + chan->tdmapi_timeslots=active_ch; + + for (i=0;iu.aft.num_of_time_slots;i++) { + if (wan_test_bit(i,&chan->tdmapi_timeslots)){ + err=aft_tdm_api_init(card,chan,i,conf); + if (err){ + break; + } + } + } + return err; +#else + DEBUG_EVENT("%s: TDM API support not compiled in\n", + card->devname); + return -EINVAL; +#endif +} + +#ifdef AFT_TDM_API_SUPPORT +static int aft_tdm_api_free_channelized(sdla_t *card, private_area_t *chan) +{ + int i; + int err=0; + for (i=0;iu.aft.num_of_time_slots;i++) { + if (wan_test_bit(i,&chan->tdmapi_timeslots)){ + err=aft_tdm_api_free(card,chan,i); + if (err){ + return err; + } + } + } + return 0; +} +#endif + +#endif + +/*============================================================================ + * new_if - Create new logical channel. + * + * &wandev: Wanpipe device pointer + * &dev: Network device pointer + * &conf: User configuration options pointer + * + * This routine is called by the ROUTER_IFNEW ioctl, + * in wanmain.c. The ioctl passes us the user configuration + * options which we use to configure the driver and + * firmware. + * + * This functions main purpose is to allocate the + * private structure for protocol and bind it + * to dev->priv pointer. + * + * Also the dev->init pointer should also be initialized + * to the if_init() function. + * + * Any allocation necessary for the private strucutre + * should be done here, as well as proc/ file initializetion + * for the network interface. + * + * o parse media- and hardware-specific configuration + * o make sure that a new channel can be created + * o allocate resources, if necessary + * o prepare network device structure for registaration. + * o add network interface to the /proc/net/wanrouter + * + * The opposite of this function is del_if() + * + * Return: 0 o.k. + * < 0 failure (channel will not be created) + */ +static int new_if_private (wan_device_t* wandev, netdevice_t* dev, wanif_conf_t* conf, int channelized) +{ + sdla_t* card = wandev->private; + private_area_t* chan; + int err = 0; + + DEBUG_EVENT( "%s: Configuring Interface: %s\n", + card->devname, wan_netif_name(dev)); + + if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)){ + DEBUG_EVENT( "%s: Invalid interface name!\n", + card->devname); + return -EINVAL; + } + + /* allocate and initialize private data */ + chan = wan_malloc(sizeof(private_area_t)); + if(chan == NULL){ + WAN_MEM_ASSERT(card->devname); + return -ENOMEM; + } + memset(chan, 0, sizeof(private_area_t)); + + chan->first_time_slot=-1; + + strncpy(chan->if_name, wan_netif_name(dev), WAN_IFNAME_SZ); + memcpy(&chan->cfg,&conf->u.aft,sizeof(chan->cfg)); + + if (channelized){ + chan->channelized_cfg=1; + if (wan_netif_priv(dev)){ +#if 1 + private_area_t *cptr; + for (cptr=wan_netif_priv(dev);cptr->next!=NULL;cptr=cptr->next); + cptr->next=chan; + chan->next=NULL; +#else + chan->next = wan_netif_priv(dev); + wan_netif_set_priv(dev, chan); +#endif + }else{ + wan_netif_set_priv(dev, chan); + } + }else{ + chan->channelized_cfg=0; + wan_netif_set_priv(dev, chan); + } + + + chan->common.card = card; + chan->true_if_encoding=conf->true_if_encoding; + + WAN_IFQ_INIT(&chan->wp_tx_free_list, 0); + WAN_IFQ_INIT(&chan->wp_tx_pending_list,0); + WAN_IFQ_INIT(&chan->wp_tx_complete_list,0); + + WAN_IFQ_INIT(&chan->wp_rx_free_list,0); + WAN_IFQ_INIT(&chan->wp_rx_complete_list,0); + + wan_trace_info_init(&chan->trace_info,MAX_TRACE_QUEUE); + + /* Initialize the socket binding information + * These hooks are used by the API sockets to + * bind into the network interface */ + + WAN_TASKLET_INIT((&chan->common.bh_task), 0, wp_bh, chan); + chan->common.dev = dev; + chan->tracing_enabled = 0; + chan->route_removed = 0; + + + + /* Setup interface as: + * WANPIPE = IP over Protocol (Firmware) + * API = Raw Socket access to Protocol (Firmware) + * BRIDGE = Ethernet over Protocol, no ip info + * BRIDGE_NODE = Ethernet over Protocol, with ip info + */ + + chan->mtu = card->wandev.mtu; + if (conf->u.aft.mtu){ + chan->mtu=conf->u.aft.mtu; + } + + if (chan->mtu > MAX_WP_PRI_MTU || + chan->mtu < MIN_WP_PRI_MTU){ + DEBUG_EVENT("%s: Error Invalid %s MTU %d (Min=%d, Max=%d)\n", + card->devname,chan->if_name,chan->mtu, + MIN_WP_PRI_MTU,MAX_WP_PRI_MTU); + err= -EINVAL; + goto new_if_error; + } + + chan->mru = card->u.aft.cfg.mru; + if (conf->u.aft.mru){ + chan->mru = conf->u.aft.mru; + } + + if (chan->mru > MAX_WP_PRI_MTU || + chan->mru < MIN_WP_PRI_MTU){ + DEBUG_EVENT("%s: Error Invalid %s MRU %d (Min=%d, Max=%d)\n", + card->devname,chan->if_name,chan->mru, + MIN_WP_PRI_MTU,MAX_WP_PRI_MTU); + + err= -EINVAL; + goto new_if_error; + } + + DEBUG_EVENT("%s: UsedBy :%s\n", + card->devname, + conf->usedby); + + + if(strcmp(conf->usedby, "WANPIPE") == 0) { + + chan->common.usedby = WANPIPE; + + /* Option to bring down the interface when + * the link goes down */ + if (conf->if_down){ + wan_set_bit(DYN_OPT_ON,&chan->interface_down); + DEBUG_EVENT( + "%s:%s: Dynamic interface configuration enabled\n", + card->devname,chan->if_name); + } + + if (conf->protocol != WANOPT_NO){ + wan_netif_set_priv(dev, chan); + if ((err=protocol_init(card,dev,chan,conf)) != 0){ + wan_netif_set_priv(dev, NULL); + goto new_if_error; + } + + if (conf->ignore_dcd == WANOPT_YES || conf->ignore_cts == WANOPT_YES){ + DEBUG_EVENT("%s: Ignore modem changes DCD/CTS\n", + card->devname); + chan->ignore_modem=1; + }else{ + DEBUG_EVENT("%s: Restart protocol on modem changes DCD/CTS\n", + card->devname); + } + DEBUG_EVENT("\n"); + } + +#if defined(__LINUX__) + + }else if( strcmp(conf->usedby, "API") == 0) { + chan->common.usedby = API; + wan_reg_api(chan, dev, card->devname); +#endif + +#if defined(__LINUX__) + }else if (strcmp(conf->usedby, "BRIDGE") == 0) { + chan->common.usedby = BRIDGE; +#endif + +#if defined(__LINUX__) + }else if (strcmp(conf->usedby, "BRIDGE_N") == 0) { + chan->common.usedby = BRIDGE_NODE; +#endif + +#if defined(__LINUX__) + }else if (strcmp(conf->usedby, "TDM_VOICE_DCHAN") == 0) { + +# ifdef CONFIG_PRODUCT_WANPIPE_TDM_VOICE +# ifdef CONFIG_PRODUCT_WANPIPE_TDM_VOICE_DCHAN + int dchan=card->u.aft.cfg.tdmv_dchan; + + /* DCHAN must be decremented for both + * T1 and E1, since from tdmv driver's + * perspective all timeslots start from ZERO*/ + dchan--; + chan->tdmv_chan=dchan; + + chan->common.usedby = TDM_VOICE_DCHAN; + conf->hdlc_streaming=1; + chan->mru=chan->mtu=1500; + chan->tdmv_zaptel_cfg=1; + card->u.aft.tdmv_zaptel_cfg=1; +# else + DEBUG_EVENT("%s: Error: TDMV_DCHAN Option not compiled into the driver!\n", + card->devname); + err=-EINVAL; + goto new_if_error; +# endif +# else + DEBUG_EVENT("\n"); + DEBUG_EVENT("%s:%s: Error: TDM VOICE/DCHAN prot not compiled\n", + card->devname,chan->if_name); + DEBUG_EVENT("%s:%s: during installation process!\n", + card->devname,chan->if_name); + err=-EINVAL; + goto new_if_error; +# endif +#endif + + }else if (strcmp(conf->usedby, "TDM_VOICE") == 0) { + +#ifdef CONFIG_PRODUCT_WANPIPE_TDM_VOICE + chan->common.usedby = TDM_VOICE; + chan->tdmv_zaptel_cfg=1; + card->u.aft.tdmv_zaptel_cfg=1; +#else + DEBUG_EVENT("\n"); + DEBUG_EVENT("%s:%s: Error: TDM VOICE prot not compiled\n", + card->devname,chan->if_name); + DEBUG_EVENT("%s:%s: during installation process!\n", + card->devname,chan->if_name); + err=-EINVAL; + goto new_if_error; +#endif + +#ifdef AFT_TDM_API_SUPPORT + }else if (strcmp(conf->usedby, "TDM_VOICE_API") == 0) { + + int dchan=card->u.aft.cfg.tdmv_dchan; + + /* DCHAN must be decremented for both + * T1 and E1, since from tdmv driver's + * perspective all timeslots start from ZERO*/ + dchan--; + chan->tdmv_chan=dchan; + + chan->common.usedby = TDM_VOICE_API; + chan->cfg.data_mux=1; + conf->hdlc_streaming=0; + chan->tdmv_zaptel_cfg=0; + + err=aft_tdm_api_init_channelized(card,chan,conf); + if (err){ + goto new_if_error; + } + +#endif + +#ifdef AFT_TDM_API_SUPPORT + }else if (strcmp(conf->usedby, "TDM_VOICE_DCHAN_API") == 0) { + int dchan=card->u.aft.cfg.tdmv_dchan; + + /* DCHAN must be decremented for both + * T1 and E1, since from tdmv driver's + * perspective all timeslots start from ZERO*/ + dchan--; + chan->tdmv_chan=dchan; + + chan->common.usedby = TDM_VOICE_DCHAN; + conf->hdlc_streaming=1; + chan->mru=chan->mtu=1500; + chan->tdmv_zaptel_cfg=0; + + err=aft_tdm_api_init_channelized(card,chan,conf); + if (err){ + goto new_if_error; + } +#endif + }else if (strcmp(conf->usedby, "STACK") == 0) { + chan->common.usedby = STACK; + + }else{ + DEBUG_EVENT( "%s:%s: Error: Invalid operation mode [%s]\n", + card->devname,chan->if_name, conf->usedby); + err=-EINVAL; + goto new_if_error; + } + + + chan->time_slot_map=conf->active_ch; + + err=aft_tdmv_if_init(card,chan,conf); + if (err){ + err=-EINVAL; + goto new_if_error; + } + + + DEBUG_EVENT("%s: MRU :%d\n", + card->devname, + chan->mru); + + DEBUG_EVENT("%s: MTU :%d\n", + card->devname, + chan->mtu); + + + xilinx_delay(1); + chan->hdlc_eng = conf->hdlc_streaming; + + DEBUG_EVENT("%s: HDLC Eng :%s\n", + card->devname, + chan->hdlc_eng?"On":"Off (Transparent)"); + + if (!chan->hdlc_eng){ + + if (!wan_test_bit(0,&card->u.aft.tdmv_sync)){ + DEBUG_EVENT("%s: Slot Sync :Enabled\n", + card->devname); + wan_set_bit(0,&card->u.aft.tdmv_sync); + wan_set_bit(0,&chan->tdmv_sync); + }else{ + DEBUG_EVENT("%s: Slot Sync :Disabled\n", + card->devname); + wan_clear_bit(0,&chan->tdmv_sync); + } + + if(conf->protocol == WANCONFIG_LIP_ATM){ + /* if ATM NO sync needed!! */ + DEBUG_EVENT("%s: Disabling Time Slot Sync for ATM.\n", chan->if_name); + card->u.aft.tdmv_sync = 0; + chan->tdmv_sync = 0; + } + + if (chan->mtu&0x03){ + DEBUG_EVENT("%s:%s: Error, Transparent MTU must be word aligned!\n", + card->devname,chan->if_name); + err = -EINVAL; + goto new_if_error; + } + } + + DEBUG_EVENT("%s: Timeslot Map :0x%08X\n", + card->devname, + chan->time_slot_map); + +#ifndef CONFIG_PRODUCT_WANPIPE_GENERIC + err=xilinx_dev_configure(card,chan); + if (err){ + goto new_if_error; + } + + /*Set the actual logic ch number of this chan + *as the dchan. Due to HDLC security issue, the + *HDLC channels are mapped on first TWO logic channels */ + if (chan->common.usedby == TDM_VOICE_DCHAN){ + card->u.aft.cfg.tdmv_dchan=chan->logic_ch_num+1; + } + + xilinx_delay(1); +#endif + + + chan->dma_mru = xilinx_valid_mtu(chan->mru+100); + if (!chan->dma_mru){ + DEBUG_EVENT("%s:%s: Error invalid MTU %d MRU %d\n", + card->devname, + chan->if_name, + chan->dma_mru,card->u.aft.cfg.mru); + err= -EINVAL; + goto new_if_error; + } + + + if (!chan->hdlc_eng){ + unsigned char *buf; + + chan->max_idle_size=chan->mru; + chan->idle_flag = conf->u.aft.idle_flag; + + DEBUG_EVENT("%s: Idle Flag :0x%02X\n", + card->devname, + chan->idle_flag); + DEBUG_EVENT("%s: Idle Buf Len :%d\n", + card->devname, + chan->max_idle_size); + + DEBUG_EVENT("%s: Data Mux :%s\n", + card->devname, + chan->cfg.data_mux?"On":"Off"); + +#ifdef CONFIG_PRODUCT_WANPIPE_TDM_VOICE + if (chan->common.usedby == TDM_VOICE){ + chan->idle_flag = WAN_TDMV_IDLE_FLAG; + } +#endif + + chan->tx_idle_skb = wan_skb_alloc(chan->dma_mru); + if (!chan->tx_idle_skb){ + err=-ENOMEM; + goto new_if_error; + } + + + if(conf->protocol != WANCONFIG_LIP_ATM){ + buf=wan_skb_put(chan->tx_idle_skb,chan->dma_mru); + memset(buf,chan->idle_flag,chan->dma_mru); + wan_skb_trim(chan->tx_idle_skb,0); + wan_skb_put(chan->tx_idle_skb,chan->max_idle_size); + }else{ + buf=wan_skb_put(chan->tx_idle_skb,chan->max_idle_size); + chan->lip_atm = 1; + /* if running below LIP ATM, transmit idle cells */ + if(init_atm_idle_buffer((unsigned char*)buf, + wan_skb_len(chan->tx_idle_skb), + chan->if_name, + chan->cfg.data_mux)){ + + wan_skb_free(chan->tx_idle_skb); + chan->tx_idle_skb = NULL; + return -EINVAL; + } + + wan_skb_reverse(chan->tx_idle_skb); + } + } + + + DEBUG_EVENT("\n"); + DEBUG_EVENT("%s: DMA MRU :%d\n", + card->devname, + chan->dma_mru); + + if (wan_test_bit(0,&chan->tdmv_sync)){ + if (chan->dma_mru%4){ + DEBUG_EVENT("%s:%s: Error invalid TDM_VOICE MTU %d MRU %d\n", + card->devname, + chan->if_name, + chan->dma_mru,card->u.aft.cfg.mru); + err= -EINVAL; + goto new_if_error; + } + } + + DEBUG_EVENT("%s: RX DMA Per Ch :%d\n", + card->devname, + card->u.aft.cfg.dma_per_ch); + + + + err=aft_alloc_rx_dma_buff(card, chan, card->u.aft.cfg.dma_per_ch); + if (err){ + goto new_if_error; + } + + /* If gateway option is set, then this interface is the + * default gateway on this system. We must know that information + * in case DYNAMIC interface configuration is enabled. + * + * I.E. If the interface is brought down by the driver, the + * default route will also be removed. Once the interface + * is brought back up, we must know to re-astablish the + * default route. + */ + + DEBUG_EVENT( "%s: Net Gateway :%s\n", + card->devname, + conf->gateway?"Yes":"No"); + + chan->gateway = conf->gateway; + + /* Get Multicast Information from the user + * FIXME: This option is not clearly defined + */ + chan->mc = conf->mc; + + + /* The network interface "dev" has been passed as + * an argument from the above layer. We must initialize + * it so it can be registered into the kernel. + * + * The "dev" structure is the link between the kernel + * stack and the wanpipe driver. It contains all + * access hooks that kernel uses to communicate to + * the our driver. + * + * For now, just set the "dev" name to the user + * defined name and initialize: + * dev->if_init : function that will be called + * to further initialize + * dev structure on "ifconfig up" + * + * dev->priv : private structure allocated above + * + */ + +#if 0 + /* Create interface file in proc fs. + * Once the proc file system is created, the new_if() function + * should exit successfuly. + * + * DO NOT place code under this function that can return + * anything else but 0. + */ + err = wanrouter_proc_add_interface(wandev, + &chan->dent, + chan->if_name, + dev); + if (err){ + DEBUG_EVENT( + "%s: can't create /proc/net/router/frmw/%s entry!\n", + card->devname, chan->if_name); + goto new_if_error; + } +#endif + + +#if defined(__LINUX__) + dev->init = &if_init; +# ifdef CONFIG_PRODUCT_WANPIPE_GENERIC + if_init(dev); +# endif +#else + if_init(dev); +#endif + +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) + chan->common.is_netdev = 1; + chan->common.iface.open = &wanpipe_xilinx_open; + chan->common.iface.close = &wanpipe_xilinx_close; + chan->common.iface.output = &wan_aft_output; + chan->common.iface.ioctl = &wanpipe_xilinx_ioctl; + chan->common.iface.get_stats = &wanpipe_xilinx_ifstats; + chan->common.iface.tx_timeout= &wanpipe_xilinx_tx_timeout; + if (wan_iface.attach){ + wan_iface.attach(dev, NULL, chan->common.is_netdev); + }else{ + DEBUG_EVENT("%s: Failed to attach interface %s!\n", + card->devname, wan_netif_name(dev)); + wan_netif_set_priv(dev, NULL); + err = -EINVAL; + goto new_if_error; + } + wan_netif_set_mtu(dev, chan->mtu); +#endif + /* Increment the number of network interfaces + ** configured on this card. */ + wan_atomic_inc(&card->wandev.if_cnt); + + chan->common.state = WAN_CONNECTING; + + DEBUG_EVENT( "\n"); + + return 0; + +new_if_error: + return err; +} + + +static int new_if (wan_device_t* wandev, netdevice_t* dev, wanif_conf_t* conf) +{ + int err=-EINVAL; + sdla_t *card=wandev->private; + + wan_netif_set_priv(dev, NULL); + + if (IS_E1_CARD(card)){ + DEBUG_TEST("%s: Time Slot Orig 0x%lX Shifted 0x%lX DCHAN=%i\n", + card->devname, + conf->active_ch, + conf->active_ch<<1, + card->u.aft.cfg.tdmv_dchan); + conf->active_ch = conf->active_ch << 1; + wan_clear_bit(0,&conf->active_ch); + } + +#if defined(CONFIG_PRODUCT_WANPIPE_TDM_VOICE) + if (strcmp(conf->usedby, "TDM_VOICE") == 0 ) { + if (card->u.aft.cfg.tdmv_span_no){ + /* Initialize TDMV interface function */ + err = wp_tdmv_te1_init(&card->tdmv_iface); + if (err){ + DEBUG_EVENT("%s: Error: Failed to initialize tdmv functions!\n", + card->devname); + return -EINVAL; + } + + WAN_TDMV_CALL(create, (card, &card->u.aft.cfg), err); + if (err){ + DEBUG_EVENT("%s: Error: Failed to create tdmv span!\n", + card->devname); + return err; + } + } + } +#endif + + if (strcmp(conf->usedby, "TDM_VOICE") == 0 || + strcmp(conf->usedby, "TDM_VOICE_API") == 0){ + + int dchan=card->u.aft.cfg.tdmv_dchan; + + if (IS_T1_CARD(card) && dchan){ + dchan--; + } + + if (dchan){ + wan_clear_bit(dchan,&conf->active_ch); + } + + err=new_if_private(wandev,dev,conf,1); + if (!err){ + if (card->u.aft.cfg.tdmv_dchan){ + + conf->active_ch=0; + if (strcmp(conf->usedby, "TDM_VOICE") == 0) { + sprintf(conf->usedby,"TDM_VOICE_DCHAN"); + } else { + sprintf(conf->usedby,"TDM_VOICE_DCHAN_API"); + } + wan_set_bit(dchan,&conf->active_ch); + + err=new_if_private(wandev,dev,conf,1); + if (err){ + return err; + } + } + } + + }else{ + err=new_if_private(wandev,dev,conf,0); + } + + if (err && wan_netif_priv(dev)){ + del_if(wandev,dev); + if (wan_netif_priv(dev)){ + wan_free(wan_netif_priv(dev)); + wan_netif_set_priv(dev, NULL); + } + } + + return err; + + +} + + + +/*============================================================================ + * del_if - Delete logical channel. + * + * @wandev: Wanpipe private device pointer + * @dev: Netowrk interface pointer + * + * This function is called by ROUTER_DELIF ioctl call + * to deallocate the network interface. + * + * The network interface and the private structure are + * about to be deallocated by the upper layer. + * We have to clean and deallocate any allocated memory. + * + * NOTE: DO NOT deallocate dev->priv here! It will be + * done by the upper layer. + * + */ +static int del_if_private (wan_device_t* wandev, netdevice_t* dev) +{ + private_area_t* chan = wan_netif_priv(dev); + sdla_t* card = (sdla_t*)chan->common.card; + netskb_t *skb; + + if (wan_test_bit(0,&chan->tdmv_sync)){ + wan_clear_bit(0,&card->u.aft.tdmv_sync); + wan_clear_bit(0,&chan->tdmv_sync); + } + + +#ifdef AFT_TDM_API_SUPPORT + if (aft_tdm_api_free_channelized(card,chan)){ + DEBUG_EVENT( + "%s: Error: Failed to del iface: TDM API Device in use!\n", + chan->if_name); + return -EBUSY; + } +#endif + +#ifndef CONFIG_PRODUCT_WANPIPE_GENERIC + xilinx_dev_unconfigure(card,chan); +#endif + WAN_TASKLET_KILL((&chan->common.bh_task)); + + if (chan->common.usedby == API){ + wan_unreg_api(chan, card->devname); + } + +#ifdef AFT_TDM_API_SUPPORT + aft_tdm_api_free_channelized(card,chan); +#endif + + aft_tdmv_if_free(card,chan); + + protocol_shutdown(card,dev); + +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) + if (wan_iface.detach){ + wan_iface.detach(dev, chan->common.is_netdev); + } +#endif + + while ((skb=wan_skb_dequeue(&chan->wp_rx_free_list)) != NULL){ + wan_skb_free(skb); + } + + while ((skb=wan_skb_dequeue(&chan->wp_rx_complete_list)) != NULL){ + wan_skb_free(skb); + } + + while ((skb=wan_skb_dequeue(&chan->wp_tx_free_list)) != NULL){ + wan_skb_free(skb); + } + while ((skb=wan_skb_dequeue(&chan->wp_tx_pending_list)) != NULL){ + wan_skb_free(skb); + } + + + if (chan->tx_dma_addr && chan->tx_dma_len){ + aft_unmap_tx_dma(card,chan); + } + + if (chan->tx_dma_skb){ + DEBUG_TEST("freeing tx dma skb\n"); + wan_skb_free(chan->tx_dma_skb); + chan->tx_dma_skb=NULL; + } + + if (chan->tx_idle_skb){ + DEBUG_TEST("freeing idle tx dma skb\n"); + wan_skb_free(chan->tx_idle_skb); + chan->tx_idle_skb=NULL; + } + + if (chan->rx_dma_skb){ + wp_rx_element_t *rx_el; + netskb_t *skb=chan->rx_dma_skb; + + chan->rx_dma_skb=NULL; + rx_el=(wp_rx_element_t *)wan_skb_data(skb); + + card->hw_iface.pci_unmap_dma(card->hw, + rx_el->dma_addr, + chan->dma_mru, + PCI_DMA_FROMDEVICE); + + wan_skb_free(skb); + } + + if (chan->tx_realign_buf){ + wan_free(chan->tx_realign_buf); + chan->tx_realign_buf=NULL; + } + + /* Delete interface name from proc fs. */ +#if 0 + wanrouter_proc_delete_interface(wandev, chan->if_name); +#endif + + /* Decrement the number of network interfaces + * configured on this card. + */ + wan_atomic_dec(&card->wandev.if_cnt); + + DEBUG_SUB_MEM(sizeof(private_area_t)); + return 0; +} + +static int del_if (wan_device_t* wandev, netdevice_t* dev) +{ + private_area_t* chan=wan_netif_priv(dev); + + if (!chan){ + return 0; + } + + if (chan->channelized_cfg){ + sdla_t *card=chan->common.card; + int err; + +#ifdef CONFIG_PRODUCT_WANPIPE_TDM_VOICE + if (chan->tdmv_zaptel_cfg) { + WAN_TDMV_CALL(running, (card), err); + if (err){ + return -EBUSY; + } + } +#endif + while(chan){ + err=del_if_private(wandev,dev); + if (err){ + return err; + } + chan=chan->next; + if (chan){ + wan_free(wan_netif_priv(dev)); + wan_netif_set_priv(dev, chan); + }else{ + /* Leave the last chan dev + * in dev->priv. It will get + * deallocated normally */ + break; + } + } + + aft_tdmv_free(card); + return 0; + }else{ + return del_if_private(wandev,dev); + } +} + + + +/**SECTION*********************************************************** + * + * KERNEL Device Entry Interfaces + * + ********************************************************************/ + + + +/*============================================================================ + * if_init - Initialize Linux network interface. + * + * @dev: Network interface pointer + * + * During "ifconfig up" the upper layer calls this function + * to initialize dev access pointers. Such as transmit, + * stats and header. + * + * It is called only once for each interface, + * during Linux network interface registration. + * + * Returning anything but zero will fail interface + * registration. + */ +static int if_init (netdevice_t* dev) +{ + private_area_t* chan = wan_netif_priv(dev); +#if defined(__LINUX__) + sdla_t* card = (sdla_t*)chan->common.card; + wan_device_t* wandev = &card->wandev; +#endif + + /* Initialize device driver entry points */ +#if defined(__LINUX__) +# ifndef CONFIG_PRODUCT_WANPIPE_GENERIC + dev->open = &wanpipe_xilinx_open; + dev->stop = &wanpipe_xilinx_close; + dev->hard_start_xmit = &wanpipe_xilinx_send; + dev->get_stats = &wanpipe_xilinx_ifstats; +# if defined(LINUX_2_4)||defined(LINUX_2_6) + if (chan->common.usedby == TDM_VOICE || + chan->common.usedby == TDM_VOICE_DCHAN || + chan->common.usedby == TDM_VOICE_API) { + dev->tx_timeout = NULL; + } else { + dev->tx_timeout = &wanpipe_xilinx_tx_timeout; + } + dev->watchdog_timeo = 2*HZ; +# endif + dev->do_ioctl = wanpipe_xilinx_ioctl; +# endif + + if (chan->common.usedby == BRIDGE || + chan->common.usedby == BRIDGE_NODE){ + + /* Setup the interface for Bridging */ + int hw_addr=0; + ether_setup(dev); + + /* Use a random number to generate the MAC address */ + memcpy(dev->dev_addr, "\xFE\xFC\x00\x00\x00\x00", 6); + get_random_bytes(&hw_addr, sizeof(hw_addr)); + *(int *)(dev->dev_addr + 2) += hw_addr; + + }else{ + + if (chan->common.protocol != WANCONFIG_GENERIC){ + dev->flags |= IFF_POINTOPOINT; + dev->flags |= IFF_NOARP; + dev->type = ARPHRD_PPP; + dev->mtu = chan->mtu; + + if (chan->common.usedby == API){ + dev->mtu+=sizeof(api_tx_hdr_t); + } + + dev->hard_header_len = 0; + dev->hard_header = NULL; + dev->rebuild_header = NULL; + + /* Enable Mulitcasting if user selected */ + if (chan->mc == WANOPT_YES){ + dev->flags |= IFF_MULTICAST; + } + + if (chan->true_if_encoding){ + DEBUG_EVENT("%s: Setting IF Type to Broadcast\n",chan->if_name); + dev->type = ARPHRD_PPP; /* This breaks the tcpdump */ + dev->flags &= ~IFF_POINTOPOINT; + dev->flags |= IFF_BROADCAST; + }else{ + dev->type = ARPHRD_PPP; + } + } + } + + /* Initialize hardware parameters */ + dev->irq = wandev->irq; + dev->dma = wandev->dma; + dev->base_addr = wandev->ioport; + card->hw_iface.getcfg(card->hw, SDLA_MEMBASE, &dev->mem_start); + card->hw_iface.getcfg(card->hw, SDLA_MEMEND, &dev->mem_end); + + /* Set transmit buffer queue length + * If too low packets will not be retransmitted + * by stack. + */ + dev->tx_queue_len = 100; +#else + dev->if_mtu = chan->mtu; +#if 0 + DEBUG_EVENT("%s: Initialize network interface...\n", + wan_netif_name(dev)); + dev->if_output = NULL; + dev->if_start = NULL; /*&wanpipe_xilinx_start;*/ + dev->if_ioctl = NULL; /* &wplip_ioctl; */ + + /* Initialize media-specific parameters */ + dev->if_flags |= IFF_POINTOPOINT; + dev->if_flags |= IFF_NOARP; + + dev->if_mtu = 1500; + WAN_IFQ_SET_MAXLEN(&dev->if_snd, 100); + dev->if_snd.ifq_len = 0; + dev->if_type = IFT_PPP; +#endif +#endif + return 0; +} + +/*============================================================================ + * if_open - Open network interface. + * + * @dev: Network device pointer + * + * On ifconfig up, this function gets called in order + * to initialize and configure the private area. + * Driver should be configured to send and receive data. + * + * This functions starts a timer that will call + * frmw_config() function. This function must be called + * because the IP addresses could have been changed + * for this interface. + * + * Return 0 if O.k. or errno. + */ +static int wanpipe_xilinx_open (netdevice_t* dev) +{ + private_area_t* chan = wan_netif_priv(dev); + sdla_t* card = (sdla_t*)chan->common.card; + wan_smp_flag_t flags; + int err = 0; + +#ifdef CONFIG_PRODUCT_WANPIPE_GENERIC + err=xilinx_chip_configure(card); + if (err){ + xilinx_chip_unconfigure(card); + return -EINVAL; + } + card->isr = &wp_xilinx_isr; + + err=xilinx_dev_configure(card, chan); + if (err){ + xilinx_chip_unconfigure(card); + return -EINVAL; + } + xilinx_delay(1); +#endif + /* Only one open per interface is allowed */ +#if defined(__LINUX__) + if (open_dev_check(dev)) + return -EBUSY; +#endif + + WAN_NETIF_START_QUEUE(dev); + WAN_NETIF_CARRIER_OFF(dev); + + wan_spin_lock_irq(&card->wandev.lock,&flags); + + aft_dev_open(card,chan); + + if (wan_test_bit(0,&chan->tdmv_sync) && + (card->wandev.state == WAN_CONNECTED || + card->u.aft.cfg.tdmv_span_no)){ + /* At this point we are out of sync. The + * DMA was enabled while interface was down. + * We must do a FULL recovery */ + DEBUG_EVENT("%s: Interface resynching!\n", + chan->if_name); + + if (card->wandev.state == WAN_CONNECTED){ + disable_data_error_intr(card,LINK_DOWN); + enable_data_error_intr(card); + + }else if (card->u.aft.cfg.tdmv_span_no) { + /* The A101/2 Card must supply clock to + * zaptel regardless of state. Thus fake + * the front end connected state */ + disable_data_error_intr(card,LINK_DOWN); + card->fe.fe_status = FE_CONNECTED; + handle_front_end_state(card); + + /* This will set the LEDs to RED and + * update the card state */ + card->fe.fe_status = FE_DISCONNECTED; + handle_front_end_state(card); + } + }else if (!chan->hdlc_eng && chan->common.usedby == API + && card->wandev.state == WAN_CONNECTED){ + disable_data_error_intr(card,LINK_DOWN); + enable_data_error_intr(card); + } + + wan_spin_unlock_irq(&card->wandev.lock,&flags); + + /* Increment the module usage count */ + wanpipe_open(card); + + if (card->wandev.state == WAN_CONNECTED){ + /* If Front End is connected already set interface + * state to Connected too */ + set_chan_state(card, dev, WAN_CONNECTED); + } + + protocol_start(card,dev); + + return err; +} + + + + +/*============================================================================ + * if_close - Close network interface. + * + * @dev: Network device pointer + * + * On ifconfig down, this function gets called in order + * to cleanup interace private area. + * + * IMPORTANT: + * + * No deallocation or unconfiguration should ever occur in this + * function, because the interface can come back up + * (via ifconfig up). + * + * Furthermore, in dynamic interfacace configuration mode, the + * interface will come up and down to reflect the protocol state. + * + * Any deallocation and cleanup can occur in del_if() + * function. That function is called before the dev interface + * itself is deallocated. + * + * Thus, we should only stop the net queue and decrement + * the wanpipe usage counter via wanpipe_close() function. + */ +static int wanpipe_xilinx_close (netdevice_t* dev) +{ + private_area_t* chan = wan_netif_priv(dev); + sdla_t* card = (sdla_t*)chan->common.card; + + + wan_clear_bit(0,&chan->up); + +#ifdef CONFIG_PRODUCT_WANPIPE_GENERIC + xilinx_dev_unconfigure(card, chan); + xilinx_chip_unconfigure(card); +#endif + WAN_NETIF_STOP_QUEUE(dev); /* stop_net_queue(dev); */ + +#if defined(LINUX_2_1) + dev->start=0; +#endif + protocol_stop(card,dev); + + aft_dev_close(card,chan); + + wanpipe_close(card); + return 0; +} + + +/*============================================================= + * disable_comm - Main shutdown function + * + * @card: Wanpipe device pointer + * + * The command 'wanrouter stop' has been called + * and the whole wanpipe device is going down. + * This is the last function called to disable + * all comunications and deallocate any memory + * that is still allocated. + * + * o Disable communications, turn off interrupts + * o Deallocate memory used, if any + * o Unconfigure TE1 card + */ + +static void disable_comm (sdla_t *card) +{ + wan_smp_flag_t flags; + + + wan_spin_lock_irq(&card->wandev.lock,&flags); + + /* Disable DMA ENGINE before we perform + * core reset. Otherwise, we will receive + * rx fifo errors on subsequent resetart. */ + disable_data_error_intr(card,DEVICE_DOWN); + + wan_set_bit(CARD_DOWN,&card->wandev.critical); + + card->isr=NULL; + + wan_spin_unlock_irq(&card->wandev.lock,&flags); + + /* TE1 - Unconfiging, only on shutdown */ + if (IS_TE1_CARD(card)) { + wan_smp_flag_t smp_flags,smp_flags1; + wan_spin_lock_irq(&card->wandev.lock, &smp_flags); + card->hw_iface.hw_lock(card->hw,&smp_flags1); + if (card->wandev.fe_iface.unconfig){ + card->wandev.fe_iface.unconfig(&card->fe); + } + card->hw_iface.hw_unlock(card->hw,&smp_flags1); + wan_spin_unlock_irq(&card->wandev.lock, &smp_flags); + } + + + WP_DELAY(10); + + xilinx_chip_unconfigure(card); + + + return; +} + + + +/*============================================================================ + * if_tx_timeout + * + * Kernel networking stack calls this function in case + * the interface has been stopped for TX_TIMEOUT seconds. + * + * This would occur if we lost TX interrupts or the + * card has stopped working for some reason. + * + * Handle transmit timeout event from netif watchdog + */ +static void wanpipe_xilinx_tx_timeout (netdevice_t* dev) +{ + private_area_t* chan = wan_netif_priv(dev); + sdla_t *card = (sdla_t*)chan->common.card; + unsigned long dma_descr; + u32 reg_lo, reg_hi; + + /* If our device stays busy for at least 5 seconds then we will + * kick start the device by making dev->tbusy = 0. We expect + * that our device never stays busy more than 5 seconds. So this + * is only used as a last resort. + */ + + ++chan->if_stats.collisions; + + DEBUG_EVENT( "%s: Transmit timed out on %s\n", card->devname,wan_netif_name(dev)); + DEBUG_EVENT("%s: TxStatus=0x%X DMAADDR=0x%X DMALEN=%d \n", + chan->if_name, + chan->dma_status, + chan->tx_dma_addr, + chan->tx_dma_len); + + dma_descr=(chan->logic_ch_num<<4) + XILINX_TxDMA_DESCRIPTOR_LO; + card->hw_iface.bus_read_4(card->hw,dma_descr, ®_lo); + + dma_descr=(chan->logic_ch_num<<4) + XILINX_TxDMA_DESCRIPTOR_HI; + card->hw_iface.bus_read_4(card->hw,dma_descr, ®_hi); + + DEBUG_EVENT("%s:%s: TX Error: Lch=%li DmaLO: 0x%08X DmaHI: 0x%08X\n", + card->devname,chan->if_name,chan->logic_ch_num, + reg_lo, reg_hi); + + wan_clear_bit(TX_BUSY,&chan->dma_status); + wan_netif_set_ticks(dev, SYSTEM_TICKS); + + WAN_NETIF_WAKE_QUEUE(dev); /*netif_wake_queue (dev);*/ +} + + +/*============================================================================ + * if_send - Send a packet on a network interface. + * + * @dev: Network interface pointer + * @skb: Packet obtained from the stack or API + * that should be sent out the port. + * + * o Mark interface as stopped + * (marks start of the transmission) to indicate + * to the stack that the interface is busy. + * + * o Check link state. + * If link is not up, then drop the packet. + * + * o Copy the tx packet into the protocol tx buffers on + * the adapter. + * + * o If tx successful: + * Free the skb buffer and mark interface as running + * and return 0. + * + * o If tx failed, busy: + * Keep interface marked as busy + * Do not free skb buffer + * Enable Tx interrupt (which will tell the stack + * that interace is not busy) + * Return a non-zero value to tell the stack + * that the tx should be retried. + * + * Return: 0 complete (socket buffer must be freed) + * non-0 packet may be re-transmitted + * + */ +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) +static int +wan_aft_output(netdevice_t *dev, netskb_t *skb, struct sockaddr *dst, struct rtentry *rt0) +#else +static int wanpipe_xilinx_send (netskb_t* skb, netdevice_t* dev) +#endif +{ + private_area_t *chan = wan_netif_priv(dev); + sdla_t *card; + + WAN_ASSERT(chan == NULL); + WAN_ASSERT(chan->common.card == NULL); + card = (sdla_t*)chan->common.card; + if (skb == NULL){ + /* This should never happen. Just a sanity check. + */ + DEBUG_EVENT( "%s: interface %s got kicked!\n", + card->devname, wan_netif_name(dev)); + + WAN_NETIF_WAKE_QUEUE(dev); + return 0; + } + + /* Non 2.4 kernels used to call if_send() + * after TX_TIMEOUT seconds have passed of interface + * being busy. Same as if_tx_timeout() in 2.4 kernels */ +#if defined(LINUX_2_1) + if (dev->tbusy){ + + /* If our device stays busy for at least 5 seconds then we will + * kick start the device by making dev->tbusy = 0. We expect + * that our device never stays busy more than 5 seconds. So this + * is only used as a last resort. + */ + ++chan->if_stats.collisions; + if((SYSTEM_TICKS - chan->tick_counter) < (5 * HZ)) { + return 1; + } + + if_tx_timeout(dev); + } +#endif + + if (chan->common.state != WAN_CONNECTED){ + ++chan->if_stats.tx_carrier_errors; + WAN_NETIF_STOP_QUEUE(dev); + wan_netif_set_ticks(dev, SYSTEM_TICKS); + return 1; + + }else { + + if (chan->common.usedby == TDM_VOICE || + chan->common.usedby == TDM_VOICE_DCHAN){ + + if (!card->u.aft.cfg.tdmv_dchan || card->u.aft.cfg.tdmv_dchan>32){ + wan_skb_free(skb); + WAN_NETIF_START_QUEUE(dev); + goto if_send_exit_crit; + } + + chan=(private_area_t*)card->u.aft.dev_to_ch_map[card->u.aft.cfg.tdmv_dchan-1]; + if (!chan){ + wan_skb_free(skb); + WAN_NETIF_START_QUEUE(dev); + goto if_send_exit_crit; + } + + if (!chan->hdlc_eng){ + wan_skb_free(skb); + WAN_NETIF_START_QUEUE(dev); + goto if_send_exit_crit; + } + + + }else if (chan->common.usedby == API){ + if (sizeof(api_tx_hdr_t) >= wan_skb_len(skb)){ + wan_skb_free(skb); + ++chan->if_stats.tx_dropped; + goto if_send_exit_crit; + } + wan_skb_pull(skb,sizeof(api_tx_hdr_t)); + + } + + if (wan_skb_queue_len(&chan->wp_tx_pending_list) > MAX_TX_BUF){ + WAN_NETIF_STOP_QUEUE(dev); /*stop_net_queue(dev);*/ + xilinx_dma_tx(card,chan); + return 1; + }else{ + wan_skb_unlink(skb); + +#if defined (__LINUX__) +#if 0 + if (is_tdm_api(chan,&chan->wp_tdm_api_cfg)){ + /* We must do this here, since it guarantees us that + * the packet will be queued up. However, we should + * disable the lock since this process could be computer + * intensive */ + int err=wanpipe_tdm_api_tx(&chan->wp_tdm_api_cfg,&skb); + if (err){ + ++chan->if_stats.tx_errors; + wan_skb_free(skb); + WAN_NETIF_START_QUEUE(dev); + err=0; + goto if_send_exit_crit; + } + } +#endif +#endif + if (!chan->hdlc_eng && chan->cfg.data_mux){ + wan_skb_reverse(skb); + } + + wan_skb_queue_tail(&chan->wp_tx_pending_list,skb); + xilinx_dma_tx(card,chan); + wan_netif_set_ticks(dev, SYSTEM_TICKS); + } + } + +if_send_exit_crit: + + WAN_NETIF_START_QUEUE(dev); + return 0; +} + + +/*============================================================================ + * if_stats + * + * Used by /proc/net/dev and ifconfig to obtain interface + * statistics. + * + * Return a pointer to struct net_device_stats. + */ +static struct net_device_stats gstats; +static struct net_device_stats* wanpipe_xilinx_ifstats (netdevice_t* dev) +{ + private_area_t* chan; + + if (!dev){ + return &gstats; + } + + if ((chan=wan_netif_priv(dev)) == NULL) + return &gstats; + + return &chan->if_stats; +} + + + + +/*======================================================================== + * + * if_do_ioctl - Ioctl handler for fr + * + * @dev: Device subject to ioctl + * @ifr: Interface request block from the user + * @cmd: Command that is being issued + * + * This function handles the ioctls that may be issued by the user + * to control or debug the protocol or hardware . + * + * It does both busy and security checks. + * This function is intended to be wrapped by callers who wish to + * add additional ioctl calls of their own. + * + * Used by: SNMP Mibs + * wanpipemon debugger + * + */ +static int +wanpipe_xilinx_ioctl(netdevice_t *dev, struct ifreq *ifr, int cmd) +{ + private_area_t* chan; + sdla_t *card; + wan_udp_pkt_t *wan_udp_pkt; +#if !defined(CONFIG_PRODUCT_WANPIPE_GENERIC) + wan_smp_flag_t smp_flags; +#endif + int err=0; + + if (!dev || !WAN_NETIF_UP(dev)){ + return -ENODEV; + } + + if (!(chan=(private_area_t*)wan_netif_priv(dev))){ + return -ENODEV; + } + card=(sdla_t*)chan->common.card; + + + switch(cmd) + { +#if defined(__LINUX__) + case SIOC_WANPIPE_BIND_SK: + if (!ifr){ + err= -EINVAL; + break; + } + +#if !defined(CONFIG_PRODUCT_WANPIPE_GENERIC) + wan_spin_lock_irq(&card->wandev.lock, &smp_flags); + err=wan_bind_api_to_svc(chan,ifr->ifr_data); + wan_spin_unlock_irq(&card->wandev.lock, &smp_flags); +#endif + + chan->if_stats.tx_carrier_errors=0; + + break; + + case SIOC_WANPIPE_UNBIND_SK: + if (!ifr){ + err= -EINVAL; + break; + } + +#if !defined(CONFIG_PRODUCT_WANPIPE_GENERIC) + wan_spin_lock_irq(&card->wandev.lock, &smp_flags); + err=wan_unbind_api_from_svc(chan,ifr->ifr_data); + wan_spin_unlock_irq(&card->wandev.lock, &smp_flags); +#endif + + break; + + case SIOC_WANPIPE_CHECK_TX: + case SIOC_ANNEXG_CHECK_TX: + err=0; + break; + + case SIOC_WANPIPE_DEV_STATE: + err = chan->common.state; + break; + + case SIOC_ANNEXG_KICK: + err=0; + break; +#endif + + case SIOC_WAN_DEVEL_IOCTL: + err = aft_devel_ioctl(card, ifr); + break; + +#if defined (__LINUX__) + case SIOC_WANPIPE_GET_DEVICE_CONFIG_ID: + err=card->wandev.config_id; + break; + +#endif + case SIOC_WANPIPE_PIPEMON: + + NET_ADMIN_CHECK(); + + if (wan_atomic_read(&chan->udp_pkt_len) != 0){ + return -EBUSY; + } + + wan_atomic_set(&chan->udp_pkt_len,MAX_LGTH_UDP_MGNT_PKT); + + /* For performance reasons test the critical + * here before spin lock */ + if (wan_test_bit(0,&card->in_isr)){ + wan_atomic_set(&chan->udp_pkt_len,0); + return -EBUSY; + } + + + wan_udp_pkt=(wan_udp_pkt_t*)chan->udp_pkt_data; + if (WAN_COPY_FROM_USER(&wan_udp_pkt->wan_udp_hdr,ifr->ifr_data,sizeof(wan_udp_hdr_t))){ + wan_atomic_set(&chan->udp_pkt_len,0); + return -EFAULT; + } + + /* We have to check here again because we don't know + * what happened during spin_lock */ + if (wan_test_bit(0,&card->in_isr)) { + DEBUG_TEST( "%s:%s Pipemon command failed, Driver busy: try again.\n", + card->devname,wan_netif_name(dev)); + wan_atomic_set(&chan->udp_pkt_len,0); + return -EBUSY; + } + + process_udp_mgmt_pkt(card,dev,chan,1); + + /* This area will still be critical to other + * PIPEMON commands due to udp_pkt_len + * thus we can release the irq */ + + if (wan_atomic_read(&chan->udp_pkt_len) > sizeof(wan_udp_pkt_t)){ + DEBUG_EVENT( "%s: Error: Pipemon buf too bit on the way up! %d\n", + card->devname,wan_atomic_read(&chan->udp_pkt_len)); + wan_atomic_set(&chan->udp_pkt_len,0); + return -EINVAL; + } + + if (WAN_COPY_TO_USER(ifr->ifr_data,&wan_udp_pkt->wan_udp_hdr,sizeof(wan_udp_hdr_t))){ + wan_atomic_set(&chan->udp_pkt_len,0); + return -EFAULT; + } + + wan_atomic_set(&chan->udp_pkt_len,0); + return 0; + + case SIOC_AFT_CUSTOMER_ID: + + if (!ifr){ + return -EINVAL; + }else{ + unsigned char cid; + wan_spin_lock_irq(&card->wandev.lock, &smp_flags); + cid=read_cpld(card,CUSTOMER_CPLD_ID_REG); + wan_spin_unlock_irq(&card->wandev.lock, &smp_flags); + return WAN_COPY_TO_USER(ifr->ifr_data,&cid,sizeof(unsigned char)); + } + break; + + default: +#if defined(CONFIG_PRODUCT_WANPIPE_GENERIC) + if (card->wandev.wanpipe_ioctl){ + err = card->wandev.wanpipe_ioctl(dev, ifr, cmd); + } +#else +# if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__) + return 1; +# else + DEBUG_TEST("%s: Command %x not supported!\n", + card->devname,cmd); + return -EOPNOTSUPP; +# endif +#endif + break; + } + + return err; +} + + +/**SECTION********************************************************** + * + * FIRMWARE Specific Interface Functions + * + *******************************************************************/ + + +/*============================================================================ + * xilinx_chip_configure + * + * + */ + +static int xilinx_chip_configure(sdla_t *card) +{ + u32 reg,tmp; + int err=0; + u16 adapter_type,adptr_security; + wan_smp_flag_t smp_flags; + + DEBUG_CFG("Xilinx Chip Configuration. -- \n"); + + xilinx_delay(1); + + card->hw_iface.bus_read_4(card->hw,XILINX_CHIP_CFG_REG,®); + + /* Configure for T1 or E1 front end */ + if (IS_T1_CARD(card)){ + card->u.aft.num_of_time_slots=NUM_OF_T1_CHANNELS; + wan_clear_bit(INTERFACE_TYPE_T1_E1_BIT,®); + wan_set_bit(FRONT_END_FRAME_FLAG_ENABLE_BIT,®); + }else if (IS_E1_CARD(card)){ + card->u.aft.num_of_time_slots=NUM_OF_E1_CHANNELS; + wan_set_bit(INTERFACE_TYPE_T1_E1_BIT,®); + wan_set_bit(FRONT_END_FRAME_FLAG_ENABLE_BIT,®); + }else{ + DEBUG_EVENT("%s: Error: Xilinx doesn't support non T1/E1 interface!\n", + card->devname); + return -EINVAL; + } + + /* Front end reference clock configuration. + * TE1 front end can use either Oscillator to + * generate clock, or use the clock from the + * other line. Supported in Ver:24 */ + if (WAN_TE1_REFCLK(&card->fe) == WAN_TE1_REFCLK_OSC){ + wan_clear_bit(AFT_TE1_FE_REF_CLOCK_BIT,®); + }else{ + wan_set_bit(AFT_TE1_FE_REF_CLOCK_BIT,®); + } + + card->hw_iface.bus_write_4(card->hw,XILINX_CHIP_CFG_REG,reg); + + WP_DELAY(10000); + + /* Reset PMC */ + card->hw_iface.bus_read_4(card->hw,XILINX_CHIP_CFG_REG,®); + wan_clear_bit(FRONT_END_RESET_BIT,®); + card->hw_iface.bus_write_4(card->hw,XILINX_CHIP_CFG_REG,reg); + WP_DELAY(1000); + + wan_set_bit(FRONT_END_RESET_BIT,®); + card->hw_iface.bus_write_4(card->hw,XILINX_CHIP_CFG_REG,reg); + WP_DELAY(100); + + + DEBUG_CFG("--- Chip Reset. -- \n"); + + /* Reset Chip Core */ + card->hw_iface.bus_read_4(card->hw,XILINX_CHIP_CFG_REG, ®); + wan_set_bit(CHIP_RESET_BIT,®); + card->hw_iface.bus_write_4(card->hw,XILINX_CHIP_CFG_REG,reg); + + WP_DELAY(100); + + /* Disable the chip/hdlc reset condition */ + wan_clear_bit(CHIP_RESET_BIT,®); + + /* Disable ALL chip interrupts */ + wan_clear_bit(GLOBAL_INTR_ENABLE_BIT,®); + wan_clear_bit(ERROR_INTR_ENABLE_BIT,®); + wan_clear_bit(FRONT_END_INTR_ENABLE_BIT,®); + + card->hw_iface.bus_write_4(card->hw,XILINX_CHIP_CFG_REG,reg); + + xilinx_delay(1); + +#if 1 + card->hw_iface.getcfg(card->hw, SDLA_ADAPTERTYPE, &adapter_type); + WP_DELAY(100); + + + /* Sanity check, where we make sure that A101 + * adapter gracefully fails on non existing + * secondary port */ + if (adapter_type == A101_1TE1_SUBSYS_VENDOR && + card->wandev.S514_cpu_no[0] == SDLA_CPU_B){ + DEBUG_EVENT("%s: Hardware Config Mismatch: A103 Adapter not found!\n", + card->devname); + /*return -ENODEV;*/ + } + + + adptr_security = read_cpld(card,SECURITY_CPLD_REG); + adptr_security = adptr_security >> SECURITY_CPLD_SHIFT; + adptr_security = adptr_security & SECURITY_CPLD_MASK; + + DEBUG_EVENT("%s: Hardware Adapter Type 0x%X Scurity 0x%02X\n", + card->devname,adapter_type, adptr_security); + + switch(adptr_security){ + + case SECURITY_1LINE_UNCH: + DEBUG_EVENT("%s: Security 1 Line UnCh\n", + card->devname); + break; + case SECURITY_1LINE_CH: + DEBUG_EVENT("%s: Security 1 Line Ch\n", + card->devname); + break; + case SECURITY_2LINE_UNCH: + DEBUG_EVENT("%s: Security 2 Line UnCh\n", + card->devname); + break; + case SECURITY_2LINE_CH: + DEBUG_EVENT("%s: Security 2 Line Ch\n", + card->devname); + break; + default: + DEBUG_EVENT("%s: Error Invalid Security ID=0x%X\n", + card->devname,adptr_security); + return -EINVAL; + } + +#endif + + /* Turn off Onboard RED LED */ + card->hw_iface.bus_read_4(card->hw,XILINX_CHIP_CFG_REG,®); + wan_set_bit(XILINX_RED_LED,®); + card->hw_iface.bus_write_4(card->hw,XILINX_CHIP_CFG_REG,reg); + WP_DELAY(10); + + err=aft_core_ready(card); + if (err != 0){ + DEBUG_EVENT("%s: WARNING: HDLC Core Not Ready: B4 TE CFG!\n", + card->devname); + + } + + card->hw_iface.hw_lock(card->hw,&smp_flags); + + err = -EINVAL; + if (card->wandev.fe_iface.config){ + err=card->wandev.fe_iface.config(&card->fe); + } + aft_red_led_ctrl(card, AFT_LED_ON); + card->wandev.fe_iface.led_ctrl(&card->fe, AFT_LED_OFF); + + card->hw_iface.hw_unlock(card->hw,&smp_flags); + + if (err){ + DEBUG_EVENT("%s: Failed %s configuratoin!\n", + card->devname, + (IS_T1_CARD(card))?"T1":"E1"); + return -EINVAL; + } + + xilinx_delay(1); + + err=aft_core_ready(card); + if (err != 0){ + DEBUG_EVENT("%s: Error: HDLC Core Not Ready!\n", + card->devname); + + card->hw_iface.bus_read_4(card->hw,XILINX_CHIP_CFG_REG, ®); + + /* Disable the chip/hdlc reset condition */ + wan_set_bit(CHIP_RESET_BIT,®); + + card->hw_iface.bus_write_4(card->hw,XILINX_CHIP_CFG_REG,reg); + return err; + } else{ + DEBUG_CFG("%s: HDLC Core Ready 0x%08X\n", + card->devname,reg); + } + + xilinx_delay(1); + + /* Setup global DMA parameters */ + reg=0; + reg|=(XILINX_DMA_SIZE << DMA_SIZE_BIT_SHIFT); + reg|=(XILINX_DMA_FIFO_UP << DMA_FIFO_HI_MARK_BIT_SHIFT); + reg|=(XILINX_DMA_FIFO_LO << DMA_FIFO_LO_MARK_BIT_SHIFT); + + /* Enable global DMA engine and set to default + * number of active channels. Note: this value will + * change in dev configuration */ + reg|=(XILINX_DEFLT_ACTIVE_CH << DMA_ACTIVE_CHANNEL_BIT_SHIFT); + wan_set_bit(DMA_ENGINE_ENABLE_BIT,®); + + DEBUG_CFG("--- Setup DMA control Reg. -- \n"); + + card->hw_iface.bus_write_4(card->hw,XILINX_DMA_CONTROL_REG,reg); + DEBUG_CFG("--- Tx/Rx global enable. -- \n"); + + xilinx_delay(1); + + reg=0; + card->hw_iface.bus_write_4(card->hw,XILINX_TIMESLOT_HDLC_CHAN_REG,reg); + + /* Clear interrupt pending registers befor first interrupt enable */ + card->hw_iface.bus_read_4(card->hw, XILINX_DMA_RX_INTR_PENDING_REG, &tmp); + card->hw_iface.bus_read_4(card->hw, XILINX_DMA_TX_INTR_PENDING_REG, &tmp); + card->hw_iface.bus_read_4(card->hw,XILINX_HDLC_RX_INTR_PENDING_REG, &tmp); + card->hw_iface.bus_read_4(card->hw,XILINX_HDLC_TX_INTR_PENDING_REG, &tmp); + card->hw_iface.bus_read_4(card->hw,XILINX_CHIP_CFG_REG, (u32*)®); + if (wan_test_bit(DMA_INTR_FLAG,®)){ + DEBUG_EVENT("%s: Error: Active DMA Interrupt Pending. !\n", + card->devname); + + reg = 0; + /* Disable the chip/hdlc reset condition */ + wan_set_bit(CHIP_RESET_BIT,®); + card->hw_iface.bus_write_4(card->hw,XILINX_CHIP_CFG_REG,reg); + return err; + } + if (wan_test_bit(ERROR_INTR_FLAG,®)){ + DEBUG_EVENT("%s: Error: Active Error Interrupt Pending. !\n", + card->devname); + + reg = 0; + /* Disable the chip/hdlc reset condition */ + wan_set_bit(CHIP_RESET_BIT,®); + card->hw_iface.bus_write_4(card->hw,XILINX_CHIP_CFG_REG,reg); + return err; + } + + + /* Alawys disable global data and error + * interrupts */ + wan_clear_bit(GLOBAL_INTR_ENABLE_BIT,®); + wan_clear_bit(ERROR_INTR_ENABLE_BIT,®); + + /* Always enable the front end interrupt */ + wan_set_bit(FRONT_END_INTR_ENABLE_BIT,®); + + DEBUG_CFG("%s: Enable Front End Interrupts\n", + card->devname); + + xilinx_delay(1); + + card->hw_iface.bus_write_4(card->hw,XILINX_CHIP_CFG_REG,reg); + + + return err; +} + +/*============================================================================ + * xilinx_chip_unconfigure + * + * + */ + +static int xilinx_chip_unconfigure(sdla_t *card) +{ + u32 reg = 0; + + card->hw_iface.bus_write_4(card->hw,XILINX_TIMESLOT_HDLC_CHAN_REG,reg); + card->hw_iface.bus_read_4(card->hw,XILINX_CHIP_CFG_REG, ®); + /* Enable the chip/hdlc reset condition */ + reg=0; + wan_set_bit(CHIP_RESET_BIT,®); + card->hw_iface.bus_write_4(card->hw,XILINX_CHIP_CFG_REG,reg); + return 0; +} + + +/*============================================================================ + * xilinx_dev_configure + * + * + */ + +static int xilinx_dev_configure(sdla_t *card, private_area_t *chan) +{ + u32 reg; + long free_logic_ch,i; + + DEBUG_TEST("-- Configure Xilinx. --\n"); + + chan->logic_ch_num=-1; + + if (!IS_TE1_CARD(card)){ + return -EINVAL; + } + + /* Channel definition section. If not channels defined + * return error */ + if (chan->time_slot_map == 0){ + DEBUG_EVENT("%s: Invalid Channel Selection 0x%X\n", + card->devname,chan->time_slot_map); + return -EINVAL; + } + + DEBUG_TEST("%s:%s: Active channels = 0x%X\n", + card->devname,chan->if_name,chan->time_slot_map); + + xilinx_delay(1); + + /* Check that the time slot is not being used. If it is + * stop the interface setup. Notice, though we proceed + * to check for all timeslots before we start binding + * the channels in. This way, we don't have to go back + * and clean the time_slot_map */ + for (i=0;iu.aft.num_of_time_slots;i++){ + if (wan_test_bit(i,&chan->time_slot_map)){ + + if (chan->first_time_slot == -1){ + DEBUG_TEST("%s:%s: Setting first time slot to %ld\n", + card->devname,chan->if_name,i); + chan->first_time_slot=i; + } + + DEBUG_CFG("%s: Configuring %s for timeslot %ld\n", + card->devname, chan->if_name, + IS_E1_CARD(card)?i:i+1); + + if (wan_test_bit(i,&card->u.aft.time_slot_map)){ + DEBUG_EVENT("%s: Channel/Time Slot resource conflict!\n", + card->devname); + DEBUG_EVENT("%s: %s: Channel/Time Slot %ld, aready in use!\n", + card->devname,chan->if_name,(i+1)); + + return -EEXIST; + } + + /* Calculate the number of timeslots for this + * interface */ + ++chan->num_of_time_slots; + } + } + + xilinx_delay(1); + + chan->logic_ch_num=request_xilinx_logical_channel_num(card, chan, &free_logic_ch); + if (chan->logic_ch_num == -1){ + return -EBUSY; + } + + xilinx_delay(1); + + DEBUG_TEST("%s:%d: GOT Logic ch %ld Free Logic ch %ld\n", + __FUNCTION__,__LINE__,chan->logic_ch_num,free_logic_ch); + + xilinx_delay(1); + + for (i=0;iu.aft.num_of_time_slots;i++){ + if (wan_test_bit(i,&chan->time_slot_map)){ + + wan_set_bit(i,&card->u.aft.time_slot_map); + + card->hw_iface.bus_read_4(card->hw, XILINX_TIMESLOT_HDLC_CHAN_REG, ®); + reg&=~TIMESLOT_BIT_MASK; + + /*FIXME do not hardcode !*/ + reg&= HDLC_LCH_TIMESLOT_MASK; /* mask not valid bits */ + + + /* Select a Timeslot for configuration */ + card->hw_iface.bus_write_4(card->hw, + XILINX_TIMESLOT_HDLC_CHAN_REG, + (reg|(i<logic_ch_num&CONTROL_RAM_DATA_MASK; + +#ifdef TRUE_FIFO_SIZE + reg|=(chan->fifo_size_code&HDLC_FIFO_SIZE_MASK)<fifo_base_addr&HDLC_FIFO_BASE_ADDR_MASK)<< + HDLC_FIFO_BASE_ADDR_SHIFT; + + if (!chan->hdlc_eng){ + wan_set_bit(TRANSPARENT_MODE_BIT,®); + } + + DEBUG_TEST("Setting Timeslot %ld to logic ch %ld Reg=0x%X\n", + i, chan->logic_ch_num,reg); + + xilinx_write_ctrl_hdlc(card, + i, + XILINX_CONTROL_RAM_ACCESS_BUF, + reg); + + } + } + + if (free_logic_ch != -1){ + + char free_ch_used=0; +#if 0 + if (wan_atomic_read(&card->wandev.if_cnt)==3){ + free_logic_ch=4; + } +#endif + for (i=0;iu.aft.num_of_time_slots;i++){ + if (!wan_test_bit(i,&card->u.aft.time_slot_map)){ + + card->hw_iface.bus_read_4(card->hw, + XILINX_TIMESLOT_HDLC_CHAN_REG, + ®); + + reg&=~TIMESLOT_BIT_MASK; + reg&= HDLC_LCH_TIMESLOT_MASK; /* mask not valid bits */ + + /* Select a Timeslot for configuration */ + card->hw_iface.bus_write_4(card->hw, + XILINX_TIMESLOT_HDLC_CHAN_REG, + (reg|(i<if_name,free_logic_ch); + + xilinx_delay(1); + + /* Setup the free logic channel as IDLE */ + + card->hw_iface.bus_read_4(card->hw, XILINX_TIMESLOT_HDLC_CHAN_REG, ®); + + reg&=~HDLC_LOGIC_CH_BIT_MASK; + reg&=HDLC_LCH_TIMESLOT_MASK; /* mask not valid bits */ + + card->hw_iface.bus_write_4(card->hw, + XILINX_TIMESLOT_HDLC_CHAN_REG, + (reg|(free_logic_ch&HDLC_LOGIC_CH_BIT_MASK))); + + reg=0; + wan_clear_bit(HDLC_RX_PROT_DISABLE_BIT,®); + wan_clear_bit(HDLC_TX_PROT_DISABLE_BIT,®); + + wan_set_bit(HDLC_RX_ADDR_RECOGN_DIS_BIT,®); + + xilinx_write_ctrl_hdlc(card, + chan->first_time_slot, + XILINX_HDLC_CONTROL_REG, + reg); + } + } + + /* Select an HDLC logic channel for configuration */ + card->hw_iface.bus_read_4(card->hw, XILINX_TIMESLOT_HDLC_CHAN_REG, ®); + + reg&=~HDLC_LOGIC_CH_BIT_MASK; + reg&= HDLC_LCH_TIMESLOT_MASK; /* mask not valid bits */ + + card->hw_iface.bus_write_4(card->hw, + XILINX_TIMESLOT_HDLC_CHAN_REG, + (reg|(chan->logic_ch_num&HDLC_LOGIC_CH_BIT_MASK))); + + reg=0; + + if (chan->hdlc_eng){ + /* HDLC engine is enabled on the above logical channels */ + wan_clear_bit(HDLC_RX_PROT_DISABLE_BIT,®); + wan_clear_bit(HDLC_TX_PROT_DISABLE_BIT,®); + DEBUG_TEST("%s:%s: Config for HDLC mode\n", + card->devname,chan->if_name); + }else{ + + /* Transprent Mode */ + + /* Do not start HDLC Core here, because + * we have to setup Tx/Rx DMA buffers first + * The transparent mode, will start + * comms as soon as the HDLC is enabled */ + + + xilinx_write_ctrl_hdlc(card, + chan->first_time_slot, + XILINX_HDLC_CONTROL_REG, + 0); + return 0; + } + + wan_set_bit(HDLC_TX_CHAN_ENABLE_BIT,®); + wan_set_bit(HDLC_RX_ADDR_RECOGN_DIS_BIT,®); + + xilinx_write_ctrl_hdlc(card, + chan->first_time_slot, + XILINX_HDLC_CONTROL_REG, + reg); + + return 0; +} + + +static void xilinx_dev_unconfigure(sdla_t *card, private_area_t *chan) +{ + u32 reg; + int i; + wan_smp_flag_t smp_flags; + + + DEBUG_CFG("\n-- Unconfigure Xilinx. --\n"); + + + if (wan_test_bit(0,&chan->tdmv_sync)){ + channel_timeslot_sync_ctrl(card,chan,0); + rx_chan_timeslot_sync_ctrl(card,0); + } + + /* Select an HDLC logic channel for configuration */ + if (chan->logic_ch_num != -1){ + + card->hw_iface.bus_read_4(card->hw,XILINX_TIMESLOT_HDLC_CHAN_REG, ®); + reg&=~HDLC_LOGIC_CH_BIT_MASK; + reg&= HDLC_LCH_TIMESLOT_MASK; /* mask not valid bits */ + + card->hw_iface.bus_write_4(card->hw, + XILINX_TIMESLOT_HDLC_CHAN_REG, + (reg|(chan->logic_ch_num&HDLC_LOGIC_CH_BIT_MASK))); + + + reg=0x00020000; + xilinx_write_ctrl_hdlc(card, + chan->first_time_slot, + XILINX_HDLC_CONTROL_REG, + reg); + + + for (i=0;iu.aft.num_of_time_slots;i++){ + if (wan_test_bit(i,&chan->time_slot_map)){ + + card->hw_iface.bus_read_4(card->hw, XILINX_TIMESLOT_HDLC_CHAN_REG, ®); + reg&=~TIMESLOT_BIT_MASK; + reg&= HDLC_LCH_TIMESLOT_MASK; /* mask not valid bits */ + + /* Select a Timeslot for configuration */ + card->hw_iface.bus_write_4(card->hw, + XILINX_TIMESLOT_HDLC_CHAN_REG, + (reg|(i<wandev.lock,&smp_flags); + free_xilinx_logical_channel_num(card,chan->logic_ch_num); + free_fifo_baddr_and_size(card,chan); + wan_spin_unlock_irq(&card->wandev.lock,&smp_flags); + + chan->logic_ch_num=-1; + + for (i=0;iu.aft.num_of_time_slots;i++){ + if (wan_test_bit(i,&chan->time_slot_map)){ + wan_clear_bit(i,&card->u.aft.time_slot_map); + } + } + } +} + +#define FIFO_RESET_TIMEOUT_CNT 1000 +#define FIFO_RESET_TIMEOUT_US 10 +static int xilinx_init_rx_dev_fifo(sdla_t *card, private_area_t *chan, unsigned char wait) +{ + + u32 reg; + u32 dma_descr; + u8 timeout=1; + u16 i; + + /* Clean RX DMA fifo */ + dma_descr=(unsigned long)(chan->logic_ch_num<<4) + XILINX_RxDMA_DESCRIPTOR_HI; + reg=0; + wan_set_bit(INIT_DMA_FIFO_CMD_BIT,®); + + DEBUG_TEST("%s: Clearing RX Fifo %s DmaDescr=(0x%X) Reg=(0x%X)\n", + __FUNCTION__,chan->if_name, + dma_descr,reg); + + card->hw_iface.bus_write_4(card->hw,dma_descr,reg); + + if (wait == WP_WAIT){ + for(i=0;ihw_iface.bus_read_4(card->hw,dma_descr,®); + if (wan_test_bit(INIT_DMA_FIFO_CMD_BIT,®)){ + WP_DELAY(FIFO_RESET_TIMEOUT_US); + continue; + } + timeout=0; + break; + } + + if (timeout){ + DEBUG_EVENT("%s:%s: Error: Rx fifo reset timedout %u us\n", + card->devname,chan->if_name,i*FIFO_RESET_TIMEOUT_US); + }else{ + DEBUG_TEST("%s:%s: Rx Fifo reset successful %u us\n", + card->devname,chan->if_name,i*FIFO_RESET_TIMEOUT_US); + } + }else{ + timeout=0; + } + + return timeout; +} + +static int xilinx_init_tx_dev_fifo(sdla_t *card, private_area_t *chan, unsigned char wait) +{ + u32 reg; + u32 dma_descr; + u8 timeout=1; + u16 i; + + /* Clean TX DMA fifo */ + dma_descr=(unsigned long)(chan->logic_ch_num<<4) + XILINX_TxDMA_DESCRIPTOR_HI; + reg=0; + wan_set_bit(INIT_DMA_FIFO_CMD_BIT,®); + + DEBUG_TEST("%s: Clearing TX Fifo %s DmaDescr=(0x%X) Reg=(0x%X)\n", + __FUNCTION__,chan->if_name, + dma_descr,reg); + + card->hw_iface.bus_write_4(card->hw,dma_descr,reg); + + if (wait == WP_WAIT){ + for(i=0;ihw_iface.bus_read_4(card->hw,dma_descr,®); + if (wan_test_bit(INIT_DMA_FIFO_CMD_BIT,®)){ + WP_DELAY(FIFO_RESET_TIMEOUT_US); + continue; + } + timeout=0; + break; + } + + if (timeout){ + DEBUG_EVENT("%s:%s: Error: Tx fifo reset timedout %u us\n", + card->devname,chan->if_name,i*FIFO_RESET_TIMEOUT_US); + }else{ + DEBUG_TEST("%s:%s: Tx Fifo reset successful %u us\n", + card->devname,chan->if_name,i*FIFO_RESET_TIMEOUT_US); + } + }else{ + timeout=0; + } + + return timeout; +} + + +static void xilinx_dev_enable(sdla_t *card, private_area_t *chan) +{ + u32 reg; + + DEBUG_TEST("%s: Enabling Global Inter Mask !\n",chan->if_name); + + /* Enable Logic Channel Interrupts for DMA and fifo */ + card->hw_iface.bus_read_4(card->hw, + XILINX_GLOBAL_INTER_MASK, ®); + wan_set_bit(chan->logic_ch_num,®); + card->hw_iface.bus_write_4(card->hw, + XILINX_GLOBAL_INTER_MASK, reg); + + wan_set_bit(chan->logic_ch_num,&card->u.aft.active_ch_map); +} + +static int xilinx_dma_rx(sdla_t *card, private_area_t *chan) +{ + u32 reg; + unsigned long dma_descr; + unsigned long bus_addr; + wp_rx_element_t *rx_el; + + + if (chan->rx_dma_skb){ + wp_rx_element_t *rx_el; + netskb_t *skb=chan->rx_dma_skb; + DEBUG_TEST("%s: Clearing RX DMA Pending buffer \n", + __FUNCTION__); + + chan->rx_dma_skb=NULL; + rx_el=(wp_rx_element_t *)wan_skb_data(skb); + + card->hw_iface.pci_unmap_dma(card->hw, + rx_el->dma_addr, + chan->dma_mru, + PCI_DMA_FROMDEVICE); + + aft_init_requeue_free_skb(chan, skb); + } + + chan->rx_dma_skb = wan_skb_dequeue(&chan->wp_rx_free_list); + + if (!chan->rx_dma_skb){ + netskb_t *skb; + DEBUG_TEST("%s: Critical Error no rx dma buf Free=%d Comp=%d!\n", + chan->if_name,wan_skb_queue_len(&chan->wp_rx_free_list), + wan_skb_queue_len(&chan->wp_rx_complete_list)); + + while((skb=wan_skb_dequeue(&chan->wp_rx_complete_list)) != NULL){ + aft_init_requeue_free_skb(chan, skb); + chan->if_stats.rx_errors++; + } + + + if (chan->common.usedby == TDM_VOICE || chan->common.usedby == TDM_VOICE_API){ + while((skb=wan_skb_dequeue(&chan->wp_tx_pending_list)) != NULL){ + aft_init_requeue_free_skb(chan, skb); + chan->if_stats.rx_errors++; + } + } + + chan->rx_dma_skb = wan_skb_dequeue(&chan->wp_rx_free_list); + if (!chan->rx_dma_skb){ + DEBUG_EVENT("%s:%ld:%d Critical Error no STILL NO MEM: RxFree=%i, RxComp=%i!\n", + chan->if_name,chan->logic_ch_num,chan->hdlc_eng, + wan_skb_queue_len(&chan->wp_rx_free_list), + wan_skb_queue_len(&chan->wp_rx_complete_list)); + + port_set_state(card,WAN_DISCONNECTED); + disable_data_error_intr(card,DEVICE_DOWN); + return -ENOMEM; + } + } + + wan_skb_put(chan->rx_dma_skb, sizeof(wp_rx_element_t)); + rx_el = (wp_rx_element_t *)wan_skb_data(chan->rx_dma_skb); + memset(rx_el,0,sizeof(wp_rx_element_t)); + + bus_addr = card->hw_iface.pci_map_dma(card->hw, + wan_skb_tail(chan->rx_dma_skb), + chan->dma_mru, + PCI_DMA_FROMDEVICE); + + if (!bus_addr){ + DEBUG_EVENT("%s: %s Critical error pci_map_dma() failed!\n", + chan->if_name,__FUNCTION__); + return -EINVAL; + } + + rx_el->dma_addr=bus_addr; + + /* Write the pointer of the data packet to the + * DMA address register */ + reg=bus_addr; + + /* Set the 32bit alignment of the data length. + * Since we are setting up for rx, set this value + * to Zero */ + reg&=~(RxDMA_LO_ALIGNMENT_BIT_MASK); + + dma_descr=(chan->logic_ch_num<<4) + XILINX_RxDMA_DESCRIPTOR_LO; + +#if 0 + DEBUG_RX("%s: RxDMA_LO = 0x%X, BusAddr=0x%X DmaDescr=0x%X\n", + __FUNCTION__,reg,bus_addr,dma_descr);*/ +#endif + card->hw_iface.bus_write_4(card->hw,dma_descr,reg); + + dma_descr=(unsigned long)(chan->logic_ch_num<<4) + XILINX_RxDMA_DESCRIPTOR_HI; + + reg =0; + + if (chan->hdlc_eng){ + reg|=(chan->dma_mru>>2)&RxDMA_HI_DMA_DATA_LENGTH_MASK; + }else{ + reg|=(chan->mru>>2)&RxDMA_HI_DMA_DATA_LENGTH_MASK; + } + +#ifdef TRUE_FIFO_SIZE + reg|=(chan->fifo_size_code&DMA_FIFO_SIZE_MASK)<fifo_base_addr&DMA_FIFO_BASE_ADDR_MASK)<< + DMA_FIFO_BASE_ADDR_SHIFT; + + wan_set_bit(RxDMA_HI_DMA_GO_READY_BIT,®); + + DEBUG_RX("%s: RXDMA_HI = 0x%X, BusAddr=0x%lX DmaDescr=0x%lX\n", + __FUNCTION__,reg,bus_addr,dma_descr); + + card->hw_iface.bus_write_4(card->hw,dma_descr,reg); + + + wan_set_bit(0,&chan->rx_dma); + + return 0; +} + +static void xilinx_dev_close(sdla_t *card, private_area_t *chan) +{ + u32 reg; + unsigned long dma_descr; + wan_smp_flag_t smp_flags; + + DEBUG_CFG("-- Close Xilinx device. --\n"); + + /* Disable Logic Channel Interrupts for DMA and fifo */ + card->hw_iface.bus_read_4(card->hw, + XILINX_GLOBAL_INTER_MASK, ®); + + wan_clear_bit(chan->logic_ch_num,®); + wan_clear_bit(chan->logic_ch_num,&card->u.aft.active_ch_map); + + /* We are masking the chan interrupt. + * Lock to make sure that the interrupt is + * not running */ + wan_spin_lock_irq(&card->wandev.lock,&smp_flags); + card->hw_iface.bus_write_4(card->hw, + XILINX_GLOBAL_INTER_MASK, reg); + wan_spin_unlock_irq(&card->wandev.lock,&smp_flags); + + + /* Clear descriptors */ + reg=0; + dma_descr=(chan->logic_ch_num<<4) + XILINX_RxDMA_DESCRIPTOR_HI; + card->hw_iface.bus_write_4(card->hw,dma_descr,reg); + dma_descr=(chan->logic_ch_num<<4) + XILINX_TxDMA_DESCRIPTOR_HI; + card->hw_iface.bus_write_4(card->hw,dma_descr,reg); + + /* FIXME: Cleanp up Tx and Rx buffers */ +} + + +static int xilinx_dma_tx (sdla_t *card, private_area_t *chan) +{ + u32 reg=0; + netskb_t *skb; + unsigned long dma_descr; + unsigned char len_align=0; + int len=0; + + + DEBUG_TX(" ------ Setup Tx DMA descriptor. --\n"); + + if (wan_test_and_set_bit(TX_BUSY,&chan->dma_status)){ + DEBUG_TX("%s:%d: TX_BUSY set!\n", + __FUNCTION__,__LINE__); + return -EBUSY; + } + + + /* Free the previously skb dma mapping. + * In this case the tx interrupt didn't finish + * and we must re-transmit.*/ + + if (chan->tx_dma_addr && chan->tx_dma_len){ + + if (WAN_NET_RATELIMIT()){ + DEBUG_EVENT("%s: Unmaping tx_dma_addr in %s\n", + chan->if_name,__FUNCTION__); + } + + aft_unmap_tx_dma(card,chan); + } + + /* Free the previously sent tx packet. To + * minimize tx isr, the previously transmitted + * packet is deallocated here */ + if (chan->tx_dma_skb){ + + if (WAN_NET_RATELIMIT()){ + DEBUG_EVENT("%s: Deallocating tx_dma_skb in %s\n", + chan->if_name,__FUNCTION__); + } + wan_skb_free(chan->tx_dma_skb); + chan->tx_dma_skb=NULL; + } + + + /* check queue pointers befor start transmittion */ + + /* sanity check: make sure that DMA is in ready state */ + dma_descr=(chan->logic_ch_num<<4) + XILINX_TxDMA_DESCRIPTOR_HI; + + DEBUG_TX("%s:%d: chan logic ch=%ld dma_descr=0x%lx set!\n", + __FUNCTION__,__LINE__,chan->logic_ch_num,dma_descr); + + card->hw_iface.bus_read_4(card->hw,dma_descr, ®); + + if (wan_test_bit(TxDMA_HI_DMA_GO_READY_BIT,®)){ + DEBUG_TEST("%s: Error: TxDMA GO Ready bit set on dma Tx 0x%X\n", + card->devname,reg); + wan_clear_bit(TX_BUSY,&chan->dma_status); + return -EFAULT; + } + + switch(chan->common.usedby){ + + case TDM_VOICE: + case TDM_VOICE_API: + skb = wan_skb_dequeue(&chan->wp_tx_pending_list); + break; + + default: + + if(!chan->lip_atm){ + skb=wan_skb_dequeue(&chan->wp_tx_pending_list); + }else{ + skb=atm_tx_skb_dequeue(&chan->wp_tx_pending_list, chan->tx_idle_skb, chan->if_name); + } + break; + } + + + if (!skb){ + if (chan->hdlc_eng){ + DEBUG_TEST("%s:%d: Tx pending list empty \n", + __FUNCTION__,__LINE__); + wan_clear_bit(TX_BUSY,&chan->dma_status); + return -ENOBUFS; + } + + /* Transparent HDLC Mode + * Transmit Idle Flag */ + len=wan_skb_len(chan->tx_idle_skb); + + chan->tx_dma_addr = card->hw_iface.pci_map_dma(card->hw, + wan_skb_data(chan->tx_idle_skb), + wan_skb_len(chan->tx_idle_skb), + PCI_DMA_TODEVICE); + + chan->tx_dma_len = wan_skb_len(chan->tx_idle_skb); + + chan->if_stats.tx_carrier_errors++; + }else{ + len = wan_skb_len(skb); + if (wan_skb_len(skb) > MAX_XILINX_TX_DMA_SIZE){ + /* FIXME: We need to split this frame into + * multiple parts. For now thought + * just drop it :) */ + DEBUG_EVENT("%s:%d: Tx pkt len > Max Len (%d)!\n", + __FUNCTION__,__LINE__,MAX_XILINX_TX_DMA_SIZE); + + if (chan->common.usedby == TDM_VOICE || chan->common.usedby == TDM_VOICE_API){ + aft_init_requeue_free_skb(chan, skb); + }else{ + wan_skb_free(skb); + } + wan_clear_bit(TX_BUSY,&chan->dma_status); + return -EINVAL; + } + + if ((u32)wan_skb_data(skb) & 0x03){ + int err=aft_realign_skb_pkt(chan, skb); + if (err){ + DEBUG_EVENT("%s: Error: Failed to allocate memory in %s()\n", + card->devname,__FUNCTION__); + + if (chan->common.usedby == TDM_VOICE || chan->common.usedby == TDM_VOICE_API){ + aft_init_requeue_free_skb(chan, skb); + }else{ + wan_skb_free(skb); + } + wan_clear_bit(TX_BUSY,&chan->dma_status); + return -EINVAL; + } + } + + + + chan->tx_dma_addr = + card->hw_iface.pci_map_dma(card->hw, + wan_skb_data(skb), + wan_skb_len(skb), + PCI_DMA_TODEVICE); + + chan->tx_dma_len = wan_skb_len(skb); + } + + if (chan->tx_dma_addr & 0x03){ + + DEBUG_EVENT("%s: Critcal Error: Tx Ptr not aligned to 32bit boudary!\n", + card->devname); + + if (skb){ + if (chan->common.usedby == TDM_VOICE || chan->common.usedby == TDM_VOICE_API){ + aft_init_requeue_free_skb(chan, skb); + }else{ + wan_skb_free(skb); + } + } + + aft_unmap_tx_dma(card,chan); + + wan_clear_bit(TX_BUSY,&chan->dma_status); + return -EINVAL; + } + + if (skb){ +#if defined(WAN_DEBUG_TX) + char* data = wan_skb_data(skb); +#endif + chan->tx_dma_skb=skb; + + DEBUG_TX("TX SKB DATA 0x%08X 0x%08X 0x%08X 0x%08X \n", + *(unsigned int*)&data[0], + *(unsigned int*)&data[4], + *(unsigned int*)&data[8], + *(unsigned int*)&data[12]); +#if defined(__LINUX__) + DEBUG_TX("Tx dma skb bound %p List=%p Data=%p BusPtr=%lx\n", + skb,skb->list,wan_skb_data(skb),chan->tx_dma_addr); +#endif + }else{ + chan->tx_dma_skb=NULL; + } + + + /* WARNING: Do ont use the "skb" pointer from + * here on. The skb pointer might not exist if + * we are in transparent mode */ + + dma_descr=(chan->logic_ch_num<<4) + XILINX_TxDMA_DESCRIPTOR_LO; + + /* Write the pointer of the data packet to the + * DMA address register */ + reg=chan->tx_dma_addr; + + /* Set the 32bit alignment of the data length. + * Used to pad the tx packet to the 32 bit + * boundary */ + reg&=~(TxDMA_LO_ALIGNMENT_BIT_MASK); + reg|=(len&0x03); + + if (len&0x03){ + len_align=1; + } + + DEBUG_TX("%s: TXDMA_LO=0x%X PhyAddr=0x%X DmaDescr=0x%lX\n", + __FUNCTION__,reg,chan->tx_dma_addr,dma_descr); + + card->hw_iface.bus_write_4(card->hw,dma_descr,reg); + + dma_descr=(chan->logic_ch_num<<4) + XILINX_TxDMA_DESCRIPTOR_HI; + + reg=0; + reg|=(((len>>2)+len_align)&TxDMA_HI_DMA_DATA_LENGTH_MASK); + +#ifdef TRUE_FIFO_SIZE + reg|=(chan->fifo_size_code&DMA_FIFO_SIZE_MASK)<fifo_base_addr&DMA_FIFO_BASE_ADDR_MASK)<< + DMA_FIFO_BASE_ADDR_SHIFT; + + if (chan->hdlc_eng){ + /* Only enable the Frame Start/Stop on + * non-transparent hdlc configuration */ + wan_set_bit(TxDMA_HI_DMA_FRAME_START_BIT,®); + wan_set_bit(TxDMA_HI_DMA_FRAME_END_BIT,®); + } + + /* For TDM VOICE Timeslot Synchronization, + * we must use FRAME START bit as a first + * slot sync character */ + if (wan_test_bit(0,&chan->tdmv_sync)){ + wan_set_bit(TxDMA_HI_DMA_FRAME_START_BIT,®); + } + + wan_set_bit(TxDMA_HI_DMA_GO_READY_BIT,®); + + DEBUG_TEST("%s: TXDMA_HI=0x%X DmaDescr=0x%lX\n", + __FUNCTION__,reg,dma_descr); + + card->hw_iface.bus_write_4(card->hw,dma_descr,reg); + + return 0; + +} + +static void xilinx_dma_tx_complete (sdla_t *card, private_area_t *chan) +{ + u32 reg=0; + unsigned long dma_descr; + +#if 0 + ++chan->if_stats.tx_carrier_errors; +#endif + /* DEBUGTX */ +/* card->hw_iface.bus_read_4(card->hw,0x78, &tmp1); */ + + dma_descr=(chan->logic_ch_num<<4) + XILINX_TxDMA_DESCRIPTOR_HI; + card->hw_iface.bus_read_4(card->hw,dma_descr, ®); + + if (reg & TxDMA_HI_DMA_DATA_LENGTH_MASK){ + chan->errstats.Tx_dma_len_nonzero++; + } + + if (!chan->tx_dma_skb){ + + if (chan->hdlc_eng){ + DEBUG_EVENT("%s: Critical Error: Tx DMA intr: no tx skb !\n", + card->devname); + wan_clear_bit(TX_BUSY,&chan->dma_status); + return; + }else{ + + aft_unmap_tx_dma(card,chan); + + /* For Transparent mode, if no user + * tx frames available, send an idle + * frame as soon as possible. + */ + wan_set_bit(0,&chan->idle_start); + + wan_clear_bit(TX_BUSY,&chan->dma_status); + xilinx_dma_tx(card,chan); + return; + } + + }else{ + + aft_unmap_tx_dma(card,chan); + + if (chan->hdlc_eng){ + + /* Do not free the packet here, + * copy the packet dma info into csum + * field and let the bh handler analyze + * the transmitted packet. + */ + + if (reg & TxDMA_HI_DMA_PCI_ERROR_RETRY_TOUT){ + + DEBUG_EVENT("%s:%s: PCI Error: 'Retry' exceeds maximum (64k): Reg=0x%X!\n", + card->devname,chan->if_name,reg); + + if (++chan->pci_retry < 3){ + wan_set_bit(TxDMA_HI_DMA_GO_READY_BIT,®); + + DEBUG_EVENT("%s: Retry: TXDMA_HI=0x%X DmaDescr=0x%lX\n", + __FUNCTION__,reg,dma_descr); + + card->hw_iface.bus_write_4(card->hw,dma_descr,reg); + return; + } + } + + chan->pci_retry=0; + wan_skb_set_csum(chan->tx_dma_skb, reg); + wan_skb_queue_tail(&chan->wp_tx_complete_list,chan->tx_dma_skb); + chan->tx_dma_skb=NULL; + + wan_clear_bit(TX_BUSY,&chan->dma_status); + + WAN_TASKLET_SCHEDULE(&chan->common.bh_task); + }else{ + netskb_t *skb = chan->tx_dma_skb; + chan->tx_dma_skb=NULL; + + /* For transparend mode, handle the + * transmitted packet directly from + * interrupt, to avoid tx overrun. + * + * We must clear TX_BUSY before post + * function, because the post function + * will restart tx dma via xilinx_dma_tx() + */ + + wan_skb_set_csum(skb, reg); + wan_clear_bit(TX_BUSY,&chan->dma_status); + xilinx_tx_post_complete (card,chan,skb); + + if (chan->common.usedby == TDM_VOICE || chan->common.usedby == TDM_VOICE_API){ + /* Voice code uses the rx buffer to + * transmit! So put the rx buffer back + * into the rx queue */ + aft_init_requeue_free_skb(chan, skb); + }else{ + wan_skb_free(skb); + } + } + } + + /* DEBUGTX */ +/* card->hw_iface.bus_read_4(card->hw,0x78, &tmp1); */ + +} + + +static void xilinx_tx_post_complete (sdla_t *card, private_area_t *chan, netskb_t *skb) +{ + unsigned long reg = wan_skb_csum(skb); + private_area_t *top_chan; + + if (card->u.aft.cfg.tdmv_dchan){ + top_chan=wan_netif_priv(chan->common.dev); + }else{ + top_chan=chan; + } + + xilinx_dma_tx(card,chan); + + if ((wan_test_bit(TxDMA_HI_DMA_GO_READY_BIT,®)) || + (reg & TxDMA_HI_DMA_DATA_LENGTH_MASK) || + (reg & TxDMA_HI_DMA_PCI_ERROR_MASK)){ + + + /* Checking Tx DMA Go bit. Has to be '0' */ + if (wan_test_bit(TxDMA_HI_DMA_GO_READY_BIT,®)){ + DEBUG_TEST("%s:%s: Error: TxDMA Intr: GO bit set on Tx intr (0x%lX)\n", + card->devname,chan->if_name,reg); + chan->errstats.Tx_dma_errors++; + } + + if (reg & TxDMA_HI_DMA_DATA_LENGTH_MASK){ + DEBUG_TEST("%s:%s: Error: TxDMA Length not equal 0 (0x%lX)\n", + card->devname,chan->if_name,reg); + chan->errstats.Tx_dma_errors++; + } + + /* Checking Tx DMA PCI error status. Has to be '0's */ + if (reg&TxDMA_HI_DMA_PCI_ERROR_MASK){ + + if (reg & TxDMA_HI_DMA_PCI_ERROR_M_ABRT){ + if (WAN_NET_RATELIMIT()){ + DEBUG_EVENT("%s:%s: Tx Error: Abort from Master: pci fatal error! (0x%lX)\n", + card->devname,chan->if_name,reg); + } + } + if (reg & TxDMA_HI_DMA_PCI_ERROR_T_ABRT){ + if (WAN_NET_RATELIMIT()){ + DEBUG_EVENT("%s:%s: Tx Error: Abort from Target: pci fatal error! (0x%lX)\n", + card->devname,chan->if_name,reg); + } + } + if (reg & TxDMA_HI_DMA_PCI_ERROR_DS_TOUT){ + DEBUG_TEST("%s:%s: Tx Warning: PCI Latency Timeout! (0x%lX)\n", + card->devname,chan->if_name,reg); + chan->errstats.Tx_pci_latency++; + goto tx_post_ok; + } + if (reg & TxDMA_HI_DMA_PCI_ERROR_RETRY_TOUT){ + if (WAN_NET_RATELIMIT()){ + DEBUG_EVENT("%s:%s: Tx Error: 'Retry' exceeds maximum (64k): pci fatal error! (0x%lX)\n", + card->devname,chan->if_name,reg); + } + } + chan->errstats.Tx_pci_errors++; + } + chan->if_stats.tx_dropped++; + goto tx_post_exit; + } + +tx_post_ok: + + chan->opstats.Data_frames_Tx_count++; + chan->opstats.Data_bytes_Tx_count+=wan_skb_len(skb); + chan->if_stats.tx_packets++; + chan->if_stats.tx_bytes+=wan_skb_len(skb); + + /* Indicate that the first tx frame went + * out on the transparent link */ + wan_set_bit(0,&chan->idle_start); + + + if (wan_tracing_enabled(&top_chan->trace_info) >= 1){ + if (card->u.aft.cfg.tdmv_dchan){ + if (chan->common.usedby == TDM_VOICE_DCHAN){ + wan_capture_trace_packet(card, &top_chan->trace_info, skb, TRC_OUTGOING_FRM); + } + }else{ + wan_capture_trace_packet_offset(card, &top_chan->trace_info, skb, + IS_T1_CARD(card)?24:16, TRC_OUTGOING_FRM); + } + }else{ + wan_capture_trace_packet(card, &top_chan->trace_info, skb, TRC_OUTGOING_FRM); + } + +tx_post_exit: + + if (WAN_NETIF_QUEUE_STOPPED(chan->common.dev)){ + WAN_NETIF_WAKE_QUEUE(chan->common.dev); +#if !defined(CONFIG_PRODUCT_WANPIPE_GENERIC) + if (chan->common.usedby == API){ +# if defined(__LINUX__) + wan_wakeup_api(chan); +# endif + }else if (chan->common.usedby == STACK){ + wanpipe_lip_kick(chan,0); + } +#endif + } + +#ifdef AFT_TDM_API_SUPPORT + if (chan->common.usedby == TDM_VOICE_DCHAN){ + wanpipe_tdm_api_dev_t *wp_tdm_api_dev = + &chan->wp_tdm_api_dev_idx[chan->tdmv_chan]; + + if (is_tdm_api(chan,wp_tdm_api_dev)){ + wanpipe_tdm_api_kick(wp_tdm_api_dev); + } + } +#endif + + + return; +} + +static void xilinx_dma_rx_complete (sdla_t *card, private_area_t *chan) +{ + unsigned long dma_descr; + netskb_t *skb; + wp_rx_element_t *rx_el; + int tdmv_sync_reset=0; + +#if 0 + /*NCDEBUG: Used to debug the TDM rx queues */ + chan->if_stats.rx_errors=wan_skb_queue_len(&chan->wp_rx_free_list); + chan->if_stats.tx_errors=wan_skb_queue_len(&chan->wp_tx_pending_list); +#endif + + wan_clear_bit(0,&chan->rx_dma); + + if (!chan->rx_dma_skb){ + if (WAN_NET_RATELIMIT()){ + DEBUG_EVENT("%s: Critical Error: rx_dma_skb\n",chan->if_name); + } + return; + } + + rx_el=(wp_rx_element_t *)wan_skb_data(chan->rx_dma_skb); + +#if 0 + chan->if_stats.rx_frame_errors++; +#endif + +/* card->hw_iface.bus_read_4(card->hw,0x80, &rx_empty); */ + + /* Reading Rx DMA descriptor information */ + dma_descr=(chan->logic_ch_num<<4) + XILINX_RxDMA_DESCRIPTOR_LO; + card->hw_iface.bus_read_4(card->hw,dma_descr, &rx_el->align); + rx_el->align&=RxDMA_LO_ALIGNMENT_BIT_MASK; + + dma_descr=(chan->logic_ch_num<<4) + XILINX_RxDMA_DESCRIPTOR_HI; + card->hw_iface.bus_read_4(card->hw,dma_descr, &rx_el->reg); + + rx_el->pkt_error = chan->pkt_error; + +/* DEBUG_RX("%s: DmaDescrLo=0x%X DmaHi=0x%X \n",*/ +/* __FUNCTION__,rx_el.align,reg);*/ + + + card->hw_iface.pci_unmap_dma(card->hw, + rx_el->dma_addr, + chan->dma_mru, + PCI_DMA_FROMDEVICE); + + DEBUG_RX("%s:%s: RX HI=0x%X LO=0x%X DMA=0x%lX\n", + __FUNCTION__,chan->if_name,rx_el->reg,rx_el->align,rx_el->dma_addr); + + skb=chan->rx_dma_skb; + chan->rx_dma_skb=NULL; + + if (wan_test_bit(WP_FIFO_ERROR_BIT, &chan->pkt_error)){ + if (wan_test_bit(0,&chan->tdmv_sync)){ + rx_chan_timeslot_sync_ctrl(card,0); + xilinx_init_rx_dev_fifo(card, chan, WP_WAIT); + tdmv_sync_reset=1; + } + } + + xilinx_dma_rx(card,chan); + + if (tdmv_sync_reset){ + rx_chan_timeslot_sync_ctrl(card,1); + } + + if (chan->common.usedby == TDM_VOICE || chan->common.usedby == TDM_VOICE_API){ + signed int err; + if (!wan_test_bit(WP_FIFO_ERROR_BIT, &chan->pkt_error)){ + err=aft_dma_rx_tdmv(card,chan,skb); + if (err == 0){ + skb=NULL; + } + } + + if (skb){ + aft_init_requeue_free_skb(chan, skb); + chan->if_stats.rx_dropped++; + } + }else{ + wan_skb_queue_tail(&chan->wp_rx_complete_list,skb); + WAN_TASKLET_SCHEDULE(&chan->common.bh_task); + } + + chan->pkt_error=0; + +/* card->hw_iface.bus_read_4(card->hw,0x80, &rx_empty); */ +} + + +static void xilinx_rx_post_complete (sdla_t *card, private_area_t *chan, + netskb_t *skb, + netskb_t **new_skb, + unsigned char *pkt_error) +{ + + unsigned int len,data_error = 0; + unsigned char *buf; + wp_rx_element_t *rx_el=(wp_rx_element_t *)wan_skb_data(skb); + + DEBUG_RX("%s:%s: RX HI=0x%X LO=0x%X DMA=0x%lX\n", + __FUNCTION__,chan->if_name,rx_el->reg,rx_el->align,rx_el->dma_addr); + +#if 0 + chan->if_stats.rx_errors++; +#endif + + rx_el->align&=RxDMA_LO_ALIGNMENT_BIT_MASK; + *pkt_error=0; + *new_skb=NULL; + + + /* Checking Rx DMA Go bit. Has to be '0' */ + if (wan_test_bit(RxDMA_HI_DMA_GO_READY_BIT,&rx_el->reg)){ + DEBUG_TEST("%s:%s: Error: RxDMA Intr: GO bit set on Rx intr\n", + card->devname,chan->if_name); + chan->if_stats.rx_errors++; + chan->errstats.Rx_dma_descr_err++; + goto rx_comp_error; + } + + /* Checking Rx DMA PCI error status. Has to be '0's */ + if (rx_el->reg&RxDMA_HI_DMA_PCI_ERROR_MASK){ + + if (rx_el->reg & RxDMA_HI_DMA_PCI_ERROR_M_ABRT){ + DEBUG_EVENT("%s:%s: Rx Error: Abort from Master: pci fatal error! (0x%08X)\n", + card->devname,chan->if_name,rx_el->reg); + } + if (rx_el->reg & RxDMA_HI_DMA_PCI_ERROR_T_ABRT){ + DEBUG_EVENT("%s:%s: Rx Error: Abort from Target: pci fatal error! (0x%08X)\n", + card->devname,chan->if_name,rx_el->reg); + } + if (rx_el->reg & RxDMA_HI_DMA_PCI_ERROR_DS_TOUT){ + DEBUG_EVENT("%s:%s: Rx Error: No 'DeviceSelect' from target: pci fatal error! (0x%08X)\n", + card->devname,chan->if_name,rx_el->reg); + } + if (rx_el->reg & RxDMA_HI_DMA_PCI_ERROR_RETRY_TOUT){ + DEBUG_EVENT("%s:%s: Rx Error: 'Retry' exceeds maximum (64k): pci fatal error! (0x%08X)\n", + card->devname,chan->if_name,rx_el->reg); + } + + chan->if_stats.rx_errors++; + chan->errstats.Rx_pci_errors++; + goto rx_comp_error; + } + + if (chan->hdlc_eng){ + + /* Checking Rx DMA Frame start bit. (information for api) */ + if (!wan_test_bit(RxDMA_HI_DMA_FRAME_START_BIT,&rx_el->reg)){ + DEBUG_TEST("%s:%s RxDMA Intr: Start flag missing: MTU Mismatch! Reg=0x%X\n", + card->devname,chan->if_name,rx_el->reg); + chan->if_stats.rx_frame_errors++; + chan->opstats.Rx_Data_discard_long_count++; + chan->errstats.Rx_hdlc_corrupiton++; + goto rx_comp_error; + } + + /* Checking Rx DMA Frame end bit. (information for api) */ + if (!wan_test_bit(RxDMA_HI_DMA_FRAME_END_BIT,&rx_el->reg)){ + DEBUG_TEST("%s:%s: RxDMA Intr: End flag missing: MTU Mismatch! Reg=0x%X\n", + card->devname,chan->if_name,rx_el->reg); + chan->if_stats.rx_frame_errors++; + chan->opstats.Rx_Data_discard_long_count++; + chan->errstats.Rx_hdlc_corrupiton++; + goto rx_comp_error; + + } else { /* Check CRC error flag only if this is the end of Frame */ + + if (wan_test_bit(RxDMA_HI_DMA_CRC_ERROR_BIT,&rx_el->reg)){ + DEBUG_TEST("%s:%s: RxDMA Intr: CRC Error! Reg=0x%X\n", + card->devname,chan->if_name,rx_el->reg); + chan->if_stats.rx_errors++; + chan->errstats.Rx_crc_err_count++; + wan_set_bit(WP_CRC_ERROR_BIT,&rx_el->pkt_error); + data_error = 1; + } + + /* Check if this frame is an abort, if it is + * drop it and continue receiving */ + if (wan_test_bit(RxDMA_HI_DMA_FRAME_ABORT_BIT,&rx_el->reg)){ + DEBUG_TEST("%s:%s: RxDMA Intr: Abort! Reg=0x%X\n", + card->devname,chan->if_name,rx_el->reg); + chan->if_stats.rx_frame_errors++; + chan->errstats.Rx_hdlc_corrupiton++; + wan_set_bit(WP_ABORT_ERROR_BIT,&rx_el->pkt_error); + data_error = 1; + } + + if (chan->common.usedby != API && data_error){ + goto rx_comp_error; + } + } + } + + len=rx_el->reg&RxDMA_HI_DMA_DATA_LENGTH_MASK; + + if (chan->hdlc_eng){ + /* In HDLC mode, calculate rx length based + * on alignment value, received from DMA */ + len=(((chan->dma_mru>>2)-len)<<2) - (~(rx_el->align)&RxDMA_LO_ALIGNMENT_BIT_MASK); + + if (len < 1 || len > chan->dma_mru){ + chan->if_stats.rx_frame_errors++; + chan->errstats.Rx_hdlc_corrupiton++; + goto rx_comp_error; + } + + }else{ + /* In Transparent mode, our RX buffer will always be + * aligned to the 32bit (word) boundary, because + * the RX buffers are all of equal length */ + len=(((chan->mru>>2)-len)<<2) - (~(0x03)&RxDMA_LO_ALIGNMENT_BIT_MASK); + + if (len < 1 || len > chan->mru){ + chan->if_stats.rx_frame_errors++; + goto rx_comp_error; + } + } + + + *pkt_error=rx_el->pkt_error; + + /* After a RX FIFO overflow, we must mark max 7 + * subsequent frames since firmware, cannot + * guarantee the contents of the fifo */ + + if (wan_test_bit(WP_FIFO_ERROR_BIT,&rx_el->pkt_error)){ + if (++chan->rx_fifo_err_cnt >= WP_MAX_FIFO_FRAMES){ + chan->rx_fifo_err_cnt=0; + } + wan_set_bit(WP_FIFO_ERROR_BIT,pkt_error); + }else{ + if (chan->rx_fifo_err_cnt){ + if (++chan->rx_fifo_err_cnt >= WP_MAX_FIFO_FRAMES){ + chan->rx_fifo_err_cnt=0; + } + wan_set_bit(WP_FIFO_ERROR_BIT,pkt_error); + } + } + + if (len > aft_rx_copyback){ + + /* The rx size is big enough, thus + * send this buffer up the stack + * and allocate another one */ + memset(wan_skb_data(skb),0,sizeof(wp_rx_element_t)); + wan_skb_put(skb,len); + wan_skb_pull(skb, sizeof(wp_rx_element_t)); + *new_skb=skb; + + aft_alloc_rx_dma_buff(card,chan,1); + + }else{ + + /* The rx packet is very + * small thus, allocate a new + * buffer and pass it up + */ + *new_skb=wan_skb_alloc(len + 20); + if (!*new_skb){ + DEBUG_EVENT("%s:%s: Failed to allocate rx skb pkt (len=%d)!\n", + card->devname,chan->if_name,(len+20)); + chan->if_stats.rx_dropped++; + goto rx_comp_error; + } + + buf=wan_skb_put((*new_skb),len); + memcpy(buf, wan_skb_tail(skb),len); + + aft_init_requeue_free_skb(chan, skb); + } + + + if (!chan->hdlc_eng && chan->cfg.data_mux){ + wan_skb_reverse(*new_skb); + } + + return; + +rx_comp_error: + + aft_init_requeue_free_skb(chan, skb); + return; +} + + +static char request_xilinx_logical_channel_num (sdla_t *card, private_area_t *chan, long *free_ch) +{ + signed char logic_ch=-1, free_logic_ch=-1; + int i,err; + + *free_ch=-1; + + DEBUG_TEST("-- Request_Xilinx_logic_channel_num:--\n"); + + DEBUG_TEST("%s:%d Global Num Timeslots=%d Global Logic ch Map 0x%lX \n", + __FUNCTION__,__LINE__, + card->u.aft.num_of_time_slots, + card->u.aft.logic_ch_map); + + + err=request_fifo_baddr_and_size(card,chan); + if (err){ + return -1; + } + + + for (i=0;iu.aft.num_of_time_slots;i++){ + if (!wan_test_and_set_bit(i,&card->u.aft.logic_ch_map)){ + logic_ch=i; + break; + } + } + + if (logic_ch == -1){ + return logic_ch; + } + + for (i=0;iu.aft.num_of_time_slots;i++){ + if (!wan_test_bit(i,&card->u.aft.logic_ch_map)){ + free_logic_ch=HDLC_FREE_LOGIC_CH; + break; + } + } + + if (card->u.aft.dev_to_ch_map[(unsigned char)logic_ch]){ + DEBUG_EVENT("%s: Error, request logical ch=%d map busy\n", + card->devname,logic_ch); + return -1; + } + + *free_ch=free_logic_ch; + + card->u.aft.dev_to_ch_map[(unsigned char)logic_ch]=(void*)chan; + + if (logic_ch > card->u.aft.top_logic_ch){ + card->u.aft.top_logic_ch=logic_ch; + xilinx_dma_max_logic_ch(card); + } + + + DEBUG_CFG("Binding logic ch %d Ptr=%p\n",logic_ch,chan); + return logic_ch; +} + +static void free_xilinx_logical_channel_num (sdla_t *card, int logic_ch) +{ + wan_clear_bit (logic_ch,&card->u.aft.logic_ch_map); + card->u.aft.dev_to_ch_map[logic_ch]=NULL; + + if (logic_ch >= card->u.aft.top_logic_ch){ + int i; + + card->u.aft.top_logic_ch=XILINX_DEFLT_ACTIVE_CH; + + for (i=0;iu.aft.num_of_time_slots;i++){ + /*NC: Bug fix: Apr 28 2005 + * Used logic_ch instead of i as the + * index into the dev_to_ch_map */ + if (card->u.aft.dev_to_ch_map[i]){ + card->u.aft.top_logic_ch=i; + } + } + + xilinx_dma_max_logic_ch(card); + } + +} + +static void xilinx_dma_max_logic_ch(sdla_t *card) +{ + u32 reg; + + + DEBUG_CFG("-- Xilinx_dma_max_logic_ch :--\n"); + + card->hw_iface.bus_read_4(card->hw,XILINX_DMA_CONTROL_REG, ®); + + /* Set up the current highest active logic channel */ + + reg&=DMA_ACTIVE_CHANNEL_BIT_MASK; + reg|=(card->u.aft.top_logic_ch << DMA_ACTIVE_CHANNEL_BIT_SHIFT); + + card->hw_iface.bus_write_4(card->hw,XILINX_DMA_CONTROL_REG,reg); +} + +static int aft_init_requeue_free_skb(private_area_t *chan, netskb_t *skb) +{ + wan_skb_init(skb,16); + wan_skb_trim(skb,0); +#if 0 + memset(wan_skb_data(skb),0,sizeof(wp_rx_element_t)); +#endif + wan_skb_queue_tail(&chan->wp_rx_free_list,skb); + + return 0; +} + +#if 0 +static int aft_reinit_pending_rx_bufs(private_area_t *chan) +{ + netskb_t *skb; + + while((skb=wan_skb_dequeue(&chan->wp_rx_complete_list)) != NULL){ + chan->if_stats.rx_dropped++; + aft_init_requeue_free_skb(chan,skb); + } + + return 0; +} +#endif + +static int aft_alloc_rx_dma_buff(sdla_t *card, private_area_t *chan, int num) +{ + int i; + netskb_t *skb; + + for (i=0;idma_mru); + if (!skb){ + DEBUG_EVENT("%s: %s no memory\n", + chan->if_name,__FUNCTION__); + return -ENOMEM; + } + wan_skb_queue_tail(&chan->wp_rx_free_list,skb); + } + + return 0; +} + + + + +/*============================================================================ + * Enable timer interrupt + */ +static void enable_timer (void* card_id) +{ + sdla_t *card = (sdla_t*)card_id; + +#if defined(__LINUX__) + wan_set_bit(AFT_FE_POLL,&card->u.aft.port_task_cmd); + WAN_TASKQ_SCHEDULE((&card->u.aft.port_task)); +#else + wan_smp_flag_t smp_flags; + wan_spin_lock_irq(&card->wandev.lock, &smp_flags); + card->wandev.fe_iface.polling(&card->fe); + wan_spin_unlock_irq(&card->wandev.lock, &smp_flags); +#endif + + DEBUG_TEST("%s: %s Sdla Polling End!\n", + __FUNCTION__,card->devname); + return; +} + +/**SECTION************************************************** + * + * API Bottom Half Handlers + * + **********************************************************/ + +#if defined(__LINUX__) +static void wp_bh (unsigned long data) +#else +static void wp_bh(void *data, int pending) +#endif +{ + private_area_t *chan = (private_area_t *)data; + sdla_t *card = chan->common.card; + netskb_t *new_skb, *skb; + unsigned char pkt_error; + int len; + private_area_t *top_chan; + + + if (!wan_test_bit(0,&chan->up)){ + DEBUG_EVENT("%s: wp_bh() chan not up!\n", + chan->if_name); + WAN_TASKLET_END(&chan->common.bh_task); + return; + } + + if (card->u.aft.cfg.tdmv_dchan){ + top_chan=wan_netif_priv(chan->common.dev); + }else{ + top_chan=chan; + } + + while((skb=wan_skb_dequeue(&chan->wp_rx_complete_list)) != NULL){ + int len; + +#if 0 + chan->if_stats.rx_errors++; +#endif + + if (chan->common.usedby == API && chan->common.sk == NULL){ + DEBUG_TEST("%s: No sock bound to channel rx dropping!\n", + chan->if_name); + chan->if_stats.rx_dropped++; + + aft_init_requeue_free_skb(chan, skb); + + continue; + } + + new_skb=NULL; + pkt_error=0; + + /* The post function will take care + * of the skb and new_skb buffer. + * If new_skb buffer exists, driver + * must pass it up the stack, or free it */ + xilinx_rx_post_complete (chan->common.card, chan, + skb, + &new_skb, + &pkt_error); + if (new_skb == NULL){ + continue; + } + len=wan_skb_len(new_skb); + + if (top_chan){ + wan_capture_trace_packet(chan->common.card, &top_chan->trace_info, + new_skb,TRC_INCOMING_FRM); + } + + if (chan->common.usedby == API){ + +#if defined(__LINUX__) +# ifndef CONFIG_PRODUCT_WANPIPE_GENERIC + + + /* Only for API, we insert packet status + * byte to indicate a packet error. Take + * this byte and put it in the api header */ + if (wan_skb_headroom(new_skb) >= sizeof(api_rx_hdr_t)){ + api_rx_hdr_t *rx_hdr= + (api_rx_hdr_t*)wan_skb_push(new_skb,sizeof(api_rx_hdr_t)); + memset(rx_hdr,0,sizeof(api_rx_hdr_t)); + rx_hdr->error_flag=pkt_error; + }else{ + DEBUG_EVENT("%s: Error Rx pkt headroom %d < %d\n", + chan->if_name, + wan_skb_headroom(new_skb), + sizeof(api_rx_hdr_t)); + ++chan->if_stats.rx_dropped; + wan_skb_free(new_skb); + continue; + } + new_skb->protocol = htons(PVC_PROT); + new_skb->mac.raw = wan_skb_data(new_skb); + new_skb->dev = chan->common.dev; + new_skb->pkt_type = WAN_PACKET_DATA; + +#if 0 + chan->if_stats.rx_frame_errors++; +#endif + if (wan_api_rx(chan,new_skb) != 0){ + if (net_ratelimit()){ + DEBUG_EVENT("%s: Error: Rx Socket busy!\n", + chan->if_name); + } + ++chan->if_stats.rx_dropped; + wan_skb_free(new_skb); + continue; + } +# endif +#endif + + + + }else if (chan->common.usedby == TDM_VOICE_DCHAN){ + + if (chan->tdmv_zaptel_cfg) { + +# if defined(CONFIG_PRODUCT_WANPIPE_TDM_VOICE_DCHAN) + sdla_t *card=chan->common.card; + int err; + + WAN_TDMV_CALL(rx_dchan, + (&card->wan_tdmv, + chan->tdmv_chan, + wan_skb_data(new_skb), + wan_skb_len(new_skb)), err); + +# else + DEBUG_EVENT("%s: DCHAN Rx Packet critical error TDMV not compiled!\n",card->devname); +# endif + + DEBUG_TEST("%s:%ld TDM DCHAN VOICE Rx Pkt Len=%d Chan=%d\n", + card->devname,chan->logic_ch_num,wan_skb_len(new_skb), + chan->tdmv_chan); + wan_skb_free(new_skb); + +#ifdef AFT_TDM_API_SUPPORT + } else if (chan->tdmv_chan) { + + int err; + wanpipe_tdm_api_dev_t *wp_tdm_api_dev = + &chan->wp_tdm_api_dev_idx[chan->tdmv_chan]; + + if (wan_skb_headroom(new_skb) >= sizeof(api_rx_hdr_t)){ + api_rx_hdr_t *rx_hdr = + (api_rx_hdr_t*)skb_push(new_skb,sizeof(api_rx_hdr_t)); + memset(rx_hdr,0,sizeof(api_rx_hdr_t)); + //rx_hdr->error_flag=pkt_error; + } else { + if (WAN_NET_RATELIMIT()){ + DEBUG_EVENT("%s: Error Rx pkt headroom %u < %u\n", + chan->if_name, + (u32)wan_skb_headroom(new_skb), + (u32)sizeof(api_rx_hdr_t)); + } + ++chan->if_stats.rx_dropped; + wan_skb_free(new_skb); + continue; + } + + err=wanpipe_tdm_api_rx_hdlc(wp_tdm_api_dev,new_skb); + if (err){ + ++chan->if_stats.rx_dropped; + wan_skb_free(new_skb); + continue; + } +#endif + } else { + + DEBUG_EVENT("%s: DCHAN Rx Packet critical error op not supported\n",card->devname); + ++chan->if_stats.rx_dropped; + wan_skb_free(new_skb); + continue; + } + + }else if (chan->common.usedby == TDM_VOICE){ + /* TDM VOICE doesn't operate here */ + if (WAN_NET_RATELIMIT()){ + DEBUG_EVENT("%s:%ld Critical Error: TDM VOICE Rx Pkt in BH\n", + chan->if_name, + chan->logic_ch_num); + } + ++chan->if_stats.rx_dropped; + wan_skb_free(new_skb); + continue; + + }else if (chan->common.usedby == STACK){ + + if (wanpipe_lip_rx(chan,new_skb) != 0){ + ++chan->if_stats.rx_dropped; + wan_skb_free(new_skb); + continue; + } + + }else{ + protocol_recv(chan->common.card,chan,new_skb); + } + + chan->opstats.Data_frames_Rx_count++; + chan->opstats.Data_bytes_Rx_count+=len; + chan->if_stats.rx_packets++; + chan->if_stats.rx_bytes+=len; + } + + while((skb=wan_skb_dequeue(&chan->wp_tx_complete_list)) != NULL){ + xilinx_tx_post_complete (chan->common.card,chan,skb); + wan_skb_free(skb); + } + + WAN_TASKLET_END(&chan->common.bh_task); + + if ((len=wan_skb_queue_len(&chan->wp_rx_complete_list))){ + DEBUG_TEST("%s: Triggering from bh rx=%d\n",chan->if_name,len); + WAN_TASKLET_SCHEDULE(&chan->common.bh_task); + }else if ((len=wan_skb_queue_len(&chan->wp_tx_complete_list))){ + DEBUG_TEST("%s: Triggering from bh tx=%d\n",chan->if_name,len); + WAN_TASKLET_SCHEDULE(&chan->common.bh_task); + } + + return; +} + +static int fifo_error_interrupt(sdla_t *card, u32 reg,u32 tx_status,u32 rx_status) +{ + u32 err=0; + u32 i; + private_area_t *chan; + + /* Clear HDLC pending registers */ + if (card->wandev.state != WAN_CONNECTED){ + DEBUG_TEST("%s: Warning: Ignoring Error Intr: link disc!\n", + card->devname); + return 0; + } + + if (tx_status != 0){ + for (i=0;iu.aft.num_of_time_slots;i++){ + if (wan_test_bit(i,&tx_status) && wan_test_bit(i,&card->u.aft.logic_ch_map)){ + + chan=(private_area_t*)card->u.aft.dev_to_ch_map[i]; + if (!chan){ + DEBUG_TEST("Warning: ignoring tx error intr: no dev!\n"); + continue; + } + + if (!wan_test_bit(0,&chan->up)){ + DEBUG_TEST("%s: Warning: ignoring tx error intr: dev down 0x%X UP=0x%X!\n", + wan_netif_name(chan->common.dev), + chan->common.state, + chan->ignore_modem); + continue; + } + + if (chan->common.state != WAN_CONNECTED){ + if (WAN_NET_RATELIMIT()){ + DEBUG_EVENT("%s: Warning: ignoring tx error intr: dev disc!\n", + wan_netif_name(chan->common.dev)); + } + continue; + } + + if (!chan->hdlc_eng && !wan_test_bit(0,&chan->idle_start)){ + DEBUG_TEST("%s: Warning: ignoring tx error intr: dev init error!\n", + wan_netif_name(chan->common.dev)); + if (chan->hdlc_eng){ + xilinx_tx_fifo_under_recover(card,chan); + } + continue; + } +#if 0 + if (chan->hdlc_eng && WAN_NET_RATELIMIT()){ + u32 reg_lo, reg_hi,dma_descr; + dma_descr=(chan->logic_ch_num<<4) + XILINX_TxDMA_DESCRIPTOR_LO; + card->hw_iface.bus_read_4(card->hw,dma_descr, ®_lo); + + dma_descr=(chan->logic_ch_num<<4) + XILINX_TxDMA_DESCRIPTOR_HI; + card->hw_iface.bus_read_4(card->hw,dma_descr, ®_hi); + + DEBUG_TEST("%s:%s: TX Fifo Error on LogicCh=%li TSlot=%d! CFG: 0x%08X DmaLO: 0x%08X DmaHI: 0x%08X\n", + card->devname, + chan->if_name, + chan->logic_ch_num, + i, + reg, + reg_lo, + reg_hi); + + } +#endif + xilinx_tx_fifo_under_recover(card,chan); + err=-EINVAL; + } + } + } + + + if (rx_status != 0){ + for (i=0;iu.aft.num_of_time_slots;i++){ + if (wan_test_bit(i,&rx_status) && wan_test_bit(i,&card->u.aft.logic_ch_map)){ + chan=(private_area_t*)card->u.aft.dev_to_ch_map[i]; + if (!chan){ + continue; + } + + if (!wan_test_bit(0,&chan->up)){ + DEBUG_TEST("%s: Warning: ignoring rx error intr: dev down 0x%X UP=0x%X!\n", + wan_netif_name(chan->common.dev), + chan->common.state, + chan->ignore_modem); + continue; + } + + if (chan->common.state != WAN_CONNECTED){ + DEBUG_TEST("%s: Warning: ignoring rx error intr: dev disc!\n", + wan_netif_name(chan->common.dev)); + continue; + } + + chan->if_stats.rx_fifo_errors++; + chan->errstats.Rx_overrun_err_count++; + +#if 0 + if (chan->hdlc_eng && WAN_NET_RATELIMIT()){ + u32 reg_lo, reg_hi,dma_descr; + + dma_descr=(chan->logic_ch_num<<4) + XILINX_RxDMA_DESCRIPTOR_LO; + card->hw_iface.bus_read_4(card->hw,dma_descr, ®_lo); + + dma_descr=(chan->logic_ch_num<<4) + XILINX_RxDMA_DESCRIPTOR_HI; + card->hw_iface.bus_read_4(card->hw,dma_descr, ®_hi); + + DEBUG_TEST("%s:%s: RX Fifo Error: LCh=%li TSlot=%d RxCompQ=%d RxFreeQ=%d RxDMA=%d CFG=0x%08X DmaLO: 0x%08X DmaHI: 0x%08X\n", + card->devname,chan->if_name,chan->logic_ch_num,i, + wan_skb_queue_len(&chan->wp_rx_complete_list), + wan_skb_queue_len(&chan->wp_rx_free_list), + chan->rx_dma, + reg,reg_lo, reg_hi); + } +#endif + wan_set_bit(WP_FIFO_ERROR_BIT, &chan->pkt_error); + + err=-EINVAL; + } + } + } + + return err; +} + + +static void front_end_interrupt(sdla_t *card, unsigned long reg,int lock) +{ + DEBUG_ISR("%s: front_end_interrupt!\n",card->devname); + + card->wandev.fe_iface.isr(&card->fe); + if (lock){ + wan_smp_flag_t smp_flags; + wan_spin_lock_irq(&card->wandev.lock,&smp_flags); + handle_front_end_state(card); + wan_spin_unlock_irq(&card->wandev.lock,&smp_flags); + }else{ + handle_front_end_state(card); + } + return; +} + +/**SECTION*************************************************************** + * + * HARDWARE Interrupt Handlers + * + ***********************************************************************/ + + +/*============================================================================ + * wpfw_isr + * + * Main interrupt service routine. + * Determin the interrupt received and handle it. + * + */ +static void wp_xilinx_isr (sdla_t* card) +{ + int i; + u32 reg; + u32 dma_tx_reg,dma_rx_reg,tx_fifo_status=0,rx_fifo_status=0; + private_area_t *chan; + + if (wan_test_bit(CARD_DOWN,&card->wandev.critical)){ + return; + } + + wan_set_bit(0,&card->in_isr); + +/* write_cpld(card,LED_CONTROL_REG,0x0F);*/ + + /* -----------------2/6/2003 9:02AM------------------ + * Disable all chip Interrupts (offset 0x040) + * -- "Transmit/Receive DMA Engine" interrupt disable + * -- "FiFo/Line Abort Error" interrupt disable + * --------------------------------------------------*/ + card->hw_iface.bus_read_4(card->hw,XILINX_CHIP_CFG_REG, ®); + + DEBUG_ISR("\n"); + DEBUG_ISR("%s: ISR (0x%X) = 0x%08X \n", + card->devname,XILINX_CHIP_CFG_REG,reg); + + if (wan_test_bit(SECURITY_STATUS_FLAG,®)){ + if (++card->u.aft.chip_security_cnt > AFT_MAX_CHIP_SECURITY_CNT){ + DEBUG_EVENT("%s: Critical: Chip Security Compromised: Disabling Driver!\n", + card->devname); + DEBUG_EVENT("%s: Please call Sangoma Tech Support (www.sangoma.com)!\n", + card->devname); + + port_set_state(card,WAN_DISCONNECTED); + disable_data_error_intr(card,DEVICE_DOWN); + goto isr_end; + } + }else{ + card->u.aft.chip_security_cnt=0; + } + + /* Note: If interrupts are received without pending + * flags, it usually indicates that the interrupt + * is being shared. (Check 'cat /proc/interrupts') + */ + + if (wan_test_bit(FRONT_END_INTR_ENABLE_BIT,®)){ + if (wan_test_bit(FRONT_END_INTR_FLAG,®)){ +#if defined(__LINUX__) + if (card->wandev.fe_iface.check_isr && + card->wandev.fe_iface.check_isr(&card->fe)){ + wan_set_bit(AFT_FE_INTR,&card->u.aft.port_task_cmd); + WAN_TASKQ_SCHEDULE((&card->u.aft.port_task)); + + __aft_fe_intr_ctrl(card,0); + } +#else + front_end_interrupt(card,reg,0); +#endif + } + } + + /* Test Fifo Error Interrupt, + * If set shutdown all interfaces and + * reconfigure */ + if (wan_test_bit(ERROR_INTR_ENABLE_BIT,®)){ + if (wan_test_bit(ERROR_INTR_FLAG,®)){ +#if 0 + DEBUG_EVENT("%s: ERR INTR (0x%X)\n",card->devname,reg); +#endif + card->hw_iface.bus_read_4(card->hw,XILINX_HDLC_TX_INTR_PENDING_REG,&tx_fifo_status); + card->hw_iface.bus_read_4(card->hw,XILINX_HDLC_RX_INTR_PENDING_REG,&rx_fifo_status); + + rx_fifo_status&=card->u.aft.active_ch_map; + tx_fifo_status&=card->u.aft.active_ch_map; + + fifo_error_interrupt(card,reg,tx_fifo_status,rx_fifo_status); + } + } + + /* -----------------2/6/2003 9:37AM------------------ + * Checking for Interrupt source: + * 1. Receive DMA Engine + * 2. Transmit DMA Engine + * 3. Error conditions. + * --------------------------------------------------*/ + if (wan_test_bit(GLOBAL_INTR_ENABLE_BIT,®) && + (wan_test_bit(DMA_INTR_FLAG,®) || rx_fifo_status) ){ + + + /* Receive DMA Engine */ + card->hw_iface.bus_read_4(card->hw, + XILINX_DMA_RX_INTR_PENDING_REG, + &dma_rx_reg); + +#if 0 + card->hw_iface.bus_read_4(card->hw,XILINX_HDLC_TX_INTR_PENDING_REG,&tx_fifo_status); + card->hw_iface.bus_read_4(card->hw,XILINX_HDLC_RX_INTR_PENDING_REG,&rx_fifo_status); + + rx_fifo_status&=card->u.aft.active_ch_map; + tx_fifo_status&=card->u.aft.active_ch_map; +#endif + + DEBUG_ISR("%s: DMA_RX_INTR_REG(0x%X) = 0x%X\n", + card->devname, + XILINX_DMA_RX_INTR_PENDING_REG,dma_rx_reg); + + dma_rx_reg&=card->u.aft.active_ch_map; + + if (dma_rx_reg == 0 && rx_fifo_status == 0){ + goto isr_skb_rx; + } + + for (i=0; iu.aft.num_of_time_slots ;i++){ + if ((wan_test_bit(i,&dma_rx_reg) || wan_test_bit(i,&rx_fifo_status)) && + wan_test_bit(i,&card->u.aft.logic_ch_map)){ + + chan=(private_area_t*)card->u.aft.dev_to_ch_map[i]; + if (!chan){ + DEBUG_EVENT("%s: Error: No Dev for Rx logical ch=%d\n", + card->devname,i); + continue; + } + + if (!wan_test_bit(0,&chan->up)){ + DEBUG_EVENT("%s: Error: Dev not up for Rx logical ch=%d\n", + card->devname,i); + continue; + } +#if 0 + chan->if_stats.rx_frame_errors++; +#endif + + if (wan_test_bit(i, &rx_fifo_status)){ + /* If fifo error occured, the rx descriptor + * was already handled, thus the rx pending + * should just be disregarded */ + chan->if_stats.rx_frame_errors++; + wan_set_bit(WP_FIFO_ERROR_BIT, &chan->pkt_error); + } + + DEBUG_RX("%s: RX Interrupt pend. \n", + card->devname); + +#if 0 + /* NCDEBUG */ + chan->if_stats.tx_fifo_errors=wan_skb_queue_len(&chan->wp_tx_pending_list); + chan->if_stats.rx_fifo_errors=wan_skb_queue_len(&chan->wp_rx_free_list); +#endif + + xilinx_dma_rx_complete(card,chan); + + if (chan->common.usedby == TDM_VOICE || chan->common.usedby == TDM_VOICE_API){ + +#if 0 + /* Never check interrupt here + * since it breaks channelization */ + card->hw_iface.bus_read_4(card->hw, + XILINX_DMA_TX_INTR_PENDING_REG, + &dma_tx_reg); +#endif + xilinx_dma_tx_complete(card,chan); + } + } + } +isr_skb_rx: + + /* Transmit DMA Engine */ + + card->hw_iface.bus_read_4(card->hw, + XILINX_DMA_TX_INTR_PENDING_REG, + &dma_tx_reg); + + dma_tx_reg&=card->u.aft.active_ch_map; + + DEBUG_ISR("%s: DMA_TX_INTR_REG(0x%X) = 0x%X\n", + card->devname, + XILINX_DMA_RX_INTR_PENDING_REG,dma_tx_reg); + + if (dma_tx_reg == 0){ + goto isr_skb_tx; + } + + for (i=0; iu.aft.num_of_time_slots ;i++){ + if (wan_test_bit(i,&dma_tx_reg) && wan_test_bit(i,&card->u.aft.logic_ch_map)){ + chan=(private_area_t*)card->u.aft.dev_to_ch_map[i]; + if (!chan){ + DEBUG_EVENT("%s: Error: No Dev for Tx logical ch=%d\n", + card->devname,i); + continue; + } + + if (!wan_test_bit(0,&chan->up)){ + DEBUG_EVENT("%s: Error: Dev not up for Tx logical ch=%d\n", + card->devname,i); + continue; + } + + if (chan->common.usedby == TDM_VOICE ||chan->common.usedby == TDM_VOICE_API) { + continue; + } + + DEBUG_TX(" ---- TX Interrupt pend. --\n"); + xilinx_dma_tx_complete(card,chan); + } + } + } + +isr_skb_tx: + + /* -----------------2/6/2003 10:36AM----------------- + * Finish of the interupt handler + * --------------------------------------------------*/ +isr_end: + +/* write_cpld(card,LED_CONTROL_REG,0x0E); */ + + DEBUG_ISR("---- ISR end.-------------------\n"); + wan_clear_bit(0,&card->in_isr); + return; +} + + + +/**SECTION*********************************************************** + * + * WANPIPE Debugging Interfaces + * + ********************************************************************/ + + + +/*============================================================================= + * process_udp_mgmt_pkt + * + * Process all "wanpipemon" debugger commands. This function + * performs all debugging tasks: + * + * Line Tracing + * Line/Hardware Statistics + * Protocol Statistics + * + * "wanpipemon" utility is a user-space program that + * is used to debug the WANPIPE product. + * + */ +#if 1 +static int process_udp_mgmt_pkt(sdla_t* card, netdevice_t* dev, + private_area_t* chan, int local_dev ) +{ + unsigned short buffer_length; + wan_udp_pkt_t *wan_udp_pkt; + wan_trace_t *trace_info=NULL; + + wan_udp_pkt = (wan_udp_pkt_t *)chan->udp_pkt_data; + + if (wan_atomic_read(&chan->udp_pkt_len) == 0){ + return -ENODEV; + } + + trace_info=&chan->trace_info; + wan_udp_pkt = (wan_udp_pkt_t *)chan->udp_pkt_data; + + { + + netskb_t *skb; + + wan_udp_pkt->wan_udp_opp_flag = 0; + + switch(wan_udp_pkt->wan_udp_command) { + + case READ_CONFIGURATION: + wan_udp_pkt->wan_udp_return_code = 0; + wan_udp_pkt->wan_udp_data_len=0; + break; + + + case READ_CODE_VERSION: + wan_udp_pkt->wan_udp_return_code = 0; + card->hw_iface.getcfg(card->hw, SDLA_COREREV, &wan_udp_pkt->wan_udp_data[0]); + wan_udp_pkt->wan_udp_data_len=1; + break; + + case AFT_LINK_STATUS: + wan_udp_pkt->wan_udp_return_code = 0; + if (card->wandev.state == WAN_CONNECTED){ + wan_udp_pkt->wan_udp_data[0]=1; + }else{ + wan_udp_pkt->wan_udp_data[0]=0; + } + wan_udp_pkt->wan_udp_data_len=1; + break; + + case AFT_MODEM_STATUS: + wan_udp_pkt->wan_udp_return_code = 0; + if (card->wandev.state == WAN_CONNECTED){ + wan_udp_pkt->wan_udp_data[0]=0x28; + }else{ + wan_udp_pkt->wan_udp_data[0]=0; + } + wan_udp_pkt->wan_udp_data_len=1; + break; + + + case READ_OPERATIONAL_STATS: + wan_udp_pkt->wan_udp_return_code = 0; + memcpy(wan_udp_pkt->wan_udp_data,&chan->opstats,sizeof(aft_op_stats_t)); + wan_udp_pkt->wan_udp_data_len=sizeof(aft_op_stats_t); + break; + + case FLUSH_OPERATIONAL_STATS: + wan_udp_pkt->wan_udp_return_code = 0; + memset(&chan->opstats,0,sizeof(aft_op_stats_t)); + wan_udp_pkt->wan_udp_data_len=0; + break; + + case READ_COMMS_ERROR_STATS: + wan_udp_pkt->wan_udp_return_code = 0; + memcpy(wan_udp_pkt->wan_udp_data,&chan->errstats,sizeof(aft_comm_err_stats_t)); + wan_udp_pkt->wan_udp_data_len=sizeof(aft_comm_err_stats_t); + break; + + case FLUSH_COMMS_ERROR_STATS: + wan_udp_pkt->wan_udp_return_code = 0; + memset(&chan->errstats,0,sizeof(aft_comm_err_stats_t)); + wan_udp_pkt->wan_udp_data_len=0; + break; + + + case ENABLE_TRACING: + + wan_udp_pkt->wan_udp_return_code = WAN_CMD_OK; + wan_udp_pkt->wan_udp_data_len = 0; + + if (!wan_test_bit(0,&trace_info->tracing_enabled)){ + + trace_info->trace_timeout = SYSTEM_TICKS; + + wan_trace_purge(trace_info); + + if (wan_udp_pkt->wan_udp_data[0] == 0){ + wan_clear_bit(1,&trace_info->tracing_enabled); + DEBUG_UDP("%s: ADSL L3 trace enabled!\n", + card->devname); + }else if (wan_udp_pkt->wan_udp_data[0] == 1){ + wan_clear_bit(2,&trace_info->tracing_enabled); + wan_set_bit(1,&trace_info->tracing_enabled); + DEBUG_UDP("%s: ADSL L2 trace enabled!\n", + card->devname); + }else{ + wan_clear_bit(1,&trace_info->tracing_enabled); + wan_set_bit(2,&trace_info->tracing_enabled); + DEBUG_UDP("%s: ADSL L1 trace enabled!\n", + card->devname); + } + wan_set_bit (0,&trace_info->tracing_enabled); + + }else{ + DEBUG_EVENT("%s: Error: AFT trace running!\n", + card->devname); + wan_udp_pkt->wan_udp_return_code = 2; + } + + break; + + case DISABLE_TRACING: + + wan_udp_pkt->wan_udp_return_code = WAN_CMD_OK; + + if(wan_test_bit(0,&trace_info->tracing_enabled)) { + + wan_clear_bit(0,&trace_info->tracing_enabled); + wan_clear_bit(1,&trace_info->tracing_enabled); + wan_clear_bit(2,&trace_info->tracing_enabled); + + wan_trace_purge(trace_info); + + DEBUG_UDP("%s: Disabling AFT trace\n", + card->devname); + + }else{ + /* set return code to line trace already + disabled */ + wan_udp_pkt->wan_udp_return_code = 1; + } + + break; + + case GET_TRACE_INFO: + + if(wan_test_bit(0,&trace_info->tracing_enabled)){ + trace_info->trace_timeout = SYSTEM_TICKS; + }else{ + DEBUG_EVENT("%s: Error AFT trace not enabled\n", + card->devname); + /* set return code */ + wan_udp_pkt->wan_udp_return_code = 1; + break; + } + + buffer_length = 0; + wan_udp_pkt->wan_udp_atm_num_frames = 0; + wan_udp_pkt->wan_udp_atm_ismoredata = 0; + +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) + while (wan_skb_queue_len(&trace_info->trace_queue)){ + WAN_IFQ_POLL(&trace_info->trace_queue, skb); + if (skb == NULL){ + DEBUG_EVENT("%s: No more trace packets in trace queue!\n", + card->devname); + break; + } + if ((WAN_MAX_DATA_SIZE - buffer_length) < skb->m_pkthdr.len){ + /* indicate there are more frames on board & exit */ + wan_udp_pkt->wan_udp_atm_ismoredata = 0x01; + break; + } + + m_copydata(skb, + 0, + skb->m_pkthdr.len, + &wan_udp_pkt->wan_udp_data[buffer_length]); + buffer_length += skb->m_pkthdr.len; + WAN_IFQ_DEQUEUE(&trace_info->trace_queue, skb); + if (skb){ + wan_skb_free(skb); + } + wan_udp_pkt->wan_udp_atm_num_frames++; + } +#elif defined(__LINUX__) + while ((skb=skb_dequeue(&trace_info->trace_queue)) != NULL){ + + if((MAX_TRACE_BUFFER - buffer_length) < wan_skb_len(skb)){ + /* indicate there are more frames on board & exit */ + wan_udp_pkt->wan_udp_atm_ismoredata = 0x01; + if (buffer_length != 0){ + wan_skb_queue_head(&trace_info->trace_queue, skb); + }else{ + /* If rx buffer length is greater than the + * whole udp buffer copy only the trace + * header and drop the trace packet */ + + memcpy(&wan_udp_pkt->wan_udp_atm_data[buffer_length], + wan_skb_data(skb), + sizeof(wan_trace_pkt_t)); + + buffer_length = sizeof(wan_trace_pkt_t); + wan_udp_pkt->wan_udp_atm_num_frames++; + wan_skb_free(skb); + } + break; + } + + memcpy(&wan_udp_pkt->wan_udp_atm_data[buffer_length], + wan_skb_data(skb), + wan_skb_len(skb)); + + buffer_length += wan_skb_len(skb); + wan_skb_free(skb); + wan_udp_pkt->wan_udp_atm_num_frames++; + } +#endif + /* set the data length and return code */ + wan_udp_pkt->wan_udp_data_len = buffer_length; + wan_udp_pkt->wan_udp_return_code = WAN_CMD_OK; + break; + + case ROUTER_UP_TIME: + wan_getcurrenttime(&chan->router_up_time, NULL); + chan->router_up_time -= chan->router_start_time; + *(unsigned long *)&wan_udp_pkt->wan_udp_data = + chan->router_up_time; + wan_udp_pkt->wan_udp_data_len = sizeof(unsigned long); + wan_udp_pkt->wan_udp_return_code = 0; + break; + + case WAN_GET_MEDIA_TYPE: + case WAN_FE_GET_STAT: + case WAN_FE_SET_LB_MODE: + case WAN_FE_FLUSH_PMON: + case WAN_FE_GET_CFG: + case WAN_FE_SET_DEBUG_MODE: + case WAN_FE_TX_MODE: + if (IS_TE1_CARD(card)){ + wan_smp_flag_t smp_flags; + card->hw_iface.hw_lock(card->hw,&smp_flags); + card->wandev.fe_iface.process_udp( + &card->fe, + &wan_udp_pkt->wan_udp_cmd, + &wan_udp_pkt->wan_udp_data[0]); + card->hw_iface.hw_unlock(card->hw,&smp_flags); + }else{ + if (wan_udp_pkt->wan_udp_command == WAN_GET_MEDIA_TYPE){ + wan_udp_pkt->wan_udp_data_len = sizeof(unsigned char); + wan_udp_pkt->wan_udp_return_code = CMD_OK; + }else{ + wan_udp_pkt->wan_udp_return_code = WAN_UDP_INVALID_CMD; + } + } + break; + + + + case WAN_GET_PROTOCOL: + wan_udp_pkt->wan_udp_aft_num_frames = card->wandev.config_id; + wan_udp_pkt->wan_udp_return_code = CMD_OK; + wan_udp_pkt->wan_udp_data_len = 1; + break; + + case WAN_GET_PLATFORM: + wan_udp_pkt->wan_udp_data[0] = WAN_PLATFORM_ID; + wan_udp_pkt->wan_udp_return_code = CMD_OK; + wan_udp_pkt->wan_udp_data_len = 1; + break; + + case WAN_GET_MASTER_DEV_NAME: + wan_udp_pkt->wan_udp_data_len = 0; + wan_udp_pkt->wan_udp_return_code = 0xCD; + break; + + default: + wan_udp_pkt->wan_udp_data_len = 0; + wan_udp_pkt->wan_udp_return_code = 0xCD; + + if (WAN_NET_RATELIMIT()){ + DEBUG_EVENT( + "%s: Warning, Illegal UDP command attempted from network: %x\n", + card->devname,wan_udp_pkt->wan_udp_command); + } + break; + } /* end of switch */ + } /* end of else */ + + /* Fill UDP TTL */ + wan_udp_pkt->wan_ip_ttl= card->wandev.ttl; + + wan_udp_pkt->wan_udp_request_reply = UDPMGMT_REPLY; + return 1; + +} +#endif + + + +/**SECTION************************************************************* + * + * TASK Functions and Triggers + * + **********************************************************************/ + + +/*============================================================================ + * port_set_state + * + * Set PORT state. + * + */ +static void port_set_state (sdla_t *card, int state) +{ + struct wan_dev_le *devle; + netdevice_t *dev; + + if (card->wandev.state != state) + { + switch (state) + { + case WAN_CONNECTED: + DEBUG_TEST( "%s: Link connected!\n", + card->devname); + break; + + case WAN_CONNECTING: + DEBUG_TEST( "%s: Link connecting...\n", + card->devname); + break; + + case WAN_DISCONNECTED: + DEBUG_TEST( "%s: Link disconnected!\n", + card->devname); + break; + } + + card->wandev.state = state; + WAN_LIST_FOREACH(devle, &card->wandev.dev_head, dev_link){ + dev = WAN_DEVLE2DEV(devle); + if (dev){ + set_chan_state(card, dev, state); + } + } + } +} + +/*============================================================ + * handle_front_end_state + * + * Front end state indicates the physical medium that + * the Z80 backend connects to. + * + * S514-1/2/3: V32/RS232/FT1 Front End + * Front end state is determined via + * Modem/Status. + * S514-4/5/7/8: 56K/T1/E1 Front End + * Front end state is determined via + * link status interrupt received + * from the front end hardware. + * + * If the front end state handler is enabed by the + * user. The interface state will follow the + * front end state. I.E. If the front end goes down + * the protocol and interface will be declared down. + * + * If the front end state is UP, then the interface + * and protocol will be up ONLY if the protocol is + * also UP. + * + * Therefore, we must have three state variables + * 1. Front End State (card->wandev.front_end_status) + * 2. Protocol State (card->wandev.state) + * 3. Interface State (dev->flags & IFF_UP) + * + */ + +static void handle_front_end_state(void *card_id) +{ + sdla_t* card = (sdla_t*)card_id; + + if (card->wandev.ignore_front_end_status == WANOPT_YES){ + return; + } + + if (card->fe.fe_status == FE_CONNECTED){ + + if (!wan_test_bit(0,&card->u.aft.comm_enabled)){ + port_set_state(card,WAN_CONNECTED); +#if defined(CONFIG_PRODUCT_WANPIPE_TDM_VOICE) + if (card->wan_tdmv.sc){ + int err; + WAN_TDMV_CALL(state, (card, WAN_CONNECTED), err); + } +#endif + enable_data_error_intr(card); + + aft_red_led_ctrl(card, AFT_LED_OFF); + card->wandev.fe_iface.led_ctrl(&card->fe, AFT_LED_ON); + + if (card->u.aft.cfg.rbs){ + if (card->wandev.fe_iface.set_fe_sigctrl){ + card->wandev.fe_iface.set_fe_sigctrl( + &card->fe, + WAN_TE_SIG_INTR); + } + } + + } else if (card->wandev.state != WAN_CONNECTED && + wan_test_bit(0,&card->u.aft.comm_enabled)){ + + disable_data_error_intr(card,LINK_DOWN); + +#if defined(CONFIG_PRODUCT_WANPIPE_TDM_VOICE) + if (card->wan_tdmv.sc){ + int err; + WAN_TDMV_CALL(state, (card, WAN_CONNECTED), err); + } +#endif + enable_data_error_intr(card); + card->wandev.state = WAN_CONNECTED; + aft_red_led_ctrl(card, AFT_LED_OFF); + card->wandev.fe_iface.led_ctrl(&card->fe, AFT_LED_ON); + + DEBUG_EVENT("%s: AFT Front End Restart!\n", + card->devname); + } + + }else{ + + if (card->u.aft.cfg.tdmv_span_no){ + /* If running in TDMV voice mode, just note + * that state went down, but keep the + * connection up */ + card->wandev.state = WAN_DISCONNECTED; + aft_red_led_ctrl(card, AFT_LED_ON); + card->wandev.fe_iface.led_ctrl(&card->fe, AFT_LED_OFF); +#if defined(CONFIG_PRODUCT_WANPIPE_TDM_VOICE) + if (card->wan_tdmv.sc){ + int err; + WAN_TDMV_CALL(state, (card, WAN_DISCONNECTED), err); + } +#endif + return; + } + + if (wan_test_bit(0,&card->u.aft.comm_enabled) || + card->wandev.state != WAN_DISCONNECTED){ + + disable_data_error_intr(card,LINK_DOWN); + port_set_state(card,WAN_DISCONNECTED); +#if defined(CONFIG_PRODUCT_WANPIPE_TDM_VOICE) + if (card->wan_tdmv.sc){ + int err; + WAN_TDMV_CALL(state, (card, WAN_DISCONNECTED), err); + } +#endif + aft_red_led_ctrl(card, AFT_LED_ON); + card->wandev.fe_iface.led_ctrl(&card->fe, AFT_LED_OFF); + } + } + return; +} + +static unsigned char read_cpld(sdla_t *card, unsigned short cpld_off) +{ + + u16 org_off; + u8 tmp; + + cpld_off &= ~BIT_DEV_ADDR_CLEAR; + cpld_off |= BIT_DEV_ADDR_CPLD; + + /*Save the current address. */ + card->hw_iface.bus_read_2(card->hw, + XILINX_MCPU_INTERFACE_ADDR, + &org_off); + + card->hw_iface.bus_write_2(card->hw, + XILINX_MCPU_INTERFACE_ADDR, + cpld_off); + + card->hw_iface.bus_read_1(card->hw,XILINX_MCPU_INTERFACE, &tmp); + + /*Restore original address */ + card->hw_iface.bus_write_2(card->hw, + XILINX_MCPU_INTERFACE_ADDR, + org_off); + return tmp; + + +} + +static unsigned char write_cpld(sdla_t *card, unsigned short off,unsigned char data) +{ + u16 org_off; + + off &= ~BIT_DEV_ADDR_CLEAR; + off |= BIT_DEV_ADDR_CPLD; + + /* Save the current original address */ + card->hw_iface.bus_read_2(card->hw, + XILINX_MCPU_INTERFACE_ADDR, + &org_off); + + card->hw_iface.bus_write_2(card->hw, + XILINX_MCPU_INTERFACE_ADDR, + off); + + /* This delay is required to avoid bridge optimization + * (combining two writes together)*/ + WP_DELAY(5); + + card->hw_iface.bus_write_1(card->hw, + XILINX_MCPU_INTERFACE, + data); + + /* This delay is required to avoid bridge optimization + * (combining two writes together)*/ + WP_DELAY(5); + + /* Restore the original address */ + card->hw_iface.bus_write_2(card->hw, + XILINX_MCPU_INTERFACE_ADDR, + org_off); + return 0; +} + +static int write_front_end_reg (void* card1, ...) +{ + va_list args; + sdla_t* card = (sdla_t*)card1; + u16 off; + u8 value; + u8 qaccess = card->wandev.state == WAN_CONNECTED ? 1 : 0; + + va_start(args, card1); + off = (u16)va_arg(args, int); + value = (u8)va_arg(args, int); + va_end(args); + + off &= ~BIT_DEV_ADDR_CLEAR; + card->hw_iface.bus_write_2(card->hw,XILINX_MCPU_INTERFACE_ADDR, off); + /* AF: Sep 10, 2003 + * IMPORTANT + * This delays are required to avoid bridge optimization + * (combining two writes together) + */ + if (!qaccess){ + WP_DELAY(5); + } + card->hw_iface.bus_write_1(card->hw,XILINX_MCPU_INTERFACE, value); + if (!qaccess){ + WP_DELAY(5); + } + + return 0; +} + + +/*============================================================================ + * Read TE1/56K Front end registers + */ +static unsigned char read_front_end_reg (void* card1, ...) +{ + va_list args; + sdla_t* card = (sdla_t*)card1; + u16 off; + u8 tmp; + u8 qaccess = card->wandev.state == WAN_CONNECTED ? 1 : 0; + + va_start(args, card1); + off = (u16)va_arg(args, int); + va_end(args); + + off &= ~BIT_DEV_ADDR_CLEAR; + card->hw_iface.bus_write_2(card->hw, XILINX_MCPU_INTERFACE_ADDR, off); + card->hw_iface.bus_read_1(card->hw,XILINX_MCPU_INTERFACE, &tmp); + + if (!qaccess){ + WP_DELAY(5); + } + + return tmp; +} + +static int xilinx_read(sdla_t *card, wan_cmd_api_t *api_cmd) +{ + if (api_cmd->offset <= 0x3C){ + card->hw_iface.pci_read_config_dword(card->hw, + api_cmd->offset, + (u32*)&api_cmd->data[0]); + api_cmd->len=4; + + }else{ + card->hw_iface.peek(card->hw, api_cmd->offset, &api_cmd->data[0], api_cmd->len); + } + +#ifdef DEB_XILINX + DEBUG_EVENT("%s: Reading Bar%d Offset=0x%X Len=%d\n", + card->devname,api_cmd->bar,api_cmd->offset,api_cmd->len); +#endif + + return 0; +} + +static int xilinx_fe_read(sdla_t *card, wan_cmd_api_t *api_cmd) +{ + wan_smp_flag_t smp_flags; + + card->hw_iface.hw_lock(card->hw,&smp_flags); + api_cmd->data[0] = (u8)read_front_end_reg (card, api_cmd->offset); + card->hw_iface.hw_unlock(card->hw,&smp_flags); + +#ifdef DEB_XILINX + DEBUG_EVENT("%s: Reading Bar%d Offset=0x%X Len=%d\n", + card->devname,api_cmd->bar,api_cmd->offset,api_cmd->len); +#endif + return 0; +} + + +static int xilinx_write(sdla_t *card, wan_cmd_api_t *api_cmd) +{ +#ifdef DEB_XILINX + DEBUG_EVENT("%s: Writting Bar%d Offset=0x%X Len=%d\n", + card->devname, + api_cmd->bar,api_cmd->offset,api_cmd->len); +#endif + + if (api_cmd->len == 1){ + card->hw_iface.bus_write_1( + card->hw, + api_cmd->offset, + (u8)api_cmd->data[0]); + }else if (api_cmd->len == 2){ + card->hw_iface.bus_write_2( + card->hw, + api_cmd->offset, + *(u16*)&api_cmd->data[0]); + }else if (api_cmd->len == 4){ + card->hw_iface.bus_write_4( + card->hw, + api_cmd->offset, + *(u32*)&api_cmd->data[0]); + }else{ + card->hw_iface.poke( + card->hw, + api_cmd->offset, + &api_cmd->data[0], + api_cmd->len); + } + + return 0; +} + + +static int xilinx_fe_write(sdla_t *card, wan_cmd_api_t *api_cmd) +{ + wan_smp_flag_t smp_flags; + +#ifdef DEB_XILINX + DEBUG_EVENT("%s: Writting Bar%d Offset=0x%X Len=%d\n", + card->devname, + api_cmd->bar,api_cmd->offset,api_cmd->len); +#endif + + card->hw_iface.hw_lock(card->hw,&smp_flags); + write_front_end_reg (card, api_cmd->offset, (u8)api_cmd->data[0]); + card->hw_iface.hw_unlock(card->hw,&smp_flags); + + return 0; +} + + +static int xilinx_write_bios(sdla_t *card, wan_cmd_api_t *api_cmd) +{ +#ifdef DEB_XILINX + DEBUG_EVENT("Setting PCI 0xX=0x%08lX 0x3C=0x%08X\n", + (card->wandev.S514_cpu_no[0] == SDLA_CPU_A) ? 0x10 : 0x14, + card->u.aft.bar,card->wandev.irq); +#endif + card->hw_iface.pci_write_config_dword(card->hw, + (card->wandev.S514_cpu_no[0] == SDLA_CPU_A) ? 0x10 : 0x14, + card->u.aft.bar); + card->hw_iface.pci_write_config_dword(card->hw, 0x3C, card->wandev.irq); + card->hw_iface.pci_write_config_dword(card->hw, 0x0C, 0x0000ff00); + + return 0; +} + +static int aft_devel_ioctl(sdla_t *card, struct ifreq *ifr) +{ + wan_cmd_api_t api_cmd; + int err = -EINVAL; + + if (!ifr || !ifr->ifr_data){ + DEBUG_EVENT("%s: Error: No ifr or ifr_data\n",__FUNCTION__); + return -EINVAL; + } + + if (WAN_COPY_FROM_USER(&api_cmd,ifr->ifr_data,sizeof(wan_cmd_api_t))){ + return -EFAULT; + } + + switch(api_cmd.cmd){ + case SIOC_WAN_READ_REG: + err=xilinx_read(card,&api_cmd); + break; + + case SIOC_WAN_WRITE_REG: + err=xilinx_write(card,&api_cmd); + break; + + case SIOC_WAN_FE_READ_REG: + err=xilinx_fe_read(card,&api_cmd); + break; + + case SIOC_WAN_FE_WRITE_REG: + err=xilinx_fe_write(card,&api_cmd); + break; + + case SIOC_WAN_SET_PCI_BIOS: + err=xilinx_write_bios(card,&api_cmd); + break; + } + if (WAN_COPY_TO_USER(ifr->ifr_data,&api_cmd,sizeof(wan_cmd_api_t))){ + return -EFAULT; + } + return err; +} + + +/*========================================= + * enable_data_error_intr + * + * Description: + * + * Run only after the front end comes + * up from down state. + * + * Clean the DMA Tx/Rx pending interrupts. + * (Ignore since we will reconfigure + * all dma descriptors. DMA controler + * was already disabled on link down) + * + * For all channels clean Tx/Rx Fifo + * + * Enable DMA controler + * (This starts the fifo cleaning + * process) + * + * For all channels reprogram Tx/Rx DMA + * descriptors. + * + * Clean the Tx/Rx Error pending interrupts. + * (Since dma fifo's are now empty) + * + * Enable global DMA and Error interrutps. + * + */ + +static void enable_data_error_intr(sdla_t *card) +{ + u32 reg; + int i; + + DEBUG_CFG("%s: !!!\n",__FUNCTION__); + + /* Clean Tx/Rx DMA interrupts */ + + card->hw_iface.bus_read_4(card->hw, + XILINX_DMA_RX_INTR_PENDING_REG, ®); + card->hw_iface.bus_read_4(card->hw, + XILINX_DMA_TX_INTR_PENDING_REG, ®); + + for (i=0; iu.aft.num_of_time_slots;i++){ + private_area_t *chan; + + if (!wan_test_bit(i,&card->u.aft.logic_ch_map)){ + continue; + } + + chan=(private_area_t*)card->u.aft.dev_to_ch_map[i]; + if (!chan){ + continue; + } + + if (!wan_test_bit(0,&chan->up)){ + continue; + } + + DEBUG_TEST("%s: Init interface fifo no wait %s\n", + __FUNCTION__,chan->if_name); + + xilinx_init_rx_dev_fifo(card, chan, WP_NO_WAIT); + xilinx_init_tx_dev_fifo(card, chan, WP_NO_WAIT); + + + if (wan_test_bit(0,&chan->tdmv_sync)){ + channel_timeslot_sync_ctrl(card,chan,1); + } + } + + /* Enable DMA controler, in order to start the + * fifo cleaning */ + card->hw_iface.bus_read_4(card->hw,XILINX_DMA_CONTROL_REG,®); + wan_set_bit(DMA_ENGINE_ENABLE_BIT,®); + card->hw_iface.bus_write_4(card->hw,XILINX_DMA_CONTROL_REG,reg); + + + /* For all channels clean Tx/Rx fifos */ + for (i=0; iu.aft.num_of_time_slots;i++){ + private_area_t *chan; + + if (!wan_test_bit(i,&card->u.aft.logic_ch_map)){ + continue; + } + + chan=(private_area_t*)card->u.aft.dev_to_ch_map[i]; + if (!chan){ + continue; + } + + if (!wan_test_bit(0,&chan->up)){ + continue; + } + + DEBUG_TEST("%s: Init interface fifo %s\n",__FUNCTION__,chan->if_name); + + xilinx_init_rx_dev_fifo(card, chan, WP_WAIT); + xilinx_init_tx_dev_fifo(card, chan, WP_WAIT); + + DEBUG_TEST("%s: Clearing Fifo and idle_flag %s\n", + card->devname,chan->if_name); + wan_clear_bit(0,&chan->idle_start); + } + + /* For all channels, reprogram Tx/Rx DMA descriptors. + * For Tx also make sure that the BUSY flag is clear + * and previoulsy Tx packet is deallocated */ + + for (i=0; iu.aft.num_of_time_slots;i++){ + private_area_t *chan; + netskb_t *skb; + + if (!wan_test_bit(i,&card->u.aft.logic_ch_map)){ + continue; + } + + chan=(private_area_t*)card->u.aft.dev_to_ch_map[i]; + if (!chan){ + continue; + } + + if (!wan_test_bit(0,&chan->up)){ + continue; + } + + DEBUG_TEST("%s: Init interface %s\n",__FUNCTION__,chan->if_name); + + if (chan->rx_dma_skb){ + wp_rx_element_t *rx_el; + netskb_t *skb=chan->rx_dma_skb; + DEBUG_TEST("%s: Clearing RX DMA Pending buffer \n",__FUNCTION__); + + chan->rx_dma_skb=NULL; + rx_el=(wp_rx_element_t *)wan_skb_data(skb); + + card->hw_iface.pci_unmap_dma(card->hw, + rx_el->dma_addr, + chan->dma_mru, + PCI_DMA_FROMDEVICE); + + aft_init_requeue_free_skb(chan, skb); + } + + while((skb=wan_skb_dequeue(&chan->wp_rx_complete_list)) != NULL){ + aft_init_requeue_free_skb(chan, skb); + chan->if_stats.rx_errors++; + } + + if (chan->common.usedby == TDM_VOICE || chan->common.usedby == TDM_VOICE_API){ + while((skb=wan_skb_dequeue(&chan->wp_tx_pending_list)) != NULL){ + aft_init_requeue_free_skb(chan, skb); + chan->if_stats.rx_errors++; + } + } + + xilinx_dma_rx(card,chan); + + if (chan->tx_dma_addr && chan->tx_dma_len){ + DEBUG_TEST("%s: Clearing TX DMA Pending buffer \n",__FUNCTION__); + aft_unmap_tx_dma(card,chan); + } + + + if (chan->tx_dma_skb){ + if (chan->common.usedby == TDM_VOICE || chan->common.usedby == TDM_VOICE_API){ + aft_init_requeue_free_skb(chan, chan->tx_dma_skb); + }else{ + wan_skb_free(chan->tx_dma_skb); + } + chan->tx_dma_skb=NULL; + } + + wan_clear_bit(TX_BUSY,&chan->dma_status); + wan_clear_bit(0,&chan->idle_start); + + if (!chan->hdlc_eng){ + int err=xilinx_dma_tx(card,chan); + if (err){ + DEBUG_EVENT("%s: DMA Tx failed err=%i\n", + chan->if_name,err); + } + } + + DEBUG_TEST("%s: Clearing Fifo and idle_flag %s\n", + card->devname,chan->if_name); + + } + + + /* Clean Tx/Rx Error interrupts, since fifos are now + * empty, and Tx fifo may generate an underrun which + * we want to ignore :) */ + + card->hw_iface.bus_read_4(card->hw, + XILINX_HDLC_RX_INTR_PENDING_REG, ®); + card->hw_iface.bus_read_4(card->hw, + XILINX_HDLC_TX_INTR_PENDING_REG, ®); + + + /* Enable Global DMA and Error Interrupts */ + reg=0; + card->hw_iface.bus_read_4(card->hw,XILINX_CHIP_CFG_REG,®); + wan_set_bit(GLOBAL_INTR_ENABLE_BIT,®); + wan_set_bit(ERROR_INTR_ENABLE_BIT,®); + + card->hw_iface.bus_write_4(card->hw,XILINX_CHIP_CFG_REG,reg); + + if (wan_test_bit(0,&card->u.aft.tdmv_sync)){ + rx_chan_timeslot_sync_ctrl(card,1); + } + + wan_set_bit(0,&card->u.aft.comm_enabled); + + DEBUG_TEST("%s: END !!!\n",__FUNCTION__); + +} + +static void disable_data_error_intr(sdla_t *card, enum wp_device_down_states event) +{ + u32 reg; + + DEBUG_TEST("%s: !!!!!!!\n",__FUNCTION__); + + card->hw_iface.bus_read_4(card->hw,XILINX_CHIP_CFG_REG,®); + wan_clear_bit(GLOBAL_INTR_ENABLE_BIT,®); + wan_clear_bit(ERROR_INTR_ENABLE_BIT,®); + if (event==DEVICE_DOWN){ + wan_clear_bit(FRONT_END_INTR_ENABLE_BIT,®); + } + card->hw_iface.bus_write_4(card->hw,XILINX_CHIP_CFG_REG,reg); + + card->hw_iface.bus_read_4(card->hw,XILINX_DMA_CONTROL_REG,®); + wan_clear_bit(DMA_ENGINE_ENABLE_BIT,®); + card->hw_iface.bus_write_4(card->hw,XILINX_DMA_CONTROL_REG,reg); + + if (event==DEVICE_DOWN){ + wan_set_bit(CARD_DOWN,&card->wandev.critical); + } + + wan_clear_bit(0,&card->u.aft.comm_enabled); +} + +static void xilinx_init_tx_dma_descr(sdla_t *card, private_area_t *chan) +{ + u32 dma_descr; + u32 reg=0; + + dma_descr=(chan->logic_ch_num<<4) + XILINX_TxDMA_DESCRIPTOR_HI; + card->hw_iface.bus_write_4(card->hw,dma_descr, reg); +} + + + +/*============================================================================ + * Update communications error and general packet statistics. + */ +static int update_comms_stats(sdla_t* card) +{ + /* 1. On the first timer interrupt, update T1/E1 alarms + * and PMON counters (only for T1/E1 card) (TE1) + */ + + /* TE1 Update T1/E1 alarms */ + if (IS_TE1_CARD(card)) { + wan_smp_flag_t smp_flags; + card->hw_iface.hw_lock(card->hw,&smp_flags); + card->wandev.fe_iface.read_alarm(&card->fe, 0); + /* TE1 Update T1/E1 perfomance counters */ + card->wandev.fe_iface.read_pmon(&card->fe, 0); + card->hw_iface.hw_unlock(card->hw,&smp_flags); + } + + return 0; +} + +#if 0 +static void xilinx_rx_fifo_over_recover(sdla_t *card, private_area_t *chan) +{ + + u32 reg=0; + u32 dma_descr; + netskb_t *skb; + + /* Initialize Tx DMA descriptor: Stop DMA */ + dma_descr=(chan->logic_ch_num<<4) + XILINX_RxDMA_DESCRIPTOR_HI; + card->hw_iface.bus_write_4(card->hw,dma_descr, reg); + + /* Clean the RX FIFO */ + rx_chan_timeslot_sync_ctrl(card,0); + xilinx_init_rx_dev_fifo(card, chan, WP_WAIT); + + if ((skb=chan->rx_dma_skb) != NULL){ + wp_rx_element_t *rx_el; + rx_el=(wp_rx_element_t *)wan_skb_data(chan->rx_dma_skb); + + card->hw_iface.pci_unmap_dma(card->hw, + rx_el->dma_addr, + chan->dma_mru, + PCI_DMA_FROMDEVICE); + + DEBUG_RX("%s:%s: RX HI=0x%X LO=0x%X DMA=0x%lX\n", + __FUNCTION__,chan->if_name,rx_el->reg,rx_el->align,rx_el->dma_addr); + + chan->rx_dma_skb=NULL; + aft_init_requeue_free_skb(chan, skb); + } + + wan_clear_bit(0,&chan->rx_dma); + aft_dma_rx(card,chan); + rx_chan_timeslot_sync_ctrl(card,1); + +} +#endif + +static void xilinx_tx_fifo_under_recover (sdla_t *card, private_area_t *chan) +{ + DEBUG_TEST("%s:%s: Tx Fifo Recovery \n",card->devname,chan->if_name); + + if (chan->common.usedby == TDM_VOICE || chan->common.usedby == TDM_VOICE_API){ + return; + } + +#if 0 +/* FIFO Already empty no need to clean the fifo */ + if (chan->hdlc_eng){ + /* Initialize Tx DMA descriptor: Stop DMA */ + dma_descr=(chan->logic_ch_num<<4) + XILINX_TxDMA_DESCRIPTOR_HI; + card->hw_iface.bus_write_4(card->hw,dma_descr, reg); + + /* Clean the TX FIFO */ + xilinx_init_tx_dev_fifo(card, chan, WP_WAIT); + } +#endif + + if (chan->tx_dma_addr && chan->tx_dma_len){ + aft_unmap_tx_dma(card,chan); + } + + + /* Requeue the current tx packet, for + * re-transmission */ + if (chan->tx_dma_skb){ + wan_skb_queue_head(&chan->wp_tx_pending_list, chan->tx_dma_skb); + chan->tx_dma_skb=NULL; + } + + /* Wake up the stack, because tx dma interrupt + * failed */ +#if defined(__LINUX__) + if (WAN_NETIF_QUEUE_STOPPED(chan->common.dev)){ + WAN_NETIF_WAKE_QUEUE(chan->common.dev); + if (chan->common.usedby == API){ +#ifndef CONFIG_PRODUCT_WANPIPE_GENERIC + wan_wakeup_api(chan); +#endif + } + } +#endif + + if (!chan->hdlc_eng){ + if (wan_test_bit(0,&chan->idle_start)){ + ++chan->if_stats.tx_fifo_errors; + } + }else{ + ++chan->if_stats.tx_fifo_errors; + } + + DEBUG_TEST("%s:%s: Tx Fifo Recovery: Restarting Transmission \n", + card->devname,chan->if_name); + + /* Re-start transmission */ + wan_clear_bit(TX_BUSY,&chan->dma_status); + + xilinx_dma_tx(card,chan); +} + +static int xilinx_write_ctrl_hdlc(sdla_t *card, u32 timeslot, u8 reg_off, u32 data) +{ + u32 reg; + u32 ts_orig=timeslot; + unsigned long timeout=SYSTEM_TICKS; + + if (timeslot == 0){ + timeslot=card->u.aft.num_of_time_slots-2; + }else if (timeslot == 1){ + timeslot=card->u.aft.num_of_time_slots-1; + }else{ + timeslot-=2; + } + + timeslot=timeslot<hw_iface.bus_read_4(card->hw,XILINX_TIMESLOT_HDLC_CHAN_REG,®); + reg&=XILINX_CURRENT_TIMESLOT_MASK; + + if (reg == timeslot){ + card->hw_iface.bus_write_4(card->hw,reg_off,data); + return 0; + } + + if ((SYSTEM_TICKS-timeout) > 1){ + DEBUG_EVENT("%s: Error: Access to timeslot %d timed out!\n", + card->devname,ts_orig); + return -EIO; + } + } + + return -EIO; +} + +static int set_chan_state(sdla_t* card, netdevice_t* dev, int state) +{ + private_area_t *chan = wan_netif_priv(dev); + private_area_t *ch_ptr; + + if (chan == NULL){ + /* This is case can happened for WANPIPE (LITE) */ + return 0; + } + + chan->common.state = state; + for (ch_ptr=chan; ch_ptr != NULL; ch_ptr=ch_ptr->next){ + ch_ptr->common.state=state; + if (ch_ptr->tdmv_zaptel_cfg) { + continue; + } +#ifdef AFT_TDM_API_SUPPORT + if (ch_ptr->common.usedby == TDM_VOICE_API || + ch_ptr->common.usedby == TDM_VOICE_DCHAN) { + aft_tdm_api_update_state_channelized(card, ch_ptr, state); + } +#endif + } + + if (state == WAN_CONNECTED){ + DEBUG_TEST("%s: Setting idle_start to 0\n", + chan->if_name); + wan_clear_bit(0,&chan->idle_start); + chan->opstats.link_active_count++; + + WAN_NETIF_CARRIER_ON(dev); + WAN_NETIF_WAKE_QUEUE(dev); + }else{ + chan->opstats.link_inactive_modem_count++; + WAN_NETIF_CARRIER_OFF(dev); + WAN_NETIF_STOP_QUEUE(dev); + } + +# if !defined(CONFIG_PRODUCT_WANPIPE_GENERIC) +#if defined(__LINUX__) + if (chan->common.usedby == API){ + wan_update_api_state(chan); + } +#endif + + if (chan->common.usedby == STACK){ + if (state == WAN_CONNECTED){ + wanpipe_lip_connect(chan,0); + }else{ + wanpipe_lip_disconnect(chan,0); + } + } +#endif + return 0; +} + + +static char fifo_size_vector[] = {1, 2, 4, 8, 16, 32}; +static char fifo_code_vector[] = {0, 1, 3, 7,0xF,0x1F}; + +static int request_fifo_baddr_and_size(sdla_t *card, private_area_t *chan) +{ + unsigned char req_fifo_size,fifo_size; + int i; + + /* Calculate the optimal fifo size based + * on the number of time slots requested */ + + if (IS_T1_CARD(card)){ + + if (chan->num_of_time_slots == NUM_OF_T1_CHANNELS){ + req_fifo_size=32; + }else if (chan->num_of_time_slots == 1){ + req_fifo_size=1; + }else if (chan->num_of_time_slots == 2 || chan->num_of_time_slots == 3){ + req_fifo_size=2; + }else if (chan->num_of_time_slots >= 4 && chan->num_of_time_slots<= 7){ + req_fifo_size=4; + }else if (chan->num_of_time_slots >= 8 && chan->num_of_time_slots<= 15){ + req_fifo_size=8; + }else if (chan->num_of_time_slots >= 16 && chan->num_of_time_slots<= 23){ + req_fifo_size=16; + }else{ + DEBUG_EVENT("%s:%s: Invalid number of timeslots %d\n", + card->devname,chan->if_name,chan->num_of_time_slots); + return -EINVAL; + } + }else{ + if (chan->num_of_time_slots == (NUM_OF_E1_CHANNELS-1)){ + req_fifo_size=32; + }else if (chan->num_of_time_slots == 1){ + req_fifo_size=1; + }else if (chan->num_of_time_slots == 2 || chan->num_of_time_slots == 3){ + req_fifo_size=2; + }else if (chan->num_of_time_slots >= 4 && chan->num_of_time_slots <= 7){ + req_fifo_size=4; + }else if (chan->num_of_time_slots >= 8 && chan->num_of_time_slots <= 15){ + req_fifo_size=8; + }else if (chan->num_of_time_slots >= 16 && chan->num_of_time_slots <= 31){ + req_fifo_size=16; + }else{ + DEBUG_EVENT("%s:%s: Invalid number of timeslots %d\n", + card->devname,chan->if_name,chan->num_of_time_slots); + return -EINVAL; + } + } + + DEBUG_TEST("%s:%s: Optimal Fifo Size =%d Timeslots=%d \n", + card->devname,chan->if_name,req_fifo_size,chan->num_of_time_slots); + + fifo_size=map_fifo_baddr_and_size(card,req_fifo_size,&chan->fifo_base_addr); + if (fifo_size == 0 || chan->fifo_base_addr == 31){ + DEBUG_EVENT("%s:%s: Error: Failed to obtain fifo size %d or addr %d \n", + card->devname,chan->if_name,fifo_size,chan->fifo_base_addr); + return -EINVAL; + } + + DEBUG_TEST("%s:%s: Optimal Fifo Size =%d Timeslots=%d New Fifo Size=%d \n", + card->devname,chan->if_name,req_fifo_size,chan->num_of_time_slots,fifo_size); + + + for (i=0;ififo_size_code=fifo_code_vector[i]; + break; + } + } + + if (fifo_size != req_fifo_size){ + DEBUG_EVENT("%s:%s: Warning: Failed to obtain the req fifo %d got %d\n", + card->devname,chan->if_name,req_fifo_size,fifo_size); + } + + DEBUG_TEST("%s: %s:Fifo Size=%d Timeslots=%d Fifo Code=%d Addr=%d\n", + card->devname,chan->if_name,fifo_size, + chan->num_of_time_slots,chan->fifo_size_code, + chan->fifo_base_addr); + + chan->fifo_size = fifo_size; + + return 0; +} + + +static int map_fifo_baddr_and_size(sdla_t *card, unsigned char fifo_size, unsigned char *addr) +{ + u32 reg=0; + int i; + + for (i=0;idevname,reg,card->u.aft.fifo_addr_map); + + for (i=0;i<32;i+=fifo_size){ + if (card->u.aft.fifo_addr_map & (reg<u.aft.fifo_addr_map |= reg<devname,card->u.aft.fifo_addr_map,i); + + return fifo_size; + } + + if (fifo_size == 1){ + return 0; + } + + fifo_size = fifo_size >> 1; + + return map_fifo_baddr_and_size(card,fifo_size,addr); +} + + +static int free_fifo_baddr_and_size (sdla_t *card, private_area_t *chan) +{ + u32 reg=0; + int i; + + for (i=0;ififo_size;i++){ + wan_set_bit(i,®); + } + + DEBUG_TEST("%s: Unmapping 0x%X from 0x%lX\n", + card->devname,reg<fifo_base_addr, card->u.aft.fifo_addr_map); + + card->u.aft.fifo_addr_map &= ~(reg<fifo_base_addr); + + DEBUG_TEST("%s: New Map is 0x%lX\n", + card->devname, card->u.aft.fifo_addr_map); + + + chan->fifo_size=0; + chan->fifo_base_addr=0; + + return 0; +} + +static void aft_red_led_ctrl(sdla_t *card, int mode) +{ + unsigned int led; + + card->hw_iface.bus_read_4(card->hw,XILINX_CHIP_CFG_REG, &led); + + if (mode == AFT_LED_ON){ + wan_clear_bit(XILINX_RED_LED,&led); + }else if (mode == AFT_LED_OFF){ + wan_set_bit(XILINX_RED_LED,&led); + }else{ + if (wan_test_bit(XILINX_RED_LED,&led)){ + wan_clear_bit(XILINX_RED_LED,&led); + }else{ + wan_set_bit(XILINX_RED_LED,&led); + } + } + + card->hw_iface.bus_write_4(card->hw,XILINX_CHIP_CFG_REG, led); +} + + +int aft_core_ready(sdla_t *card) +{ + u32 reg; + volatile unsigned char cnt=0; + + for (;;){ + card->hw_iface.bus_read_4(card->hw,XILINX_CHIP_CFG_REG, ®); + + if (!wan_test_bit(HDLC_CORE_READY_FLAG_BIT,®)){ + /* The HDLC Core is not ready! we have + * an error. */ + if (++cnt > 5){ + return -EINVAL; + }else{ + WP_DELAY(500); + /* WARNING: we cannot do this while in + * critical area */ + } + }else{ + return 0; + } + } + + return -EINVAL; +} + + +static void aft_unmap_tx_dma(sdla_t *card, private_area_t *chan) +{ + + card->hw_iface.pci_unmap_dma(card->hw, + chan->tx_dma_addr, + chan->tx_dma_len, + PCI_DMA_TODEVICE); + + chan->tx_dma_addr=0; + chan->tx_dma_len=0; + +} + +static int protocol_init (sdla_t *card, netdevice_t *dev, + private_area_t *chan, + wanif_conf_t* conf) +{ + + chan->common.protocol = conf->protocol; + +#ifndef CONFIG_PRODUCT_WANPIPE_GENERIC + + DEBUG_EVENT("%s: AFT Driver doesn't directly support any protocols!\n", + chan->if_name); + return -EPROTONOSUPPORT; + +#else + if (chan->common.protocol == WANCONFIG_PPP || + chan->common.protocol == WANCONFIG_CHDLC){ + + struct ifreq ifr; + struct if_settings ifsettings; + + chan->common.is_netdev = 0; + if (wan_iface.attach){ + wan_iface.attach(dev, wan_netif_name(dev), chan->common.is_netdev); + }else{ + DEBUG_EVENT("%s: Failed to attach interface!\n", + chan->if_name); + return -EINVAL; + } + chan->common.prot_ptr = dev; + + if (chan->common.protocol == WANCONFIG_CHDLC){ + DEBUG_EVENT("%s: Starting Kernel CISCO HDLC protocol\n", + chan->if_name); + ifsettings.type = IF_PROTO_CISCO; + }else{ + DEBUG_EVENT("%s: Starting Kernel Sync PPP protocol\n", + chan->if_name); + ifsettings.type = IF_PROTO_PPP; + + } + ifr.ifr_data = (caddr_t)&ifsettings; + if (!wan_iface.set_proto || wan_iface.set_proto(dev, &ifr)){ + if (wan_iface.detach){ + wan_iface.detach(dev, chan->common.is_netdev); + } + if (wan_iface.free){ + wan_iface.free(dev); + } + return -EINVAL; + } + + }else if (chan->common.protocol == WANCONFIG_GENERIC){ + chan->common.prot_ptr = dev; + + }else{ + DEBUG_EVENT("%s:%s: Unsupported protocol %d\n", + card->devname,chan->if_name,chan->common.protocol); + return -EPROTONOSUPPORT; + } +#endif + + return 0; +} + + +static int protocol_start (sdla_t *card, netdevice_t *dev) +{ + int err=0; + + private_area_t *chan=wan_netif_priv(dev); + + if (!chan) + return 0; + + return err; +} + +static int protocol_stop (sdla_t *card, netdevice_t *dev) +{ + private_area_t *chan=wan_netif_priv(dev); + int err = 0; + + if (!chan) + return 0; + + return err; +} + +static int protocol_shutdown (sdla_t *card, netdevice_t *dev) +{ + private_area_t *chan=wan_netif_priv(dev); + + if (!chan) + return 0; + +#ifdef CONFIG_PRODUCT_WANPIPE_GENERIC + if (chan->common.protocol == WANCONFIG_PPP || + chan->common.protocol == WANCONFIG_CHDLC){ + + chan->common.prot_ptr = NULL; + wanpipe_generic_unregister(dev); + if (wan_iface.detach){ + wan_iface.detach(dev, chan->common.is_netdev); + } + if (wan_iface.free){ + wan_iface.free(dev); + } + + } +#endif + return 0; +} + +void protocol_recv(sdla_t *card, private_area_t *chan, netskb_t *skb) +{ + +#ifdef CONFIG_PRODUCT_WANPIPE_GENERIC + if (chan->common.protocol == WANCONFIG_PPP || + chan->common.protocol == WANCONFIG_CHDLC){ + wanpipe_generic_input(chan->common.dev, skb); + return 0; + } + + if (wan_iface.input){ + wan_iface.input(chan->common.dev, skb); + } +#endif + +#if defined(__LINUX__) && defined(CONFIG_PRODUCT_WANPIPE_GENERIC) + if (chan->common.protocol == WANCONFIG_GENERIC){ + skb->protocol = htons(ETH_P_HDLC); + skb->dev = chan->common.dev; + skb->mac.raw = wan_netif_data(skb); + netif_rx(skb); + return 0; + } +#endif + +#if defined(__LINUX__) + skb->protocol = htons(ETH_P_IP); + skb->dev = chan->common.dev; + skb->mac.raw = wan_skb_data(skb); + netif_rx(skb); +#else + if (wan_iface.input){ + wan_iface.input(chan->common.dev, skb); + } +#endif + + return; +} + + +static int channel_timeslot_sync_ctrl(sdla_t *card, private_area_t * chan, int enable) +{ + u32 reg; + + card->hw_iface.bus_read_4(card->hw,XILINX_CHIP_CFG_REG, ®); + + if (enable){ + set_channel_timeslot_sync(®,chan->first_time_slot); + + /* Make sure that Rx channel is disabled until + * we setup an rx dma descriptor */ + wan_clear_bit(START_RX_CHANNEL_TSLOT_SYNC,®); + + /* Enable Global Tx Rx timeslot sync */ + wan_set_bit(ENABLE_CHANNEL_TSLOT_SYNC,®); + + DEBUG_TEST("%s:%s: Enabling Channel Timeslot Synch (Reg=0x%X)\n", + card->devname,chan->if_name,reg); + + }else{ + wan_clear_bit(ENABLE_CHANNEL_TSLOT_SYNC,®); + + DEBUG_TEST("%s:%s: Disabling Channel Timeslot Synch (Reg=0x%X)\n", + card->devname,chan->if_name,reg); + } + + card->hw_iface.bus_write_4(card->hw,XILINX_CHIP_CFG_REG, reg); + + return 0; +} + +static int rx_chan_timeslot_sync_ctrl(sdla_t *card, int start) +{ + u32 reg; + card->hw_iface.bus_read_4(card->hw,XILINX_CHIP_CFG_REG, ®); + + if (start){ + DEBUG_TEST("%s: Enabling Rx Timeslot Synch (Reg=0x%X)\n", + card->devname,reg); + + wan_set_bit(START_RX_CHANNEL_TSLOT_SYNC,®); + }else{ + DEBUG_TEST("%s: Disabling Rx Timeslot Synch (Reg=0x%X)\n", + card->devname,reg); + wan_clear_bit(START_RX_CHANNEL_TSLOT_SYNC,®); + } + + card->hw_iface.bus_write_4(card->hw,XILINX_CHIP_CFG_REG, reg); + + return 0; +} + +static int send_rbs_oob_msg (sdla_t *card, private_area_t *chan, int channel, int status) +{ +#if defined(__LINUX__) + unsigned char *buf; + api_rx_hdr_t *api_rx_el; + struct sk_buff *skb; + int err=0, len=5; + unsigned char signal=0; + + if (chan->common.usedby != API){ + return -ENODEV; + } + + if (!chan->common.sk){ + return -ENODEV; + } + + skb=wan_skb_alloc(sizeof(api_rx_hdr_t)+len); + if (!skb){ + return -ENOMEM; + } + + api_rx_el=(api_rx_hdr_t *)wan_skb_put(skb,sizeof(api_rx_hdr_t)); + memset(api_rx_el,0,sizeof(api_rx_hdr_t)); + + api_rx_el->channel=channel; + + buf = wan_skb_put(skb,1); + if (!buf){ + wan_skb_free(skb); + return -ENOMEM; + } + +#if 0 +This conversion is done in te1 sources. + if (status & BIT_SIGX_A) signal |= WAN_RBS_SIG_A; + if (status & BIT_SIGX_B) signal |= WAN_RBS_SIG_B; + if (status & BIT_SIGX_C) signal |= WAN_RBS_SIG_C; + if (status & BIT_SIGX_D) signal |= WAN_RBS_SIG_D; +#endif + + buf[0]=signal; + + skb->pkt_type = WAN_PACKET_ERR; + skb->protocol=htons(PVC_PROT); + skb->dev=chan->common.dev; + DEBUG_TEST("%s: Sending OOB message len=%i\n", + chan->if_name, wan_skb_len(skb)); + + if (wan_api_rx(chan,skb)!=0){ + err=-ENODEV; + wan_skb_free(skb); + } + return err; + +#else + DEBUG_EVENT("%s: OOB messages not supported!\n", + chan->if_name); + return -EINVAL; +#endif +} + + +static void aft_report_rbsbits(void* pcard, int channel, unsigned char status) +{ + sdla_t *card=(sdla_t *)pcard; + int i; + + DEBUG_TEST("%s: Report Ch=%i Status=0x%X\n", + card->devname,channel,status); + + if (!wan_test_bit(channel-1, &card->u.aft.time_slot_map)){ + return; + } + + for (i=0; iu.aft.num_of_time_slots;i++){ + private_area_t *chan; + + if (!wan_test_bit(i,&card->u.aft.logic_ch_map)){ + continue; + } + + chan=(private_area_t*)card->u.aft.dev_to_ch_map[i]; + if (!chan){ + continue; + } + + if (!wan_test_bit(0,&chan->up)){ + continue; + } + + if (!wan_test_bit(channel-1, &chan->time_slot_map)){ + continue; + } + + send_rbs_oob_msg (card, chan, channel, status); + break; + } + + + return; +} + + +static int aft_rx_post_complete_voice (sdla_t *card, private_area_t *chan, + netskb_t *skb) +{ + + unsigned int len = 0; + wp_rx_element_t *rx_el=(wp_rx_element_t *)wan_skb_data(skb); + + DEBUG_RX("%s:%s: RX HI=0x%X LO=0x%X DMA=0x%lX\n", + __FUNCTION__,chan->if_name,rx_el->reg,rx_el->align,rx_el->dma_addr); + + + rx_el->align&=RxDMA_LO_ALIGNMENT_BIT_MASK; + + /* Checking Rx DMA Go bit. Has to be '0' */ + if (wan_test_bit(RxDMA_HI_DMA_GO_READY_BIT,&rx_el->reg)){ + DEBUG_TEST("%s:%s: Error: RxDMA Intr: GO bit set on Rx intr\n", + card->devname,chan->if_name); + chan->if_stats.rx_errors++; + chan->errstats.Rx_dma_descr_err++; + goto rx_comp_error; + } + + /* Checking Rx DMA PCI error status. Has to be '0's */ + if (rx_el->reg&RxDMA_HI_DMA_PCI_ERROR_MASK){ + + if (rx_el->reg & RxDMA_HI_DMA_PCI_ERROR_M_ABRT){ + DEBUG_EVENT("%s:%s: Rx Error: Abort from Master: pci fatal error! (0x%08X)\n", + card->devname,chan->if_name,rx_el->reg); + } + if (rx_el->reg & RxDMA_HI_DMA_PCI_ERROR_T_ABRT){ + DEBUG_EVENT("%s:%s: Rx Error: Abort from Target: pci fatal error! (0x%08X)\n", + card->devname,chan->if_name,rx_el->reg); + } + if (rx_el->reg & RxDMA_HI_DMA_PCI_ERROR_DS_TOUT){ + DEBUG_EVENT("%s:%s: Rx Error: No 'DeviceSelect' from target: pci fatal error! (0x%08X)\n", + card->devname,chan->if_name,rx_el->reg); + } + if (rx_el->reg & RxDMA_HI_DMA_PCI_ERROR_RETRY_TOUT){ + DEBUG_EVENT("%s:%s: Rx Error: 'Retry' exceeds maximum (64k): pci fatal error! (0x%08X)\n", + card->devname,chan->if_name,rx_el->reg); + } + + chan->if_stats.rx_errors++; + chan->errstats.Rx_pci_errors++; + goto rx_comp_error; + } + + len=rx_el->reg&RxDMA_HI_DMA_DATA_LENGTH_MASK; + + /* In Transparent mode, our RX buffer will always be + * aligned to the 32bit (word) boundary, because + * the RX buffers are all of equal length */ + len=(((chan->mru>>2)-len)<<2) - (~(0x03)&RxDMA_LO_ALIGNMENT_BIT_MASK); + + memset(wan_skb_data(skb),0,sizeof(wp_rx_element_t)); + wan_skb_put(skb,len); + + /* The rx size is big enough, thus + * send this buffer up the stack + * and allocate another one */ + wan_skb_pull(skb, sizeof(wp_rx_element_t)); + + wan_skb_reverse(skb); + + return 0; + +rx_comp_error: + + return -1; +} + + +static int aft_dma_rx_tdmv(sdla_t *card, private_area_t *chan, netskb_t *skb) +{ + unsigned int err; + err=aft_rx_post_complete_voice(card,chan,skb); + if (err==0){ + if (wan_tracing_enabled(&chan->trace_info) >= 1){ + if (card->u.aft.cfg.tdmv_dchan == 0){ + wan_capture_trace_packet_offset(card, &chan->trace_info, skb, + IS_T1_CARD(card)?24:16, TRC_INCOMING_FRM); + } + }else{ + wan_capture_trace_packet(card, &chan->trace_info, + skb, TRC_INCOMING_FRM); + } + + if (chan->tdmv_zaptel_cfg){ +#ifdef CONFIG_PRODUCT_WANPIPE_TDM_VOICE + WAN_TDMV_CALL(rx_tx, (card,skb), err); + if (err == 0) { + chan->if_stats.rx_frame_errors++; + aft_init_requeue_free_skb(chan, skb); + return 0; + } + + if (card->wan_tdmv.sc){ + WAN_TDMV_CALL(is_rbsbits, (&card->wan_tdmv), err); + if (err == 1){ + wan_set_bit(AFT_FE_TDM_RBS,&card->u.aft.port_task_cmd); + WAN_TASKQ_SCHEDULE((&card->u.aft.port_task)); + } + } +#endif + } else { +#ifdef AFT_TDM_API_SUPPORT + /* TDM VOICE API */ + aft_tdm_api_rx_tx_channelized(card,chan,skb); +#endif + } + + wan_skb_reverse(skb); + + wan_skb_queue_tail(&chan->wp_tx_pending_list,skb); + chan->if_stats.rx_packets++; + chan->if_stats.rx_bytes += wan_skb_len(skb); + return 0; + } + + return 1; +} + + +static int aft_realign_skb_pkt(private_area_t *chan, netskb_t *skb) +{ + unsigned char *data=wan_skb_data(skb); + int len = wan_skb_len(skb); + + if (len > chan->dma_mru){ + DEBUG_EVENT("%s: Critical error: Tx unalign pkt(%d) > MTU buf(%d)!\n", + chan->if_name,len,chan->dma_mru); + return -ENOMEM; + } + + if (!chan->tx_realign_buf){ + chan->tx_realign_buf=wan_malloc(chan->dma_mru); + if (!chan->tx_realign_buf){ + DEBUG_EVENT("%s: Error: Failed to allocate tx memory buf\n", + chan->if_name); + return -ENOMEM; + }else{ + DEBUG_EVENT("%s: AFT Realign buffer allocated Len=%d\n", + chan->if_name,chan->dma_mru); + + } + } + + memcpy(chan->tx_realign_buf,data,len); + + wan_skb_init(skb,0); + wan_skb_trim(skb,0); + + if (wan_skb_tailroom(skb) < len){ + DEBUG_EVENT("%s: Critical error: Tx unalign pkt tail room(%i) < unalign len(%i)!\n", + chan->if_name,wan_skb_tailroom(skb),len); + + return -ENOMEM; + } + + data=wan_skb_put(skb,len); + + if ((unsigned long)data & 0x03){ + /* At this point pkt should be realigned. If not + * there is something really wrong! */ + return -EINVAL; + } + + memcpy(data,chan->tx_realign_buf,len); + + chan->opstats.Data_frames_Tx_realign_count++; + + return 0; +} + +static void __aft_fe_intr_ctrl(sdla_t *card, int status) +{ + u32 reg; + + card->hw_iface.bus_read_4(card->hw,XILINX_CHIP_CFG_REG,®); + if (status){ + wan_set_bit(FRONT_END_INTR_ENABLE_BIT,®); + }else{ + wan_clear_bit(FRONT_END_INTR_ENABLE_BIT,®); + } + card->hw_iface.bus_write_4(card->hw,XILINX_CHIP_CFG_REG,reg); +} + +static void aft_fe_intr_ctrl(sdla_t *card, int status) +{ + wan_smp_flag_t smp_flags; + + wan_spin_lock_irq(&card->wandev.lock,&smp_flags); + __aft_fe_intr_ctrl(card, status); + wan_spin_unlock_irq(&card->wandev.lock,&smp_flags); +} + +#if defined(__LINUX__) +static void aft_port_task (void * card_ptr) +#else +static void aft_port_task (void * card_ptr, int arg) +#endif +{ + sdla_t *card = (sdla_t *)card_ptr; + wan_smp_flag_t smp_flags; + + if (wan_test_bit(CARD_DOWN,&card->wandev.critical)){ + return; + } + + DEBUG_TEST("%s: AFT PORT TASK CMD=0x%X!\n", + card->devname,card->u.aft.port_task_cmd); + + card->hw_iface.hw_lock(card->hw,&smp_flags); + + if (wan_test_bit(AFT_FE_INTR,&card->u.aft.port_task_cmd)){ + aft_fe_intr_ctrl(card, 0); + front_end_interrupt(card,0,1); + + wan_clear_bit(AFT_FE_INTR,&card->u.aft.port_task_cmd); + + aft_fe_intr_ctrl(card, 1); + } + + if (wan_test_bit(AFT_FE_POLL,&card->u.aft.port_task_cmd)){ + aft_fe_intr_ctrl(card, 0); + if (card->wandev.fe_iface.polling){ + wan_smp_flag_t smp_flags; + + card->wandev.fe_iface.polling(&card->fe); + + wan_spin_lock_irq(&card->wandev.lock,&smp_flags); + handle_front_end_state(card); + wan_spin_unlock_irq(&card->wandev.lock,&smp_flags); + } + + aft_fe_intr_ctrl(card, 1); + wan_clear_bit(AFT_FE_POLL,&card->u.aft.port_task_cmd); + } + +#ifdef CONFIG_PRODUCT_WANPIPE_TDM_VOICE + if (wan_test_bit(AFT_FE_TDM_RBS,&card->u.aft.port_task_cmd)){ + int err; + aft_fe_intr_ctrl(card, 0); + WAN_TDMV_CALL(rbsbits_poll, (&card->wan_tdmv, card), err); + aft_fe_intr_ctrl(card, 1); + wan_clear_bit(AFT_FE_TDM_RBS,&card->u.aft.port_task_cmd); + } +#endif + + + card->hw_iface.hw_unlock(card->hw,&smp_flags); +} + + +/* + * ****************************************************************** + * Proc FS function + */ +static int wan_aft_get_info(void* pcard, struct seq_file *m, int *stop_cnt) +{ + sdla_t *card = (sdla_t*)pcard; + + if (card->wandev.fe_iface.update_alarm_info){ + m->count = + WAN_FECALL( + &card->wandev, + update_alarm_info, + (&card->fe, m, stop_cnt)); + } + if (card->wandev.fe_iface.update_pmon_info){ + m->count = + WAN_FECALL( + &card->wandev, + update_pmon_info, + (&card->fe, m, stop_cnt)); + } + + return m->count; +} + +static int aft_dev_open_private(sdla_t *card, private_area_t *chan) +{ + int err=0; + + /* Initialize the router start time. + * Used by wanpipemon debugger to indicate + * how long has the interface been up */ + wan_getcurrenttime(&chan->router_start_time, NULL); + + /* If FRONT End is down, it means that the DMA + * is disabled. In this case don't try to + * reset fifo. Let the enable_data_error_intr() + * function do this, after front end has come up */ + + if (card->wandev.state == WAN_CONNECTED){ + + xilinx_init_rx_dev_fifo(card,chan,WP_WAIT); + xilinx_init_tx_dev_fifo(card,chan,WP_WAIT); + xilinx_init_tx_dma_descr(card,chan); + + err=xilinx_dma_rx(card,chan); + if (err){ + return err; + } + } + + /* Check for transparent HDLC mode */ + if (!chan->hdlc_eng){ + + u32 reg=0,reg1; + + /* The Transparent HDLC engine is + * enabled. The Rx dma has already + * been setup above. Now setup + * TX DMA and enable the HDLC engine */ + + xilinx_dma_tx(card,chan); + + DEBUG_CFG("%s: Transparent Tx Enabled!\n", + chan->if_name); + + /* Select an HDLC logic channel for configuration */ + card->hw_iface.bus_read_4( + card->hw, + XILINX_TIMESLOT_HDLC_CHAN_REG, + ®); + + reg&=~HDLC_LOGIC_CH_BIT_MASK; + reg&= HDLC_LCH_TIMESLOT_MASK; /* mask not valid bits */ + + card->hw_iface.bus_write_4(card->hw, + XILINX_TIMESLOT_HDLC_CHAN_REG, + (reg|(chan->logic_ch_num&HDLC_LOGIC_CH_BIT_MASK))); + + reg=0; + + /* Enable the transparend HDLC + * engine. */ + wan_set_bit(HDLC_RX_PROT_DISABLE_BIT,®); + wan_set_bit(HDLC_TX_PROT_DISABLE_BIT,®); + + wan_set_bit(HDLC_TX_CHAN_ENABLE_BIT,®); + wan_set_bit(HDLC_RX_ADDR_RECOGN_DIS_BIT,®); + + card->hw_iface.bus_read_4( + card->hw, + XILINX_TIMESLOT_HDLC_CHAN_REG, + ®1); + + DEBUG_CFG("%s: Writting to REG(0x64)=0x%X Reg(0x60)=0x%X\n", + chan->if_name,reg,reg1); + + xilinx_write_ctrl_hdlc(card, + chan->first_time_slot, + XILINX_HDLC_CONTROL_REG, + reg); + if (err){ + DEBUG_EVENT("%s:%d wait for timeslot failed\n", + __FUNCTION__,__LINE__); + return err; + } + } + + xilinx_dev_enable(card,chan); + wan_set_bit(0,&chan->up); + + chan->ignore_modem=0x0F; + + return err; + +} + +static int aft_dev_open(sdla_t *card, private_area_t *gchan) +{ + private_area_t *chan=gchan; + int err=0; + + if (chan->channelized_cfg){ + for (chan=gchan; chan != NULL; chan=chan->next){ + err=aft_dev_open_private(card,chan); + } + }else{ + err=aft_dev_open_private(card,chan); + } + return err; +} + +static void aft_dev_close_private(sdla_t *card, private_area_t *chan) +{ + chan->common.state = WAN_DISCONNECTED; + xilinx_dev_close(card,chan); + chan->ignore_modem=0x00; +} + +static void aft_dev_close(sdla_t *card, private_area_t *gchan) +{ + private_area_t *chan=gchan; + + if (chan->channelized_cfg){ + + for (chan=gchan; chan != NULL; chan=chan->next){ + + aft_dev_close_private(card,chan); + + DEBUG_TEST("%s: Closing Ch=%ld\n", + chan->if_name,chan->logic_ch_num); + + wan_clear_bit(0,&chan->up); + } + }else{ + aft_dev_close_private(card,chan); + wan_clear_bit(0,&chan->up); + } + return; +} + + +/* + * ****************************************************************** + * Init TDMV interface + */ +static int aft_tdmv_init(sdla_t *card, wandev_conf_t *conf) +{ + + int err; + + DEBUG_EVENT("%s: TDMV Span = %d : %s\n", + card->devname, + card->u.aft.cfg.tdmv_span_no, + card->u.aft.cfg.tdmv_span_no?"Enabled":"Disabled"); + + err=0; + + return 0; +} + +static int aft_tdmv_free(sdla_t *card) +{ +#if defined(CONFIG_PRODUCT_WANPIPE_TDM_VOICE) + if (card->u.aft.cfg.tdmv_span_no){ + int err; + WAN_TDMV_CALL(remove, (card), err); + } +#endif + return 0; +} + +static int aft_tdmv_if_init(sdla_t *card, private_area_t *chan, wanif_conf_t *conf) +{ + + int err = 0; + int dchan=card->u.aft.cfg.tdmv_dchan; + + if (chan->common.usedby != TDM_VOICE && chan->common.usedby != TDM_VOICE_API){ + return 0; + } + + if (!card->u.aft.cfg.tdmv_span_no){ + return -EINVAL; + } + + if (!conf->hdlc_streaming) { + + if (chan->common.usedby == TDM_VOICE) { +#if defined(CONFIG_PRODUCT_WANPIPE_TDM_VOICE) + WAN_TDMV_CALL(check_mtu, (card, conf->active_ch, &card->wandev.mtu), err); +#endif + } + + if (chan->common.usedby == TDM_VOICE_API) { +#ifdef AFT_TDM_API_SUPPORT + err=wp_tdmapi_check_mtu(card, conf->active_ch, 8, &card->wandev.mtu); +#endif + } + + if (err){ + DEBUG_EVENT("Error: TMDV mtu check failed!"); + return -EINVAL; + } + + chan->mtu = chan->mru = card->u.aft.cfg.mru = card->wandev.mtu; + + } + + + /* If DCHAN is enabled, set this timeslot, so zaptel + * configures it. However, the wp_tdmv_software_init() + * will remove it from the timeslot list. */ + if (IS_T1_CARD(card) && card->u.aft.cfg.tdmv_dchan){ + dchan--; + } + if (card->u.aft.cfg.tdmv_dchan){ + wan_set_bit(dchan,&conf->active_ch); + } + + /* The TDMV drivers always starts from number + * ZERO. Wanpipe driver doesn't allow timeslot + * ZERO. Thus, the active_ch map must me adjusted + * before calling tdmv_reg */ + if (IS_E1_CARD(card)){ + conf->active_ch=conf->active_ch>>1; + } + +#if defined(CONFIG_PRODUCT_WANPIPE_TDM_VOICE) + if (chan->tdmv_zaptel_cfg){ + + WAN_TDMV_CALL(reg, (card, conf, chan->common.dev), err); + if (err < 0){ + DEBUG_EVENT("%s: Error: Failed to register TDMV channel!\n", + chan->if_name); + + return -EINVAL; + } + + card->wan_tdmv.brt_enable = 1; + conf->hdlc_streaming=0; + + WAN_TDMV_CALL(software_init, (&card->wan_tdmv), err); + if (err){ + return err; + } + } +#endif + + if (card->u.aft.cfg.tdmv_dchan){ + wan_clear_bit(dchan,&conf->active_ch); + } + + return 0; +} + +static int aft_tdmv_if_free(sdla_t *card, private_area_t *chan) +{ +#if defined(CONFIG_PRODUCT_WANPIPE_TDM_VOICE) + if (chan->common.usedby == TDM_VOICE){ + int err; + WAN_TDMV_CALL(unreg, (card,chan->time_slot_map), err); + if (err){ + return err; + } + } +#endif + return 0; +} + +#ifdef AFT_TDM_API_SUPPORT +static int aft_read_rbs_bits(void *chan_ptr, u32 ch, u8 *rbs_bits) +{ + private_area_t *chan = (private_area_t *)chan_ptr; + wan_smp_flag_t flags; + sdla_t *card; + + if (!chan_ptr){ + return -EINVAL; + } + card=(sdla_t*)chan->common.card; + + card->hw_iface.hw_lock(card->hw,&flags); + *rbs_bits = card->wandev.fe_iface.read_rbsbits( + &card->fe, + ch, + WAN_TE_RBS_UPDATE); + card->hw_iface.hw_unlock(card->hw,&flags); + + return 0; + +} + +static int aft_write_rbs_bits(void *chan_ptr, u32 ch, u8 rbs_bits) +{ + private_area_t *chan = (private_area_t *)chan_ptr; + wan_smp_flag_t flags; + sdla_t *card; + int err; + + if (!chan_ptr){ + return -EINVAL; + } + + card=(sdla_t*)chan->common.card; + card->hw_iface.hw_lock(card->hw,&flags); + err = card->wandev.fe_iface.set_rbsbits(&card->fe, + ch, + rbs_bits); + card->hw_iface.hw_unlock(card->hw,&flags); + + return err; +} + + +static int aft_write_hdlc_frame(void *chan_ptr, netskb_t *skb) +{ + private_area_t *chan = (private_area_t *)chan_ptr; + sdla_t *card=chan->common.card; + wan_smp_flag_t smp_flags; + int err=-EINVAL; + + if (!chan_ptr || !chan->common.dev || !card){ + WAN_ASSERT(1); + return -EINVAL; + } + + if (chan->common.usedby != TDM_VOICE_DCHAN) { + return -EINVAL; + } + + if (wan_skb_len(skb) > chan->mtu) { + return -EINVAL; + } + + wan_spin_lock_irq(&card->wandev.lock, &smp_flags); + + if (wan_skb_queue_len(&chan->wp_tx_pending_list) > MAX_TX_BUF){ + xilinx_dma_tx(card,chan); + wan_spin_unlock_irq(&card->wandev.lock, &smp_flags); + return -EBUSY; + + } + + wan_skb_unlink(skb); + wan_skb_queue_tail(&chan->wp_tx_pending_list,skb); + xilinx_dma_tx(card,chan); + + err=0; + wan_spin_unlock_irq(&card->wandev.lock, &smp_flags); + + + return err; +} + +static int aft_tdm_api_update_state_channelized(sdla_t *card, private_area_t *chan, int state) +{ + int x; + + for (x=0;xu.aft.num_of_time_slots;x++){ + if (!wan_test_bit(x,&chan->tdmapi_timeslots)){ + continue; + } + if (is_tdm_api(chan,&chan->wp_tdm_api_dev_idx[x])){ + wanpipe_tdm_api_update_state(&chan->wp_tdm_api_dev_idx[x], state); + } + } + + return 0; +} + +static int aft_tdm_api_rx_tx_channelized(sdla_t *card, private_area_t *chan, netskb_t *skb) +{ + + u8 *rxbuf = wan_skb_data(skb); + u8 *txbuf = wan_skb_data(skb); + int rxbuf_len = wan_skb_len(skb); + int x,y; + int offset=0; + + if (rxbuf_len != chan->mru) { + chan->if_stats.rx_errors++; + return -EINVAL; + } + + for (y=0;yu.aft.num_of_time_slots;x++){ + + if (!wan_test_bit(x,&chan->tdmapi_timeslots)){ + continue; + } + + chan->wp_tdm_api_dev_idx[x].rx_data[y] = + rxbuf[offset++]; + + if (y == WP_TDM_API_CHUNK_SZ-1) { + wanpipe_tdm_api_rx_tx(&chan->wp_tdm_api_dev_idx[x], + chan->wp_tdm_api_dev_idx[x].rx_data, + chan->wp_tdm_api_dev_idx[x].tx_data, + WP_TDM_API_CHUNK_SZ); + } + } + } + + offset=0; + for (y=0;yu.aft.num_of_time_slots;x++){ + if (!wan_test_bit(x,&chan->tdmapi_timeslots)){ + continue; + } + txbuf[offset++] = chan->wp_tdm_api_dev_idx[x].tx_data[y]; + } + } + + return 0; +} + +#endif + + + + +/****** End ****************************************************************/ diff -Nur linux.org/drivers/net/wan/wanpipe_abstr.c linux-2.6.17/drivers/net/wan/wanpipe_abstr.c --- linux.org/drivers/net/wan/wanpipe_abstr.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/drivers/net/wan/wanpipe_abstr.c 2006-08-30 10:07:17.000000000 +0000 @@ -0,0 +1,1106 @@ +/***************************************************************************** +* wanpipe_abstr.c WANPIPE(tm) Kernel Abstraction Layer. +* +* Authors: Nenad Corbic +* Alex Feldman +# include +# include +# include +# include +#elif defined(__KERNEL__) +# include +# include +# include +# include +# include +# include +# include +# include +# include +#else +# error "Unsupported Operating System!" +#endif + + +/* +****************************************************************************** +** Call Back function for kernel memory buffers +****************************************************************************** +*/ +/* +** wpabs_skb_data() - +*/ +unsigned char* wpabs_skb_data(void* skb) +{ + return wan_skb_data(skb); +} + +/* +** wpabs_skb_tail() - +*/ +unsigned char* wpabs_skb_tail(void* skb) +{ + return wan_skb_tail(skb); +} + + +/* +** wpabs_skb_len() - +*/ +int wpabs_skb_len(void* skb) +{ + return wan_skb_len(skb); +} + +/* +** wpabs_skb_len() - +*/ +int wpabs_skb_headroom(void* skb) +{ + return wan_skb_headroom(skb); +} + + +/* +** +*/ +void* wpabs_skb_alloc_queue(void) +{ + return wan_malloc(sizeof(wan_skb_queue_t)); +} + +/* +** +*/ +void wpabs_skb_free_queue(void* queue_ptr) +{ + + if (!queue_ptr){ + DEBUG_EVENT("%s: Wanpipe Assertion: queue_ptr==NULL!\n", + __FUNCTION__); + return; + } + + WAN_IFQ_PURGE((wan_skb_queue_t*)queue_ptr); + wan_free((wan_skb_queue_t*)queue_ptr); +} + +/* +** +*/ +void wpabs_skb_queue_init(void *queue_ptr) +{ + wan_skb_queue_init(queue_ptr); +} + +/* +** wpabs_skb_alloc() - +*/ +void* wpabs_skb_alloc(unsigned int len) +{ + void *skb; + skb = wan_skb_alloc(len); + return skb; +} + +/* +** wpabs_skb_free() - +*/ +void wpabs_skb_free(void* skb) +{ + wan_skb_free(skb); +} + +/* +** wpabs_skb_copyback() - +*/ +void wpabs_skb_copyback(void* skb, int off, int len, unsigned long cp) +{ + wan_skb_copyback(skb, off, len, (caddr_t)cp); +} + +void wpabs_skb_copyback_user(void* skb, int off, int len, unsigned long cp) +{ + wan_skb_copyback_user(skb, off, len, (caddr_t)cp); +} + + +/* +** wpabs_skb_pull() - +*/ +unsigned char* wpabs_skb_pull(void* skb, int len) +{ + return wan_skb_pull(skb, len); +} + +/* +** wpabs_skb_push() - +*/ +unsigned char* wpabs_skb_push(void* skb, int len) +{ + return wan_skb_push(skb, len); +} + +/* +** wpabs_skb_reserve() - +*/ +void wpabs_skb_reserve(void* skb, int len) +{ + wan_skb_reserve(skb, len); +} + + +/* +** wpabs_skb_put() - +*/ +unsigned char* wpabs_skb_put(void* skb, int len) +{ + return wan_skb_put(skb, len); +} + + +/* +** wpabs_skb_trim() - Trim from tail +*/ +void wpabs_skb_trim(void* skb, unsigned int len) +{ + wan_skb_trim(skb, len); +} + +/* +** wpabs_skb_clone() - Clone SKB Buffer +*/ +void *wpabs_skb_clone(void* skb) +{ + return wan_skb_clone(skb); +} +/* +** wpabs_skb_copy() - Copy Skb buffer +*/ +void *wpabs_skb_copy(void* skb) +{ + return wan_skb_copy(skb); +} + + +/* +** wpabs_skb_tailroom() - Skb tail room +*/ +int wpabs_skb_tailroom(void* skb) +{ + return wan_skb_tailroom(skb); +} + +/* +** wpabs_skb_queue_len() - Length of skb queue +*/ + +int wpabs_skb_queue_len(void *queue) +{ + return wan_skb_queue_len(queue); +} + +void wpabs_skb_queue_purge(void *queue) +{ + WAN_IFQ_PURGE((wan_skb_queue_t*)queue); +} + +void *wpabs_skb_dequeue(void *queue) +{ + return wan_skb_dequeue((wan_skb_queue_t*)queue); +} + +/* +** wpabs_skb_queue_tail() - Length of skb queue +*/ + +void wpabs_skb_queue_tail(void *queue,void *skb) +{ + wan_skb_queue_tail(queue,skb); +} + +void wpabs_skb_queue_head(void *queue,void *skb) +{ + wan_skb_queue_head(queue,skb); +} + +void wpabs_skb_append(void *skb_prev, void *skb_cur, void *list) +{ + wan_skb_append(skb_prev,skb_cur,list); +} + +void wpabs_skb_unlink(void *skb) +{ + wan_skb_unlink(skb); +} + + + +/* +** wpabs_skb_init() - Init data pointer +*/ +void wpabs_skb_init(void* skb, unsigned int len) +{ + wan_skb_init(skb, len); +} + +void wpabs_skb_set_dev(void *skb_new_ptr, void *dev) +{ + wan_skb_set_dev(skb_new_ptr,dev); +} + +void wpabs_skb_set_raw(void *skb_new_ptr) +{ + wan_skb_set_raw(skb_new_ptr); +} + +void wpabs_skb_set_protocol(void *skb_new_ptr, unsigned int prot) +{ + wan_skb_set_protocol(skb_new_ptr,prot); +} + +void wpabs_skb_set_csum(void *skb_new_ptr, unsigned int csum) +{ + wan_skb_set_csum(skb_new_ptr,csum); +} + +unsigned int wpabs_skb_csum(void *skb_new_ptr) +{ + return wan_skb_csum(skb_new_ptr); +} + + + +void *wpabs_netif_alloc(unsigned char *dev_name,int ifType, int *err) +{ + return wan_netif_alloc(dev_name,ifType,err); +} + +void wpabs_netif_free(void *dev) +{ + return wan_netif_free(dev); +} + + +unsigned char* wpabs_netif_name(void *dev) +{ + return wan_netif_name(dev); +} + +/* +** wpabs_netif_queue_stopped +*/ +int wpabs_netif_queue_stopped(void* dev) +{ + return WAN_NETIF_QUEUE_STOPPED((netdevice_t*)dev); +} + +/* +** wpabs_netif_queue_stopped +*/ +int wpabs_netif_dev_up(void* dev) +{ + return WAN_NETIF_UP((netdevice_t*)dev); +} + + + +/* +** wpabs_netif_wake_queue +*/ +void wpabs_netif_wake_queue(void* dev) +{ + WAN_NETIF_WAKE_QUEUE((netdevice_t*)dev); +} + +void* wpabs_timer_alloc(void) +{ + return wan_malloc(sizeof(wan_timer_t)); +} + +/* +** wpabs_add_timer() - Set timer +*/ +void wpabs_add_timer(void* timer_info, unsigned long delay) +{ + wan_timer_t* timer = (wan_timer_t*)timer_info; + + WAN_ASSERT1(timer == NULL); + wan_add_timer(timer, delay); +} + +/* +** wpabs_init_timer +*/ +void wpabs_init_timer(void* timer_info, void* timer_func, unsigned long data) +{ + wan_timer_t* timer = (wan_timer_t*)timer_info; + + WAN_ASSERT1(timer == NULL); + timer->MiniportTimerFunction = (wan_timer_func_t)timer_func; + timer->MiniportAdapterHandle = (void*)data; + timer->MiniportTimerContext = (void*)data; + + wan_init_timer(timer, timer_func, (wan_timer_arg_t)data); +} + +/* +** wpabs_del_timer +*/ +void wpabs_del_timer(void* timer_info) +{ + wan_timer_t* timer = (wan_timer_t*)timer_info; + + WAN_ASSERT1(timer == NULL); + wan_del_timer(timer); +} + + + +unsigned long* wpabs_dma_get_vaddr(void* pcard, void* dma_descr) +{ + return wan_dma_get_vaddr(pcard,dma_descr); +} + +unsigned long wpabs_dma_get_paddr(void* pcard, void* dma_descr) +{ + return wan_dma_get_paddr(pcard,dma_descr); +} + +void* wpabs_malloc(int size) +{ + return wan_malloc(size); +} + +void wpabs_free(void* ptr) +{ + wan_free(ptr); +} + +/* +** wpabs_virt2bus +*/ +unsigned long wpabs_virt2bus(unsigned long* ptr) +{ + return wan_virt2bus(ptr); +} + +/* +** wpabs_bus2virt +*/ +unsigned long* wpabs_bus2virt(unsigned long ptr) +{ + return wan_bus2virt(ptr); +} + +/* +** +*/ +unsigned char wpabs_bus_read_1(void* cardp, int offset) +{ + sdla_t* card = (sdla_t*)cardp; + unsigned char data = 0x00; + + WAN_ASSERT(card == NULL); + card->hw_iface.peek(card->hw, offset, (void*)&data, 1); + return data; +} + +/* +** +*/ +unsigned long wpabs_bus_read_4(void* cardp, int offset) +{ + sdla_t* card = (sdla_t*)cardp; + unsigned long data = 0x00; + + WAN_ASSERT(card == NULL); + card->hw_iface.peek(card->hw, offset, (void*)&data, 4); + return data; +} + +/* +** +*/ +void wpabs_bus_write_1(void* cardp, int offset, unsigned char data) +{ + sdla_t* card = (sdla_t*)cardp; + + WAN_ASSERT1(card == NULL); + card->hw_iface.poke_byte(card->hw, offset, data); +} + +/* +** +*/ +void wpabs_bus_write_4(void* cardp, int offset, unsigned long data) +{ + sdla_t* card = (sdla_t*)cardp; + + WAN_ASSERT1(card == NULL); + card->hw_iface.poke(card->hw, offset, (void*)&data, 4); +} + +/* +** +*/ +void wpabs_udelay(unsigned long microsecs) +{ + WP_DELAY(microsecs); +} + +void* wpabs_spinlock_alloc(void) +{ + return wan_malloc(sizeof(wan_spinlock_t)); +} +void wpabs_spinlock_free(void* lock) +{ + return wan_free(lock); +} + +/* +** +*/ +void wpabs_spin_lock_irqsave(void* lock,unsigned long *flags) +{ + wan_spinlock_t* SpinLock = (wan_spinlock_t*)lock; + + WAN_ASSERT1(SpinLock == NULL); + wan_spin_lock_irq(SpinLock,(wan_smp_flag_t*)flags); +} +/* +** +*/ +void wpabs_spin_unlock_irqrestore(void* lock,unsigned long *flags) +{ + wan_spinlock_t* SpinLock = (wan_spinlock_t*)lock; + + WAN_ASSERT1(SpinLock == NULL); + wan_spin_unlock_irq(SpinLock,(wan_smp_flag_t*)flags); +} + +/* +** +*/ +void wpabs_spin_lock_init(void* lock) +{ + wan_spinlock_t* SpinLock = (wan_spinlock_t*)lock; + + WAN_ASSERT1(SpinLock == NULL); + wan_spin_lock_init(SpinLock); + +} + +#if 0 +/* +** +*/ +void* wpabs_rwlock_alloc(void) +{ + return wan_malloc(sizeof(wan_rwlock_t)); +} +void wpabs_rwlock_free(void* lock) +{ + return wan_free(lock); +} + +void wpabs_rwlock_init(void* lock) +{ + wan_rwlock_t* rwlock = (wan_rwlock_t*)lock; + WAN_ASSERT1(lock == NULL); + WAN_RWLOCK_INIT(rwlock); +} + +void wpabs_read_rw_lock(void* lock) +{ + wan_rwlock_t* rwlock = (wan_rwlock_t*)lock; + WAN_ASSERT1(lock == NULL); + wan_read_rw_lock(&rwlock->rwlock); +} + +void wpabs_read_rw_unlock(void* lock) +{ + wan_rwlock_t* rwlock = (wan_rwlock_t*)lock; + WAN_ASSERT1(lock == NULL); + wan_read_rw_unlock(&rwlock->rwlock); +} + +void wpabs_write_rw_lock_irq(void* lock,unsigned long *flags) +{ + wan_rwlock_t* rwlock = (wan_rwlock_t*)lock; + WAN_ASSERT1(lock == NULL); + wan_write_rw_lock_irq(&rwlock->rwlock,flags); +} + +void wpabs_write_rw_unlock_irq(void* lock,unsigned long *flags) +{ + wan_rwlock_t* rwlock = (wan_rwlock_t*)lock; + WAN_ASSERT1(lock == NULL); + wan_write_rw_unlock_irq(&rwlock->rwlock,flags); +} + +#endif + +/* +** +*/ + +void wpabs_debug_event(const char * fmt, ...) +{ +#ifdef WAN_DEBUG_EVENT + va_list args; + char buf[1024]; + va_start(args, fmt); + vsnprintf(buf, sizeof(buf), fmt, args); + DEBUG_EVENT("%s", buf); + va_end(args); +#endif +} + +/* +** +*/ + +void wpabs_debug_test(const char * fmt, ...) +{ +#ifdef WAN_DEBUG_TEST + va_list args; + char buf[1024]; + va_start(args, fmt); + vsnprintf(buf, sizeof(buf), fmt, args); + DEBUG_TEST("%s", buf); + va_end(args); +#endif +} + + +/* +** +*/ +void wpabs_debug_cfg(const char * fmt, ...) +{ +#ifdef WAN_DEBUG_CFG + va_list args; + char buf[1024]; + va_start(args, fmt); + vsnprintf(buf, sizeof(buf), fmt, args); + DEBUG_CFG("%s",buf); + va_end(args); +#endif +} + +/* +** +*/ +void wpabs_debug_init(const char * fmt, ...) +{ +#ifdef WAN_DEBUG_INIT_VAR + va_list args; + char buf[1024]; + va_start(args, fmt); + vsnprintf(buf, sizeof(buf), fmt, args); + DEBUG_INIT("%s",buf); + va_end(args); +#endif +} + +/* +** +*/ +void wpabs_debug_tx(const char * fmt, ...) +{ +#ifdef WAN_DEBUG_TX + va_list args; + char buf[1024]; + va_start(args, fmt); + vsnprintf(buf, sizeof(buf), fmt, args); + DEBUG_TX("%s",buf); + va_end(args); +#endif +} + +/* +** +*/ +void wpabs_debug_rx(const char * fmt, ...) +{ +#ifdef WAN_DEBUG_RX + va_list args; + char buf[1024]; + va_start(args, fmt); + vsnprintf(buf, sizeof(buf), fmt, args); + DEBUG_RX("%s",buf); + va_end(args); +#endif +} + +/* +** +*/ +void wpabs_debug_isr(const char * fmt, ...) +{ +#ifdef WAN_DEBUG_ISR + va_list args; + char buf[1024]; + va_start(args, fmt); + vsnprintf(buf, sizeof(buf), fmt, args); + DEBUG_ISR("%s",buf); + va_end(args); +#endif +} +/* +** +*/ +void wpabs_debug_timer(const char * fmt, ...) +{ +#ifdef WAN_DEBUG_TIMER + va_list args; + char buf[1024]; + va_start(args, fmt); + vsnprintf(buf, sizeof(buf), fmt, args); + DEBUG_TIMER("%s",buf); + va_end(args); +#endif +} +/* +** +*/ +int wpabs_set_bit(int bit, void *ptr) +{ + wan_set_bit(bit,ptr); + return 0; +} + +/* +** +*/ +int wpabs_test_and_set_bit(int bit, void *ptr) +{ +#if defined(__LINUX__) + return test_and_set_bit(bit,ptr); +#elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) + if (wan_test_bit(bit,ptr)){ + return 1; + } + wan_set_bit(bit,ptr); + return 0; +#else +# error "Error: wpabs_test_and_set_bit() not implemented!" +#endif + +} + + +/* +** +*/ +int wpabs_test_bit(int bit, void *ptr) +{ + return wan_test_bit(bit,ptr); +} +/* +** +*/ +int wpabs_clear_bit(int bit, void *ptr) +{ + wan_clear_bit(bit,ptr); + return 0; +} + +unsigned long wpabs_get_systemticks(void) +{ + return SYSTEM_TICKS; +} + +unsigned long wpabs_get_hz(void) +{ + return HZ; +} + +unsigned short wpabs_htons(unsigned short data) +{ + return htons(data); +} + +unsigned short wpabs_ntohs(unsigned short data) +{ + return ntohs(data); +} + +unsigned long wpabs_htonl(unsigned long data) +{ + return htonl(data); +} + +unsigned long wpabs_ntohl(unsigned long data) +{ + return ntohl(data); +} + + + +void * wpabs_tasklet_alloc(void) +{ + wan_tasklet_t* task = NULL; + task = (wan_tasklet_t*)wan_malloc(sizeof(wan_tasklet_t)); + task->running = 0; + return (void*)task; +} + +void wpabs_tasklet_init(void *task_ptr, int priority, void* func, void* arg) +{ + wan_tasklet_t* task = (wan_tasklet_t *)task_ptr; + wan_tasklet_func_t* task_func = (wan_tasklet_func_t*)func; + + WAN_ASSERT1(task == NULL); + WAN_TASKLET_INIT(task, priority, task_func, arg); +} + + +void wpabs_tasklet_schedule(void *task_ptr) +{ + wan_tasklet_t *task = (wan_tasklet_t*)task_ptr; + + WAN_ASSERT1(task == NULL); + WAN_TASKLET_SCHEDULE(task); +} + +void wpabs_tasklet_end(void *task_ptr) +{ + wan_tasklet_t *task = (wan_tasklet_t*)task_ptr; + + WAN_ASSERT1(task == NULL); + WAN_TASKLET_END(task); +} + +void wpabs_tasklet_kill(void *task_ptr) +{ + wan_tasklet_t *task = (wan_tasklet_t*)task_ptr; + + WAN_ASSERT1(task == NULL); + WAN_TASKLET_KILL(task); +} + +void *wpabs_taskq_alloc(void) +{ + return wan_malloc(sizeof(wan_taskq_t)); +} + +void wpabs_taskq_init(void *tq_ptr, void *func, void *data) +{ + wan_taskq_t* tq = (wan_taskq_t *)tq_ptr; + wan_taskq_func_t tq_func = (wan_taskq_func_t)func; + + WAN_ASSERT1(tq==NULL); + + WAN_TASKQ_INIT(tq, 0, tq_func, data); +} + +/*+F************************************************************************* + * Function: + * wpabs_taskq_schedule_event + * + * Description: + * Schedule an event to be processed by the bottom half handler. + *-F*************************************************************************/ +void wpabs_taskq_schedule_event(unsigned int bit, unsigned long *event, void *tq_ptr) +{ + wan_taskq_t *tq = (wan_taskq_t *)tq_ptr; + + WAN_ASSERT1(tq==NULL) + DEBUG_TX ("wpabs_wan_schedule_event: scheduling task\n"); + wan_set_bit(bit, event); + WAN_TASKQ_SCHEDULE(tq); +} + +void* wpabs_memset(void *b, int c, int len) +{ + return memset(b,c,len); +} + +void* wpabs_strncpy(void *b, void * c, int len) +{ + return strncpy(b,c,len); +} + +void* wpabs_memcpy(void *b, void *c, int len) +{ + return memcpy(b,c,len); +} + +int wpabs_memcmp(void *b, void *c, int len) +{ + return memcmp(b,c,len); +} + +int wpabs_strlen(unsigned char *str) +{ + return strlen(str); +} + +void wpabs_debug_print_skb(void *skb_ptr, char dir) +{ +#if 1 +/*#ifdef WAN_DEBUG_TX*/ + netskb_t* skb = (netskb_t*)skb_ptr; + unsigned char* data = NULL; + int i; + + DEBUG_TX("%s SKB: Len=%i : ",dir?"TX":"RX",wan_skb_len(skb)); + data = wan_skb_data(skb); + for (i=0; i < wan_skb_len(skb); i++){ + _DEBUG_TX("%02X ", data[i]); + } + + _DEBUG_TX("\n"); +#endif +} + + + +/* + * ============================================================================ + * Set WAN device state. + */ + +void wpabs_decode_ipaddr(unsigned long ipaddr, unsigned char *str, int len) +{ + snprintf(str,len,"%u.%u.%u.%u",NIPQUAD(ipaddr)); +} + + + +unsigned long wan_get_ip_addr(void* dev, int option) +{ + netdevice_t* ifp = (netdevice_t*)dev; + +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) + struct ifaddr* ifa = NULL; + struct sockaddr_in* addr = NULL; + + if (ifp == NULL){ + return 0; + } + ifa = WAN_TAILQ_FIRST(ifp); + if (ifa == NULL || ifa->ifa_addr == NULL){ + return 0; + } +#elif defined(__LINUX__) + struct in_ifaddr *ifaddr; + struct in_device *in_dev; + + if ((in_dev = in_dev_get(ifp)) == NULL){ + return 0; + } + if ((ifaddr = in_dev->ifa_list)== NULL ){ + in_dev_put(in_dev); + return 0; + } + in_dev_put(in_dev); +#endif + + switch (option){ + case WAN_LOCAL_IP: +#if defined(__FreeBSD__) + ifa = WAN_TAILQ_NEXT(ifa); + if (ifa == NULL) return 0; + addr = (struct sockaddr_in *)ifa->ifa_addr; + return addr->sin_addr.s_addr; +#elif defined(__NetBSD__) || defined(__OpenBSD__) + addr = (struct sockaddr_in *)ifa->ifa_addr; + return htonl(addr->sin_addr.s_addr); +#else + return ifaddr->ifa_local; +#endif + break; + + case WAN_POINTOPOINT_IP: +#if defined(__FreeBSD__) + ifa = WAN_TAILQ_NEXT(ifa); + if (ifa == NULL) return 0; + addr = (struct sockaddr_in *)ifa->ifa_dstaddr; + return addr->sin_addr.s_addr; +#elif defined(__NetBSD__) || defined(__OpenBSD__) + return 0; +#else + return ifaddr->ifa_address; +#endif + break; + + case WAN_NETMASK_IP: +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) + return 0; +#else + return ifaddr->ifa_mask; +#endif + break; + + case WAN_BROADCAST_IP: +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) + return 0; +#else + return ifaddr->ifa_broadcast; +#endif + break; + default: + break; + } + + return 0; +} + +unsigned long wpabs_get_ip_addr(void* dev, int option) +{ + return wan_get_ip_addr(dev, option); +} + +#define UNKNOWN_PROT "Unknown Prot" +#define IP_LLC_ATM "Classic IP (LLC) over ATM" +#define IP_VC_ATM "IP (VC) over ATM" +#define B_LLC_ETH "Bridged LLC Ethernet over ATM" +#define B_VC_ETH "Bridged VC Ethernet over ATM" +#define PPP_LLC_ATM "PPP (LLC) over ATM" +#define PPP_VC_ATM "PPP (VC) over ATM" +int wpabs_detect_prot_header(unsigned char *data,int dlen, char* temp, int tlen) +{ + int i,cnt=0; + + if (temp){ + memset(temp, 0, tlen); + } + + if (data[0] == 0xAA && data[1] == 0xAA){ + if (data[6] == 0x08){ + if (data[7] == 0x00 || data[7] == 0x06){ + if (temp){ + memcpy(temp, IP_LLC_ATM, strlen(IP_LLC_ATM)); + } + return 0; + } + }else if (data[6] == 0x00 && data[7] == 0x07){ + if (temp){ + memcpy(temp, B_LLC_ETH, strlen(B_LLC_ETH)); + } + return 0; + } + goto detect_unknown; + } + + if ((data[0] == 0xFE && data[1] == 0xFE) || + (data[0] == 0xFE && data[1] == 0x03)){ + if (temp){ + memcpy(temp, PPP_LLC_ATM, strlen(PPP_LLC_ATM)); + } + return 0; + } + + if (data[0] == 0xC0 && data[1] == 0x21){ + if (temp){ + memcpy(temp, PPP_VC_ATM, strlen(PPP_VC_ATM)); + } + return 0; + } + + if (data[0] == 0x45){ + if (temp){ + memcpy(temp, IP_VC_ATM, strlen(IP_VC_ATM)); + } + return 0; + } + +detect_unknown: + if (temp){ + for (i=0;ilast_trace_direction = direction; +} + +unsigned char wpabs_get_last_trace_direction(void *trace_ptr) +{ + return ((wan_trace_t*)trace_ptr)->last_trace_direction; +} + +/* +** wpabs_bpf_report +*/ +int wpabs_bpf_report(void* dev, void* skb, int flag) +{ + wan_bpf_report((netdevice_t*)dev, (netskb_t*)skb, flag); + return 0; +} + diff -Nur linux.org/drivers/net/wan/wanpipe_codec.c linux-2.6.17/drivers/net/wan/wanpipe_codec.c --- linux.org/drivers/net/wan/wanpipe_codec.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/drivers/net/wan/wanpipe_codec.c 2006-08-30 10:07:17.000000000 +0000 @@ -0,0 +1,98 @@ +/************************************************************************** + * wanpipe_codec.c WANPIPE(tm) Multiprotocol WAN Link Driver. + * TDM voice board configuration. + * + * Author: Nenad Corbic + * + * Copyright: (c) 1995-2005 Sangoma Technologies Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + ****************************************************************************** + */ +/* + ****************************************************************************** + INCLUDE FILES + ****************************************************************************** +*/ + +#if (defined __FreeBSD__) | (defined __OpenBSD__) +# include +# include +# include +# include +# include +# include +# include +#elif (defined __WINDOWS__) +# include +#else +# include +# include +# include +# include +#endif + + +wanpipe_codec_ops_t *WANPIPE_CODEC_OPS[WP_TDM_HW_CODING_MAX][WP_TDM_CODEC_MAX]; + + + +int wanpipe_codec_init(void) +{ + wanpipe_codec_ops_t *wp_codec_ops; + +#ifdef CONFIG_PRODUCT_WANPIPE_CODEC_SLINEAR_LAW + + wanpipe_codec_law_init(); + + wp_codec_ops = wan_malloc(sizeof(wanpipe_codec_ops_t)); + if (!wp_codec_ops){ + return -ENOMEM; + } + + memset(wp_codec_ops,0,sizeof(wanpipe_codec_ops_t)); + + wp_codec_ops->init = 1; + wp_codec_ops->encode = wanpipe_codec_convert_ulaw_2_s; + wp_codec_ops->decode = wanpipe_codec_convert_s_2_ulaw; + + WANPIPE_CODEC_OPS[WP_MULAW][WP_SLINEAR] = wp_codec_ops; + + + wp_codec_ops = wan_malloc(sizeof(wanpipe_codec_ops_t)); + if (!wp_codec_ops){ + return -ENOMEM; + } + + memset(wp_codec_ops,0,sizeof(wanpipe_codec_ops_t)); + + wp_codec_ops->init = 1; + wp_codec_ops->encode = wanpipe_codec_convert_alaw_2_s; + wp_codec_ops->decode = wanpipe_codec_convert_s_2_alaw; + + WANPIPE_CODEC_OPS[WP_ALAW][WP_SLINEAR] = wp_codec_ops; + +#endif + + DEBUG_EVENT("WANPIPE: TDM Codecs Initialized\n"); + + return 0; +} + +int wanpipe_codec_free(void) +{ + int i,j; + for (i = 0; i < WP_TDM_HW_CODING_MAX; i++){ + for (j=0;j < WP_TDM_CODEC_MAX; j++){ + if (WANPIPE_CODEC_OPS[i][j]){ + wan_free(WANPIPE_CODEC_OPS[i][j]); + WANPIPE_CODEC_OPS[i][j]=NULL; + } + } + } + + return 0; +} diff -Nur linux.org/drivers/net/wan/wanpipe_codec_law.c linux-2.6.17/drivers/net/wan/wanpipe_codec_law.c --- linux.org/drivers/net/wan/wanpipe_codec_law.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/drivers/net/wan/wanpipe_codec_law.c 2006-08-30 10:07:17.000000000 +0000 @@ -0,0 +1,371 @@ +/************************************************************************** + * wanpipe_codec_law.c WANPIPE(tm) Multiprotocol WAN Link Driver. + * TDM voice board configuration. + * + * Author: Nenad Corbic + * + * Copyright: (c) 1995-2005 Sangoma Technologies Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + ****************************************************************************** + */ +/* + ****************************************************************************** + INCLUDE FILES + ****************************************************************************** +*/ + +#if (defined __FreeBSD__) | (defined __OpenBSD__) +# include +# include +# include +# include +# include +# include +# include +#elif (defined __WINDOWS__) +# include +#else +# include +# include +# include +# include +# include +# include +# include +#endif + + + +/* MULAW table */ +static unsigned short u2s[] = { + /*Part 2 - this is the only part used. The 2 parts are switched + from it's original locations because we only intrested in + absolute values, not interested in sign. + */ + 0x7D7C, 0x797C, 0x757C, 0x717C, 0x6D7C, 0x697C, 0x657C, 0x617C, + 0x5D7C, 0x597C, 0x557C, 0x517C, 0x4D7C, 0x497C, 0x457C, 0x417C, + 0x3E7C, 0x3C7C, 0x3A7C, 0x387C, 0x367C, 0x347C, 0x327C, 0x307C, + 0x2E7C, 0x2C7C, 0x2A7C, 0x287C, 0x267C, 0x247C, 0x227C, 0x207C, + 0x1EFC, 0x1DFC, 0x1CFC, 0x1BFC, 0x1AFC, 0x19FC, 0x18FC, 0x17FC, + 0x16FC, 0x15FC, 0x14FC, 0x13FC, 0x12FC, 0x11FC, 0x10FC, 0x0FFC, + 0x0F3C, 0x0EBC, 0x0E3C, 0x0DBC, 0x0D3C, 0x0CBC, 0x0C3C, 0x0BBC, + 0x0B3C, 0x0ABC, 0x0A3C, 0x09BC, 0x093C, 0x08BC, 0x083C, 0x07BC, + 0x075C, 0x071C, 0x06DC, 0x069C, 0x065C, 0x061C, 0x05DC, 0x059C, + 0x055C, 0x051C, 0x04DC, 0x049C, 0x045C, 0x041C, 0x03DC, 0x039C, + 0x036C, 0x034C, 0x032C, 0x030C, 0x02EC, 0x02CC, 0x02AC, 0x028C, + 0x026C, 0x024C, 0x022C, 0x020C, 0x01EC, 0x01CC, 0x01AC, 0x018C, + 0x0174, 0x0164, 0x0154, 0x0144, 0x0134, 0x0124, 0x0114, 0x0104, + 0x00F4, 0x00E4, 0x00D4, 0x00C4, 0x00B4, 0x00A4, 0x0094, 0x0084, + 0x0078, 0x0070, 0x0068, 0x0060, 0x0058, 0x0050, 0x0048, 0x0040, + 0x0038, 0x0030, 0x0028, 0x0020, 0x0018, 0x0010, 0x0008, 0x0000, + + /*Part 1*/ + 0x8284, 0x8684, 0x8A84, 0x8E84, 0x9284, 0x9684, 0x9A84, 0x9E84, + 0xA284, 0xA684, 0xAA84, 0xAE84, 0xB284, 0xB684, 0xBA84, 0xBE84, + 0xC184, 0xC384, 0xC584, 0xC784, 0xC984, 0xCB84, 0xCD84, 0xCF84, + 0xD184, 0xD384, 0xD584, 0xD784, 0xD984, 0xDB84, 0xDD84, 0xDF84, + 0xE104, 0xE204, 0xE304, 0xE404, 0xE504, 0xE604, 0xE704, 0xE804, + 0xE904, 0xEA04, 0xEB04, 0xEC04, 0xED04, 0xEE04, 0xEF04, 0xF004, + 0xF0C4, 0xF144, 0xF1C4, 0xF244, 0xF2C4, 0xF344, 0xF3C4, 0xF444, + 0xF4C4, 0xF544, 0xF5C4, 0xF644, 0xF6C4, 0xF744, 0xF7C4, 0xF844, + 0xF8A4, 0xF8E4, 0xF924, 0xF964, 0xF9A4, 0xF9E4, 0xFA24, 0xFA64, + 0xFAA4, 0xFAE4, 0xFB24, 0xFB64, 0xFBA4, 0xFBE4, 0xFC24, 0xFC64, + 0xFC94, 0xFCB4, 0xFCD4, 0xFCF4, 0xFD14, 0xFD34, 0xFD54, 0xFD74, + 0xFD94, 0xFDB4, 0xFDD4, 0xFDF4, 0xFE14, 0xFE34, 0xFE54, 0xFE74, + 0xFE8C, 0xFE9C, 0xFEAC, 0xFEBC, 0xFECC, 0xFEDC, 0xFEEC, 0xFEFC, + 0xFF0C, 0xFF1C, 0xFF2C, 0xFF3C, 0xFF4C, 0xFF5C, 0xFF6C, 0xFF7C, + 0xFF88, 0xFF90, 0xFF98, 0xFFA0, 0xFFA8, 0xFFB0, 0xFFB8, 0xFFC0, + 0xFFC8, 0xFFD0, 0xFFD8, 0xFFE0, 0xFFE8, 0xFFF0, 0xFFF8, 0x0000 +}; + +/* ALAW table */ +static unsigned short a2s[] = { +/* part 2 (positive) */ +0x1500, 0x1400, 0x1700, 0x1600, 0x1100, 0x1000, 0x1300, 0x1200, +0x1D00, 0x1C00, 0x1F00, 0x1E00, 0x1900, 0x1800, 0x1B00, 0x1A00, +0x0A80, 0x0A00, 0x0B80, 0x0B00, 0x0880, 0x0800, 0x0980, 0x0900, +0x0E80, 0x0E00, 0x0F80, 0x0F00, 0x0C80, 0x0C00, 0x0D80, 0x0D00, +0x5400, 0x5000, 0x5C00, 0x5800, 0x4400, 0x4000, 0x4C00, 0x4800, +0x7400, 0x7000, 0x7C00, 0x7800, 0x6400, 0x6000, 0x6C00, 0x6800, +0x2A00, 0x2800, 0x2E00, 0x2C00, 0x2200, 0x2000, 0x2600, 0x2400, +0x3A00, 0x3800, 0x3E00, 0x3C00, 0x3200, 0x3000, 0x3600, 0x3400, +0x0150, 0x0140, 0x0170, 0x0160, 0x0110, 0x0100, 0x0130, 0x0120, +0x01D0, 0x01C0, 0x01F0, 0x01E0, 0x0190, 0x0180, 0x01B0, 0x01A0, +0x0050, 0x0040, 0x0070, 0x0060, 0x0010, 0x0000, 0x0030, 0x0020, +0x00D0, 0x00C0, 0x00F0, 0x00E0, 0x0090, 0x0080, 0x00B0, 0x00A0, +0x0540, 0x0500, 0x05C0, 0x0580, 0x0440, 0x0400, 0x04C0, 0x0480, +0x0740, 0x0700, 0x07C0, 0x0780, 0x0640, 0x0600, 0x06C0, 0x0680, +0x02A0, 0x0280, 0x02E0, 0x02C0, 0x0220, 0x0200, 0x0260, 0x0240, +0x03A0, 0x0380, 0x03E0, 0x03C0, 0x0320, 0x0300, 0x0360, 0x0340, + +/* part 1 (negative) */ +0xEB00, 0xEC00, 0xE900, 0xEA00, 0xEF00, 0xF000, 0xED00, 0xEE00, +0xE300, 0xE400, 0xE100, 0xE200, 0xE700, 0xE800, 0xE500, 0xE600, +0xF580, 0xF600, 0xF480, 0xF500, 0xF780, 0xF800, 0xF680, 0xF700, +0xF180, 0xF200, 0xF080, 0xF100, 0xF380, 0xF400, 0xF280, 0xF300, +0xAC00, 0xB000, 0xA400, 0xA800, 0xBC00, 0xC000, 0xB400, 0xB800, +0x8C00, 0x9000, 0x8400, 0x8800, 0x9C00, 0xA000, 0x9400, 0x9800, +0xD600, 0xD800, 0xD200, 0xD400, 0xDE00, 0xE000, 0xDA00, 0xDC00, +0xC600, 0xC800, 0xC200, 0xC400, 0xCE00, 0xD000, 0xCA00, 0xCC00, +0xFEB0, 0xFEC0, 0xFE90, 0xFEA0, 0xFEF0, 0xFF00, 0xFED0, 0xFEE0, +0xFE30, 0xFE40, 0xFE10, 0xFE20, 0xFE70, 0xFE80, 0xFE50, 0xFE60, +0xFFB0, 0xFFC0, 0xFF90, 0xFFA0, 0xFFF0, 0x0000, 0xFFD0, 0xFFE0, +0xFF30, 0xFF40, 0xFF10, 0xFF20, 0xFF70, 0xFF80, 0xFF50, 0xFF60, +0xFAC0, 0xFB00, 0xFA40, 0xFA80, 0xFBC0, 0xFC00, 0xFB40, 0xFB80, +0xF8C0, 0xF900, 0xF840, 0xF880, 0xF9C0, 0xFA00, 0xF940, 0xF980, +0xFD60, 0xFD80, 0xFD20, 0xFD40, 0xFDE0, 0xFE00, 0xFDA0, 0xFDC0, +0xFC60, 0xFC80, 0xFC20, 0xFC40, 0xFCE0, 0xFD00, 0xFCA0, 0xFCC0 +}; + +static u_char __wp_lin2mu[16384]; +static u_char __wp_lin2a[16384]; +static short __wp_mulaw[256]; +static short __wp_alaw[256]; + + +#define ZEROTRAP /* turn on the trap as per the MIL-STD */ +#define BIAS 0x84 /* define the add-in bias for 16 bit samples */ +#define CLIP 32635 + + +static unsigned char __init +__wp_lineartoulaw(short sample) +{ + static int exp_lut[256] = {0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7}; + int sign, exponent, mantissa; + unsigned char ulawbyte; + + /* Get the sample into sign-magnitude. */ + sign = (sample >> 8) & 0x80; /* set aside the sign */ + if (sign != 0) sample = -sample; /* get magnitude */ + if (sample > CLIP) sample = CLIP; /* clip the magnitude */ + + /* Convert from 16 bit linear to ulaw. */ + sample = sample + BIAS; + exponent = exp_lut[(sample >> 7) & 0xFF]; + mantissa = (sample >> (exponent + 3)) & 0x0F; + ulawbyte = ~(sign | (exponent << 4) | mantissa); +#ifdef ZEROTRAP + if (ulawbyte == 0) ulawbyte = 0x02; /* optional CCITT trap */ +#endif + if (ulawbyte == 0xff) ulawbyte = 0x7f; /* never return 0xff */ + return(ulawbyte); +} + +#define AMI_MASK 0x55 + +static inline unsigned char __init +__wp_lineartoalaw (short linear) +{ + int mask; + int seg; + int pcm_val; + static int seg_end[8] = + { + 0xFF, 0x1FF, 0x3FF, 0x7FF, 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF + }; + + pcm_val = linear; + if (pcm_val >= 0) + { + /* Sign (7th) bit = 1 */ + mask = AMI_MASK | 0x80; + } + else + { + /* Sign bit = 0 */ + mask = AMI_MASK; + pcm_val = -pcm_val; + } + + /* Convert the scaled magnitude to segment number. */ + for (seg = 0; seg < 8; seg++) + { + if (pcm_val <= seg_end[seg]) + break; + } + /* Combine the sign, segment, and quantization bits. */ + return ((seg << 4) | ((pcm_val >> ((seg) ? (seg + 3) : 4)) & 0x0F)) ^ mask; +} + + +static inline short int __init wp_alaw2linear (uint8_t alaw) +{ + int i; + int seg; + + alaw ^= AMI_MASK; + i = ((alaw & 0x0F) << 4); + seg = (((int) alaw & 0x70) >> 4); + if (seg) + i = (i + 0x100) << (seg - 1); + return (short int) ((alaw & 0x80) ? i : -i); +} + + + +static int wanpipe_codec_convert_law2s(u8 *data, + int len, + u16 *buf, + u32 *power_ptr, + enum wan_codec_source_format src_codec, + u8 usr) +{ + int i; + u16 power=0; + short *codec; + unsigned short *pcodec; + + len = len*2; + + if (src_codec == WP_MULAW){ + codec=__wp_mulaw; + pcodec=u2s; + }else{ + codec=__wp_alaw; + pcodec=a2s; + } + + for (i=0;i>2]; + }else{ + buf[i] = codec[data[i]>>2]; + } + } + + return len; +} + + + +/************* PUBLIC FUNCTIONS *********************/ + +int wanpipe_codec_convert_ulaw_2_s(u8 *data, + int len, + u16 *buf, + u32 *power_ptr, u8 usr) +{ + return wanpipe_codec_convert_law2s(data, + len, + buf, + power_ptr, + WP_MULAW,usr); +} + +int wanpipe_codec_convert_alaw_2_s(u8 *data, + int len, + u16 *buf, + u32 *power_ptr,u8 usr) +{ + return wanpipe_codec_convert_law2s(data, + len, + buf, + power_ptr, + WP_ALAW,usr); +} + + +int wanpipe_codec_convert_s_2_ulaw(u16 *data, + int len, + u8 *buf,u8 usr) +{ + return wanpipe_codec_convert_s2law(data, + len, + buf, + WP_MULAW,usr); +} + +int wanpipe_codec_convert_s_2_alaw(u16 *data, + int len, + u8 *buf,u8 usr) +{ + return wanpipe_codec_convert_s2law(data, + len, + buf, + WP_ALAW,usr); +} + + + +int wanpipe_codec_law_init(void) +{ + int i; + + for(i = -32768; i < 32768; i += 4) { + __wp_lin2mu[((unsigned short)(short)i) >> 2] = __wp_lineartoulaw(i); + __wp_lin2a[((unsigned short)(short)i) >> 2] = __wp_lineartoalaw(i); + } + + for(i = 0;i < 256;i++) { + short mu,e,f,y; + static short etab[]={0,132,396,924,1980,4092,8316,16764}; + + mu = 255-i; + e = (mu & 0x70)/16; + f = mu & 0x0f; + y = f * (1 << (e + 3)); + y += etab[e]; + if (mu & 0x80) y = -y; + __wp_mulaw[i] = y; + __wp_alaw[i] = wp_alaw2linear(i); + } + + return 0; +} diff -Nur linux.org/drivers/net/wan/wanpipe_linux_iface.c linux-2.6.17/drivers/net/wan/wanpipe_linux_iface.c --- linux.org/drivers/net/wan/wanpipe_linux_iface.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/drivers/net/wan/wanpipe_linux_iface.c 2006-08-30 10:07:17.000000000 +0000 @@ -0,0 +1,525 @@ +/**************************************************************************** +* wanpipe_main.c WANPIPE(tm) OpenSource WANPIPe Driver. +* +* Author: Alex Feldman +* +* +* Copyright: (c) 2004 Sangoma Technologies Inc. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version +* 2 of the License, or (at your option) any later version. +* ============================================================================ +* Jan 28, 2004 Alex Feldman Initial version. +*****************************************************************************/ + +#if defined (__LINUX__) + +# include +# include +# include /* WAN router definitions */ +# include +# include /* WANPIPE common user API definitions */ +# include +# include +# include +# include + +#else + +# error "Only Linux OS support HDLC interface!" + +#endif + +/****** Defines & Macros ****************************************************/ + +#ifdef _DEBUG_ +#define STATIC +#else +#define STATIC static +#endif + +/****** Function Prototypes *************************************************/ +static netdevice_t* wan_iface_alloc (int, int); +static void wan_iface_free (netdevice_t*); +static int wan_iface_attach (netdevice_t*, char*,int is_netdev); +static int wan_iface_attach_eth (netdevice_t* dev, char *ifname, int is_netdev); +static void wan_iface_detach (netdevice_t*, int); +static int wan_iface_init(netdevice_t* dev); +static int wan_iface_eth_init(netdevice_t* dev); +static int wan_iface_input(netdevice_t*, netskb_t*); +static int wan_iface_set_proto(netdevice_t*, struct ifreq*); + + +static int wan_iface_open(netdevice_t*); +static int wan_iface_close(netdevice_t*); +static int wan_iface_send(netskb_t*, netdevice_t*); +static int wan_iface_ioctl(netdevice_t*, struct ifreq*, int); +static struct net_device_stats* wan_iface_get_stats (netdevice_t*); +static void wan_iface_tx_timeout (netdevice_t*); + +#ifdef CONFIG_PRODUCT_WANPIPE_GENERIC +static int wan_iface_hdlc_attach(hdlc_device*, unsigned short,unsigned short); +#endif + +/****** Global Data *********************************************************/ +wan_iface_t wan_iface = +{ + wan_iface_alloc, /* alloc */ + wan_iface_free, /* free */ + wan_iface_attach, /* attach */ + wan_iface_detach, /* detach */ + wan_iface_input, /* input */ + wan_iface_set_proto, /* set_proto */ + wan_iface_attach_eth /* attach ethernet interface */ +}; + +/******* WAN Device Driver Entry Points *************************************/ + +static netdevice_t* wan_iface_alloc (int is_netdev, int ifType) +{ + netdevice_t *dev; + int err; + unsigned char tmp_name[]="wan"; +#ifdef CONFIG_PRODUCT_WANPIPE_GENERIC + hdlc_device* hdlc; +#endif + + /* Register in HDLC device */ + if (is_netdev){ + dev = wan_netif_alloc(tmp_name,ifType,&err); + if (dev == NULL) { + return NULL; + } + + }else{ +#ifdef CONFIG_PRODUCT_WANPIPE_GENERIC + hdlc = (hdlc_device*)wan_malloc(sizeof(hdlc_device)); + if (hdlc == NULL) { + return NULL; + } + dev = hdlc_to_dev(hdlc); +#else + DEBUG_EVENT("%s: Critical Compile Error %i!\n",__FUNCTION__,__LINE__); + dev = NULL; +#endif + } + return dev; +} + +static void wan_iface_free(netdevice_t* dev) +{ + /* On 2.4 kernels device is freed + * on unregisger_netdev. However, + * on 2.6 kernels we must call free + * ouselves. + * + * IMPORTANT: This function should + * only be used by outside code. + * + * For internal use wan_netif_free(dev) */ + +#ifdef LINUX_2_4 + return; +#else + wan_netif_free(dev); + return; +#endif +} + + +static int wan_iface_attach_eth (netdevice_t* dev, char *ifname, int is_netdev) +{ + int err = 0; + if (is_netdev){ + if (ifname){ + wan_netif_init(dev, ifname); + } + dev->init = &wan_iface_eth_init; + err=register_netdev(dev); + }else{ +#ifdef CONFIG_PRODUCT_WANPIPE_GENERIC + hdlc_device* hdlc = dev_to_hdlc(dev); + + hdlc->attach = wan_iface_hdlc_attach; + hdlc->xmit = wan_iface_send; + + err = register_hdlc_device(hdlc); +#else + err = -EINVAL; +#endif + } + if (err){ + DEBUG_EVENT("%s: Failed to register interface (%d)\n", + wan_netif_name(dev), err); + dev->init = NULL; + *(dev->name) = 0; + wan_netif_free(dev); + return -EINVAL; + } + return 0; +} + + +static int wan_iface_attach (netdevice_t* dev, char *ifname, int is_netdev) +{ + int err = 0; + if (is_netdev){ + if (ifname){ + wan_netif_init(dev, ifname); + } + dev->init = &wan_iface_init; + err=register_netdev(dev); + }else{ +#ifdef CONFIG_PRODUCT_WANPIPE_GENERIC + hdlc_device* hdlc = dev_to_hdlc(dev); + + hdlc->attach = wan_iface_hdlc_attach; + hdlc->xmit = wan_iface_send; + + err = register_hdlc_device(hdlc); +#else + err = -EINVAL; +#endif + } + if (err){ + DEBUG_EVENT("%s: Failed to register interface (%d)\n", + wan_netif_name(dev), err); + dev->init = NULL; + *(dev->name) = 0; + wan_netif_free(dev); + return -EINVAL; + } + return 0; +} + +static void wan_iface_detach (netdevice_t* dev, int is_netdev) +{ + DEBUG_EVENT("%s: Unregister interface!\n", + wan_netif_name(dev)); + if (is_netdev){ + if (dev->priv){ + dev->priv=NULL; + } + unregister_netdev(dev); + + }else{ +#ifdef CONFIG_PRODUCT_WANPIPE_GENERIC + unregister_hdlc_device(dev_to_hdlc(dev)); +#else + DEBUG_EVENT("%s: Compilation Assertion Error! %d\n",__FUNCTION__,__LINE__); +#endif + } + return; +} + + +static int wan_iface_init(netdevice_t* dev) +{ +// dev->priv = NULL; /* We need 'priv', hdlc doesn't */ + dev->get_stats = &wan_iface_get_stats; + dev->do_ioctl = &wan_iface_ioctl; + dev->open = &wan_iface_open; + dev->stop = &wan_iface_close; + + dev->hard_header = NULL; + dev->rebuild_header = NULL; + dev->hard_start_xmit = &wan_iface_send; + dev->get_stats = &wan_iface_get_stats; + dev->tx_timeout = &wan_iface_tx_timeout; + dev->watchdog_timeo = HZ*2; + dev->hard_header_len = 32; + dev->set_config = NULL; + + /* Initialize media-specific parameters */ + dev->flags |= IFF_POINTOPOINT; + dev->flags |= IFF_NOARP; + + if (!dev->mtu) { + dev->mtu = 1500; + } + dev->tx_queue_len = 100; + dev->type = ARPHRD_PPP; + dev->addr_len = 0; + *(u8*)dev->dev_addr = 0; + + dev->trans_start = SYSTEM_TICKS; + + /* Initialize socket buffers */ + dev_init_buffers(dev); + + DEBUG_TEST("%s: %s:%d %p\n", + dev->name, + __FUNCTION__,__LINE__, + dev->priv); + + return 0; +} + +static int wan_iface_eth_init(netdevice_t* dev) +{ + int hw_addr=0; + +// dev->priv = NULL; /* We need 'priv', hdlc doesn't */ + dev->get_stats = &wan_iface_get_stats; + dev->do_ioctl = &wan_iface_ioctl; + dev->open = &wan_iface_open; + dev->stop = &wan_iface_close; + + dev->hard_header = NULL; + dev->rebuild_header = NULL; + dev->hard_start_xmit = &wan_iface_send; + dev->get_stats = &wan_iface_get_stats; + dev->tx_timeout = &wan_iface_tx_timeout; + dev->watchdog_timeo = HZ*2; + dev->hard_header_len = 32; + dev->set_config = NULL; + + if (!dev->mtu) { + dev->mtu = 1500; + } + dev->tx_queue_len = 100; + + dev->trans_start = SYSTEM_TICKS; + + /* Initialize socket buffers */ + dev_init_buffers(dev); + + + /* Setup the interface for Bridging */ + ether_setup(dev); + + /* Use a random number to generate the MAC address */ + memcpy(dev->dev_addr, "\xFE\xFC\x00\x00\x00\x00", 6); + get_random_bytes(&hw_addr, sizeof(hw_addr)); + *(int *)(dev->dev_addr + 2) += hw_addr; + + dev->hard_header_len = 32; + dev->tx_queue_len = 100; + + DEBUG_TEST("%s: %s:%d %p\n", + dev->name, + __FUNCTION__,__LINE__, + dev->priv); + + return 0; +} + + +static int wan_iface_open(netdevice_t* dev) +{ + wanpipe_common_t *common; + int err; +#ifdef CONFIG_PRODUCT_WANPIPE_GENERIC + void *org_priv; +#endif + + WAN_ASSERT(wan_netif_priv(dev) == NULL); + common = wan_netif_priv(dev); + +#ifdef CONFIG_PRODUCT_WANPIPE_GENERIC + /* Save original private pointer and restore it later after returning + * from hdlc_open function call (Linux-2.6 overwrite private pointer. */ + org_priv = wan_netif_priv(dev); + hdlc_open(dev_to_hdlc(dev)); + wan_netif_set_priv(dev, org_priv); +#endif + + DEBUG_TEST("%s: OPEN \n",dev->name); + + if (common->iface.open){ + err = common->iface.open(dev); +#ifdef CONFIG_PRODUCT_WANPIPE_GENERIC + if (err){ + hdlc_close(dev_to_hdlc(dev)); + } +#endif + return err; + } + return -EINVAL; +} + +static int wan_iface_close(netdevice_t* dev) +{ + wanpipe_common_t *common; + int err; + + WAN_ASSERT(wan_netif_priv(dev) == NULL); + common = wan_netif_priv(dev); + if (common->iface.close){ + err = common->iface.close(dev); +#ifdef CONFIG_PRODUCT_WANPIPE_GENERIC + hdlc_close(dev_to_hdlc(dev)); +#endif + return err; + } + return -EINVAL; +} + +static int wan_iface_send(netskb_t* skb, netdevice_t* dev) +{ + wanpipe_common_t *common; + + WAN_ASSERT(wan_netif_priv(dev) == NULL); + common = wan_netif_priv(dev); + if (common->iface.send){ + return common->iface.send(skb, dev); + }else{ + wan_skb_free(skb); + } + return 0; +} + +static int wan_iface_ioctl(netdevice_t* dev, struct ifreq* ifr, int cmd) +{ + wanpipe_common_t *common; + int err = -EOPNOTSUPP; + + WAN_ASSERT(wan_netif_priv(dev) == NULL); + +#if 0 + DEBUG_EVENT("%s: %s:%d\n",dev->name,__FUNCTION__,__LINE__); + return err; +#endif + common = wan_netif_priv(dev); + switch(cmd){ + + default: + if (common->iface.ioctl){ + err = common->iface.ioctl(dev, ifr, cmd); + } + break; + } + if (err == 1){ +#ifdef CONFIG_PRODUCT_WANPIPE_GENERIC + err = hdlc_ioctl(dev, ifr, cmd); +#else + err = -EINVAL; +#endif + } + return err; +} + +/* Get ethernet-style interface statistics. + * Return a pointer to struct enet_statistics. + */ +static struct net_device_stats gif_stats; +static struct net_device_stats* wan_iface_get_stats (netdevice_t* dev) +{ + wanpipe_common_t *common; + +#if 0 +NC: This is not an error +On shutdown, this is possible + WAN_ASSERT2(wan_netif_priv(dev) == NULL, NULL); +#endif + + common = wan_netif_priv(dev); + if (common && common->iface.get_stats){ + return common->iface.get_stats(dev); + }else{ + return &gif_stats; + } + return NULL; +} + +/*============================================================================ + * Handle transmit timeout event from netif watchdog + */ +static void wan_iface_tx_timeout (netdevice_t *dev) +{ + wanpipe_common_t *common; + + WAN_ASSERT1(wan_netif_priv(dev) == NULL); + common = wan_netif_priv(dev); + /* If our device stays busy for at least 5 seconds then we will + * kick start the device by making dev->tbusy = 0. We expect + * that our device never stays busy more than 5 seconds. So this + * is only used as a last resort. + */ + if (common->iface.tx_timeout){ + common->iface.tx_timeout(dev); + } + return; +} + +static int wan_iface_input(netdevice_t* dev, netskb_t* skb) +{ + wanpipe_common_t *common; + + WAN_ASSERT(wan_netif_priv(dev) == NULL); + common = wan_netif_priv(dev); + +#ifdef CONFIG_PRODUCT_WANPIPE_GENERIC + if (!common->is_netdev){ + skb->protocol = htons(ETH_P_HDLC); + skb->dev = dev; + skb->mac.raw = skb->data; + skb->nh.raw = skb->data; + } +#endif + + netif_rx(skb); + return 0; +} + +#ifdef CONFIG_PRODUCT_WANPIPE_GENERIC +static int +wan_iface_hdlc_attach(hdlc_device * hdlc, unsigned short encoding, unsigned short parity) +{ + return 0; +} +#endif + +static int wan_iface_set_proto(netdevice_t* dev, struct ifreq* ifr) +{ + wanpipe_common_t* common; + int err = 0; + + + if ((common = wan_netif_priv(dev)) == NULL){ + DEBUG_EVENT("%s: Private structure is null!\n", + wan_netif_name(dev)); + return -EINVAL; + } + +#ifdef CONFIG_PRODUCT_WANPIPE_GENERIC + { + struct if_settings* ifsettings; + ifsettings = (struct if_settings*)ifr->ifr_data; + + + case IF_PROTO_PPP: + case IF_PROTO_CISCO: + case IF_PROTO_FR: + common->protocol = + (ifsettings->type == IF_PROTO_PPP) ? WANCONFIG_PPP : + (ifsettings->type == IF_PROTO_CISCO) ? WANCONFIG_CHDLC : + WANCONFIG_FR; + if (common->protocol == WANCONFIG_PPP){ + hdlc_device* hdlc = dev_to_hdlc(dev); + ((wanpipe_common_t*)dev->priv)->prot_ptr = + (netdevice_t*)&hdlc->state.ppp.pppdev; +#if defined(LINUX2_6) + hdlc->state.ppp.syncppp_ptr = (struct ppp_device*) + ((wanpipe_common_t*)dev->priv)->prot_ptr; +#endif + } + + + err = hdlc_ioctl(dev, ifr, SIOCWANDEV); + break; + default: + err = -EINVAL; + break; + } + } + +#else + err = -EINVAL; +#endif + return err; +} + +/************************************ END **********************************/ diff -Nur linux.org/drivers/net/wan/wanpipe.mod.c linux-2.6.17/drivers/net/wan/wanpipe.mod.c --- linux.org/drivers/net/wan/wanpipe.mod.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/drivers/net/wan/wanpipe.mod.c 2006-08-30 10:07:17.000000000 +0000 @@ -0,0 +1,28 @@ +#include +#include +#include + +MODULE_INFO(vermagic, VERMAGIC_STRING); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,6) || defined(WANPIPE_MOD_266_FORCE_UPDATE) +#undef unix +struct module __this_module +__attribute__((section(".gnu.linkonce.this_module"))) = { + .name = __stringify(KBUILD_MODNAME), + .init = init_module, +#ifdef CONFIG_MODULE_UNLOAD + .exit = cleanup_module, +#endif +}; +#endif + +static const struct modversion_info ____versions[] +__attribute__((section("__versions"))) = { + +}; + +static const char __module_depends[] +__attribute_used__ +__attribute__((section(".modinfo"))) = +"depends=wanrouter,sdladrv"; + diff -Nur linux.org/drivers/net/wan/wanpipe_multppp.c linux-2.6.17/drivers/net/wan/wanpipe_multppp.c --- linux.org/drivers/net/wan/wanpipe_multppp.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/drivers/net/wan/wanpipe_multppp.c 2006-08-30 10:07:17.000000000 +0000 @@ -0,0 +1,3627 @@ +/***************************************************************************** +* wanpipe_multppp.c Multi-Port PPP driver module. +* +* Authors: Nenad Corbic +* +* Copyright: (c) 1995-2001 Sangoma Technologies Inc. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version +* 2 of the License, or (at your option) any later version. +* ============================================================================ +* Apr 12, 2003 Nenad Corbic Added MPAPI Annexg Support as well as the +* new tracing package. +* Mar 26, 2003 David Rokhvarg Added PAP and CHAP support. Only as a peer, +* not an authenticator. +* Sep 20, 2001 Nenad Corbic The min() function has changed for 2.4.9 +* kernel. Thus using the wp_min() defined in +* wanpipe.h + +* May 29 2001 Nenad Corbic Added T1/E1 support (TE1). +* Apr 15 2001 Nenad Corbic Bug Fix (2.2.X kernel) Driver +* crashed on shutdown while mrouted +* was running. The dev->do_ioctl call +* was still bound to syncppp after +* syncpp_detach(). +* Dec 15 2000 Nenad Corbic Updated for 2.4.X kernel +* Nov 15 2000 Nenad Corbic Fixed the SyncPPP support for +* kernels 2.2.16 and higher. +* The pppstruct has changed. +* Jul 13 2000 Nenad Corbic Using the kernel Syncppp module on +* top of RAW Wanpipe CHDLC module. +*****************************************************************************/ + +#include +#include +#include +#include +#include +#include /* WAN router definitions */ +#include /* WANPIPE common user API definitions */ +#include +#include +#include /* CHDLC firmware API definitions */ +#include /* CHDLC (async) API definitions */ +#include /* Socket Driver common area */ +#include +#include + +#ifdef CONFIG_PRODUCT_WANPIPE_ANNEXG +# include "wanpipe_lapb_kernel.h" +#endif + +/****** Defines & Macros ****************************************************/ + +#ifdef _DEBUG_ +#define STATIC +#else +#define STATIC static +#endif + +/* reasons for enabling the timer interrupt on the adapter */ +#define TMR_INT_ENABLED_UDP 0x01 +#define TMR_INT_ENABLED_UPDATE 0x02 +#define TMR_INT_ENABLED_CONFIG 0x04 +#define TMR_INT_ENABLED_TE 0x20 + + +#define CHDLC_DFLT_DATA_LEN 1500 /* default MTU */ +#define CHDLC_HDR_LEN 1 + +#define IFF_POINTTOPOINT 0x10 + +#define CHDLC_API 0x01 + +#define PORT(x) (x == 0 ? "PRIMARY" : "SECONDARY" ) +#define MAX_BH_BUFF 10 + +#define CRC_LENGTH 2 +#define PPP_HEADER_LEN 4 + +#define MAX_TRACE_QUEUE 100 +#define MAX_TRACE_BUFFER WAN_MAX_DATA_SIZE + +#define MAX_RX_QUEUE 100 +/******Data Structures*****************************************************/ + +/* This structure is placed in the private data area of the device structure. + * The card structure used to occupy the private area but now the following + * structure will incorporate the card structure along with CHDLC specific data + */ + +typedef struct private_area +{ + wanpipe_common_t common; + sdla_t *card; + netdevice_t *dev; + unsigned long router_start_time; + unsigned char route_status; + unsigned char route_removed; + unsigned long tick_counter; /* For 5s timeout counter */ + unsigned long router_up_time; + unsigned char mc; /* Mulitcast support on/off */ + char update_comms_stats; /* updating comms stats */ + + /* Entry in proc fs per each interface */ + struct proc_dir_entry* dent; + + unsigned char ignore_modem; + + char udp_pkt_src; + unsigned char udp_pkt_data[sizeof(wan_udp_pkt_t)+10]; + atomic_t udp_pkt_len; + + wan_trace_t trace_info; + wan_tasklet_t tasklet; + wan_skb_queue_t rx_queue; + + char if_name[WAN_IFNAME_SZ+1]; + netdevice_t *annexg_dev; + unsigned char label[WAN_IF_LABEL_SZ+1]; + + unsigned char prev_error; + +} private_area_t; + +/* Route Status options */ +#define NO_ROUTE 0x00 +#define ADD_ROUTE 0x01 +#define ROUTE_ADDED 0x02 +#define REMOVE_ROUTE 0x03 + + +/* variable for keeping track of enabling/disabling FT1 monitor status */ +static int rCount = 0; + +/* variable for tracking how many interfaces to open for WANPIPE on the + two ports */ + +extern void disable_irq(unsigned int); +extern void enable_irq(unsigned int); + +/****** Function Prototypes *************************************************/ +/* WAN link driver entry points. These are called by the WAN router module. */ +static int update (wan_device_t* wandev); +static int new_if (wan_device_t* wandev, netdevice_t* dev, + wanif_conf_t* conf); +static int del_if (wan_device_t* wandev, netdevice_t* dev); + +/* Network device interface */ +static int if_init (netdevice_t* dev); +static int if_open (netdevice_t* dev); +static int if_close (netdevice_t* dev); +static int if_send (struct sk_buff* skb, netdevice_t* dev); +static struct net_device_stats* if_stats (netdevice_t* dev); + +static void if_tx_timeout (netdevice_t *dev); + +/* CHDLC Firmware interface functions */ +static int chdlc_configure (sdla_t* card, void* data); +static int chdlc_comm_enable (sdla_t* card); +static int chdlc_comm_disable (sdla_t* card); +static int chdlc_read_version (sdla_t* card, char* str); +static int chdlc_set_intr_mode (sdla_t* card, unsigned mode); +static int set_adapter_config (sdla_t* card); +static int chdlc_send (sdla_t* card, void* data, unsigned len); +static int chdlc_read_comm_err_stats (sdla_t* card); +static int chdlc_read_op_stats (sdla_t* card); +static int config_chdlc (sdla_t *card); + + +/* Miscellaneous CHDLC Functions */ +static int set_chdlc_config (sdla_t* card); +static int set_asy_config(sdla_t* card); +static int asy_comm_enable (sdla_t* card); +static void init_chdlc_tx_rx_buff( sdla_t* card, netdevice_t *dev ); +static int chdlc_error (sdla_t *card, int err, wan_mbox_t *mb); +static int process_chdlc_exception(sdla_t *card); +static int process_global_exception(sdla_t *card); +static int update_comms_stats(sdla_t* card, + private_area_t* chan); +static void port_set_state (sdla_t *card, int); + +/* Interrupt handlers */ +static void wsppp_isr (sdla_t* card); +static void rx_intr (sdla_t* card); +static void timer_intr(sdla_t *); + +/* Miscellaneous functions */ +static int intr_test( sdla_t* card); +static int udp_pkt_type( struct sk_buff *skb , sdla_t* card); +static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, + struct sk_buff *skb, netdevice_t* dev, + private_area_t* chan); +static int process_udp_mgmt_pkt(sdla_t* card, netdevice_t* dev, + private_area_t* chan,int local_dev); +static void s508_lock (sdla_t *card, unsigned long *smp_flags); +static void s508_unlock (sdla_t *card, unsigned long *smp_flags); +static void send_ppp_term_request (netdevice_t*); + + +static int chdlc_get_config_info(void* priv, struct seq_file* m, int*); +static int chdlc_get_status_info(void* priv, struct seq_file* m, int*); +static int chdlc_set_dev_config(struct file*, const char*, unsigned long, void *); +static int chdlc_set_if_info(struct file*, const char*, unsigned long, void *); +static int if_do_ioctl(netdevice_t *dev, struct ifreq *ifr, int cmd); +static void chdlc_enable_timer (void* card_id); +static void wp_bh (unsigned long data); + + +#ifdef CONFIG_PRODUCT_WANPIPE_ANNEXG +static int bind_annexg(netdevice_t *dev, netdevice_t *annexg_dev); +static netdevice_t * un_bind_annexg(wan_device_t *wandev, netdevice_t* annexg_dev_name); +static int get_map(wan_device_t*, netdevice_t*, struct seq_file* m, int*); +static void get_active_inactive(wan_device_t *wandev, netdevice_t *dev, + void *wp_stats); +#endif + + +/* TE1 */ +static WRITE_FRONT_END_REG_T write_front_end_reg; +static READ_FRONT_END_REG_T read_front_end_reg; +static void handle_front_end_state(void* card_id); + +/****** Public Functions ****************************************************/ + +/*============================================================================ + * Cisco HDLC protocol initialization routine. + * + * This routine is called by the main WANPIPE module during setup. At this + * point adapter is completely initialized and firmware is running. + * o read firmware version (to make sure it's alive) + * o configure adapter + * o initialize protocol-specific fields of the adapter data space. + * + * Return: 0 o.k. + * < 0 failure. + */ +int wp_mprot_init (sdla_t* card, wandev_conf_t* conf) +{ + unsigned char port_num; + int err; + u_int32_t max_permitted_baud = 0; + union + { + char str[80]; + } u; + volatile wan_mbox_t* mb; + wan_mbox_t* mb1; + unsigned long timeout; + + /* Verify configuration ID */ + if (conf->config_id != WANCONFIG_MPPP) { + printk(KERN_INFO "%s: invalid configuration ID %u!\n", + card->devname, conf->config_id); + return -EINVAL; + } + + /* Find out which Port to use */ + if ((conf->comm_port == WANOPT_PRI) || (conf->comm_port == WANOPT_SEC)){ + if (card->next){ + + if (conf->comm_port != card->next->u.c.comm_port){ + card->u.c.comm_port = conf->comm_port; + }else{ + printk(KERN_INFO "%s: ERROR - %s port used!\n", + card->wandev.name, PORT(conf->comm_port)); + return -EINVAL; + } + }else{ + card->u.c.comm_port = conf->comm_port; + } + }else{ + printk(KERN_INFO "%s: ERROR - Invalid Port Selected!\n", + card->wandev.name); + return -EINVAL; + } + + + /* Initialize protocol-specific fields */ + /* Set a pointer to the actual mailbox in the allocated virtual + * memory area */ + /* Alex Apr 8 2004 Sangoma ISA card */ + if (card->u.c.comm_port == WANOPT_PRI){ + card->mbox_off = PRI_BASE_ADDR_MB_STRUCT; + }else{ + card->mbox_off = SEC_BASE_ADDR_MB_STRUCT; + } + + mb = &card->wan_mbox; + mb1 = &card->wan_mbox; + + if (!card->configured){ + unsigned char return_code; + /* The board will place an 'I' in the return code to indicate that it is + ready to accept commands. We expect this to be completed in less + than 1 second. */ + + timeout = jiffies; + /* Wait 1s for board to initialize */ + do { + return_code = 0x00; + card->hw_iface.peek(card->hw, + card->mbox_off+offsetof(wan_mbox_t, wan_return_code), + &return_code, + sizeof(unsigned char)); + if ((jiffies - timeout) > 1*HZ) break; + }while(return_code != 'I'); + if (return_code != 'I') { + printk(KERN_INFO + "%s: Initialization not completed by adapter\n", + card->devname); + printk(KERN_INFO "Please contact Sangoma representative.\n"); + return -EIO; + } + } + + err = (card->hw_iface.check_mismatch) ? + card->hw_iface.check_mismatch(card->hw,conf->fe_cfg.media) : -EINVAL; + if (err){ + return err; + } + + /* TE1 Make special hardware initialization for T1/E1 board */ + if (IS_TE1_MEDIA(&conf->fe_cfg)){ + + memcpy(&card->fe.fe_cfg, &conf->fe_cfg, sizeof(sdla_fe_cfg_t)); + sdla_te_iface_init(&card->wandev.fe_iface); + card->fe.name = card->devname; + card->fe.card = card; + card->fe.write_fe_reg = write_front_end_reg; + card->fe.read_fe_reg = read_front_end_reg; + + card->wandev.fe_enable_timer = chdlc_enable_timer; + card->wandev.te_link_state = handle_front_end_state; + conf->interface = + (IS_T1_CARD(card)) ? WANOPT_V35 : WANOPT_RS232; + + if (card->u.c.comm_port == WANOPT_PRI){ + conf->clocking = WANOPT_EXTERNAL; + } + + }else if (IS_56K_MEDIA(&conf->fe_cfg)){ + + memcpy(&card->fe.fe_cfg, &conf->fe_cfg, sizeof(sdla_fe_cfg_t)); + sdla_56k_iface_init(&card->wandev.fe_iface); + card->fe.name = card->devname; + card->fe.card = card; + card->fe.write_fe_reg = write_front_end_reg; + card->fe.read_fe_reg = read_front_end_reg; + + if (card->u.c.comm_port == WANOPT_PRI){ + conf->clocking = WANOPT_EXTERNAL; + } + + }else{ + card->fe.fe_status = FE_CONNECTED; + } + + card->wandev.ignore_front_end_status = conf->ignore_front_end_status; + if (card->wandev.ignore_front_end_status == WANOPT_NO){ + printk(KERN_INFO + "%s: Enabling front end link monitor\n", + card->devname); + }else{ + printk(KERN_INFO + "%s: Disabling front end link monitor\n", + card->devname); + } + + + /* Read firmware version. Note that when adapter initializes, it + * clears the mailbox, so it may appear that the first command was + * executed successfully when in fact it was merely erased. To work + * around this, we execute the first command twice. + */ + + if (chdlc_read_version(card, u.str)) + return -EIO; + + printk(KERN_INFO "%s: Running Raw HDLC firmware v%s\n" + "%s: for Multi-Port protocol.\n", + card->devname,u.str,card->devname); + + if (set_adapter_config(card)) { + return -EIO; + } + + card->isr = &wsppp_isr; + card->poll = NULL; + card->exec = NULL; + card->wandev.update = &update; + card->wandev.new_if = &new_if; + card->wandev.del_if = &del_if; + card->wandev.udp_port = conf->udp_port; + +#ifdef CONFIG_PRODUCT_WANPIPE_ANNEXG + card->wandev.bind_annexg = &bind_annexg; + card->wandev.un_bind_annexg = &un_bind_annexg; + card->wandev.get_map = &get_map; + card->wandev.get_active_inactive= &get_active_inactive; +#endif + + + card->wandev.new_if_cnt = 0; + + // Proc fs functions + card->wandev.get_config_info = &chdlc_get_config_info; + card->wandev.get_status_info = &chdlc_get_status_info; + card->wandev.set_dev_config = &chdlc_set_dev_config; + card->wandev.set_if_info = &chdlc_set_if_info; + + /* reset the number of times the 'update()' proc has been called */ + card->u.c.update_call_count = 0; + + card->wandev.ttl = conf->ttl; + card->wandev.interface = conf->interface; + + if ((card->u.c.comm_port == WANOPT_SEC && conf->interface == WANOPT_V35)&& + card->type != SDLA_S514){ + printk(KERN_INFO "%s: ERROR - V35 Interface not supported on S508 %s port \n", + card->devname, PORT(card->u.c.comm_port)); + return -EIO; + } + + + card->wandev.clocking = conf->clocking; + + port_num = card->u.c.comm_port; + + /* Setup Port Bps */ + + if(card->wandev.clocking) { + if((port_num == WANOPT_PRI) || card->u.c.receive_only) { + /* For Primary Port 0 */ + max_permitted_baud = + (card->type == SDLA_S514) ? + PRI_MAX_BAUD_RATE_S514 : + PRI_MAX_BAUD_RATE_S508; + } + else if(port_num == WANOPT_SEC) { + /* For Secondary Port 1 */ + max_permitted_baud = + (card->type == SDLA_S514) ? + SEC_MAX_BAUD_RATE_S514 : + SEC_MAX_BAUD_RATE_S508; + } + + if(conf->bps > max_permitted_baud) { + conf->bps = max_permitted_baud; + printk(KERN_INFO "%s: Baud too high!\n", + card->wandev.name); + printk(KERN_INFO "%s: Baud rate set to %u bps\n", + card->wandev.name, max_permitted_baud); + } + + card->wandev.bps = conf->bps; + }else{ + card->wandev.bps = 0; + } + + if (conf->u.chdlc.fast_isr == WANOPT_YES){ + DEBUG_EVENT("%s: Configuring Fast Interrupt Handlers\n", + card->devname); + card->u.c.protocol_options|=INSTALL_FAST_INT_HANDLERS; + } + + + /* Setup the Port MTU */ + if((port_num == WANOPT_PRI) || card->u.c.receive_only) { + + /* For Primary Port 0 */ + card->wandev.mtu = + (conf->mtu >= MIN_LGTH_CHDLC_DATA_CFG) ? + wp_min(conf->mtu, PRI_MAX_NO_DATA_BYTES_IN_FRAME) : + CHDLC_DFLT_DATA_LEN; + } else if(port_num == WANOPT_SEC) { + /* For Secondary Port 1 */ + card->wandev.mtu = + (conf->mtu >= MIN_LGTH_CHDLC_DATA_CFG) ? + wp_min(conf->mtu, SEC_MAX_NO_DATA_BYTES_IN_FRAME) : + CHDLC_DFLT_DATA_LEN; + } + + /* Add on a PPP Header */ + card->wandev.mtu += PPP_HEADER_LEN; + + /* Set up the interrupt status area */ + /* Read the CHDLC Configuration and obtain: + * Ptr to shared memory infor struct + * Use this pointer to calculate the value of card->u.c.flags ! + */ + mb1->wan_data_len = 0; + mb1->wan_command = READ_CHDLC_CONFIGURATION; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb1); + if(err != COMMAND_OK) { + wan_clear_bit(1, (void*)&card->wandev.critical); + + if(card->type != SDLA_S514) + enable_irq(card->wandev.irq/* ALEX_TODAY ard->hw.irq*/); + + chdlc_error(card, err, mb1); + return -EIO; + } + + /* Alex Apr 8 2004 Sangoma ISA card */ + card->flags_off = + ((CHDLC_CONFIGURATION_STRUCT *)mb1->wan_data)-> + ptr_shared_mem_info_struct; + + card->intr_type_off = + card->flags_off + + offsetof(SHARED_MEMORY_INFO_STRUCT, interrupt_info_struct) + + offsetof(INTERRUPT_INFORMATION_STRUCT, interrupt_type); + card->intr_perm_off = + card->flags_off + + offsetof(SHARED_MEMORY_INFO_STRUCT, interrupt_info_struct) + + offsetof(INTERRUPT_INFORMATION_STRUCT, interrupt_permission); + card->fe_status_off = + card->flags_off + + offsetof(SHARED_MEMORY_INFO_STRUCT, FT1_info_struct) + + offsetof(FT1_INFORMATION_STRUCT, parallel_port_A_input); + + /* This is for the ports link state */ + card->wandev.state = WAN_DUALPORT; + card->u.c.state = WAN_DISCONNECTED; + + + if (!card->wandev.piggyback){ + err = intr_test(card); + + if(err || (card->timer_int_enabled < MAX_INTR_TEST_COUNTER)) { + printk(KERN_INFO "%s: Interrupt test failed (%i)\n", + card->devname, card->timer_int_enabled); + printk(KERN_INFO "%s: Please choose another interrupt\n", + card->devname); + return -EIO; + } + + printk(KERN_INFO "%s: Interrupt test passed (%i)\n", + card->devname, card->timer_int_enabled); + card->configured = 1; + } + + + if (chdlc_set_intr_mode(card, APP_INT_ON_TIMER)){ + printk (KERN_INFO "%s: Failed to set interrupt triggers!\n", + card->devname); + return -EIO; + } + + /* Mask the Timer interrupt */ + card->hw_iface.clear_bit(card->hw, card->intr_perm_off, APP_INT_ON_TIMER); + + printk(KERN_INFO "\n"); + + return 0; +} + +/******* WAN Device Driver Entry Points *************************************/ + +/*============================================================================ + * Update device status & statistics + * This procedure is called when updating the PROC file system and returns + * various communications statistics. These statistics are accumulated from 3 + * different locations: + * 1) The 'if_stats' recorded for the device. + * 2) Communication error statistics on the adapter. + * 3) CHDLC operational statistics on the adapter. + * The board level statistics are read during a timer interrupt. Note that we + * read the error and operational statistics during consecitive timer ticks so + * as to minimize the time that we are inside the interrupt handler. + * + */ +static int update (wan_device_t* wandev) +{ + sdla_t* card = wandev->private; + netdevice_t* dev; + private_area_t* chan; + unsigned long smp_flags; + + /* sanity checks */ + if((wandev == NULL) || (wandev->private == NULL)) + return -EFAULT; + + if(wandev->state == WAN_UNCONFIGURED) + return -ENODEV; + + /* more sanity checks */ + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + if(dev == NULL) + return -ENODEV; + + if((chan=dev->priv) == NULL) + return -ENODEV; + + if(chan->update_comms_stats){ + return -EAGAIN; + } + + spin_lock_irqsave(&card->wandev.lock, smp_flags); + update_comms_stats(card, chan); + chan->update_comms_stats=0; + spin_unlock_irqrestore(&card->wandev.lock, smp_flags); + + return 0; +} + + +/*============================================================================ + * Create new logical channel. + * This routine is called by the router when ROUTER_IFNEW IOCTL is being + * handled. + * o parse media- and hardware-specific configuration + * o make sure that a new channel can be created + * o allocate resources, if necessary + * o prepare network device structure for registaration. + * + * Return: 0 o.k. + * < 0 failure (channel will not be created) + */ +static int new_if (wan_device_t* wandev, netdevice_t* dev, wanif_conf_t* conf) +{ + + struct ppp_device *pppdev=NULL; + struct sppp *sp=NULL; + sdla_t* card = wandev->private; + private_area_t* chan; + int err = 0; + + if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) { + printk(KERN_INFO "%s: invalid interface name!\n", + card->devname); + return -EINVAL; + } + + if(++card->wandev.new_if_cnt > 1) { + DEBUG_EVENT("%s: Error: Interface already configured!\n", + card->devname); + --card->wandev.new_if_cnt; + return -EEXIST; + } + + /* allocate and initialize private data */ + chan = kmalloc(sizeof(private_area_t), GFP_KERNEL); + + if(chan == NULL){ + --card->wandev.new_if_cnt; + return -ENOMEM; + } + + memset(chan, 0, sizeof(private_area_t)); + + chan->card = card; + + /* initialize data */ + strncpy(card->u.c.if_name, conf->name,WAN_IFNAME_SZ); + strncpy(chan->if_name,conf->name,WAN_IFNAME_SZ); + + /* Initialize the trace queue */ + if (!conf->max_trace_queue){ + conf->max_trace_queue=MAX_TRACE_QUEUE; + } + + wan_trace_info_init(&chan->trace_info,conf->max_trace_queue); + + /* Initialize the receive bh handler */ + WAN_TASKLET_INIT((&chan->tasklet), + 0, wp_bh, (unsigned long)chan); + + WAN_IFQ_INIT((&chan->rx_queue),0); + + //We don't need this any more + chan->route_status = NO_ROUTE; + chan->route_removed = 0; + + card->u.c.async_mode = conf->async_mode; + + printk(KERN_INFO "%s: Firmware running in HDLC STREAMING Mode\n", + wandev->name); + + chan->common.prot_ptr=NULL; + + /* setup for asynchronous mode */ + if(conf->async_mode) { + printk(KERN_INFO "%s: Configuring for asynchronous mode\n", + wandev->name); + + if(card->u.c.comm_port == WANOPT_PRI) { + printk(KERN_INFO + "%s:Asynchronous mode on secondary port only\n", + wandev->name); + + err=-EINVAL; + goto new_if_error; + } + + if (strcmp(conf->usedby, "API") == 0){ + printk(KERN_INFO "%s: Running in API Async Mode\n", + wandev->name); + + chan->common.usedby = API; + wan_reg_api(chan, dev, card->devname); + }else{ + DEBUG_EVENT("%s: Invalid Async Operation Mode: %s\n", + chan->if_name, conf->usedby); + err=-EINVAL; + goto new_if_error; + } + + if(!card->wandev.clocking) { + printk(KERN_INFO + "%s: Asynch. clocking must be 'Internal'\n", + wandev->name); + + err=-EINVAL; + goto new_if_error; + } + + if((card->wandev.bps < MIN_ASY_BAUD_RATE) || + (card->wandev.bps > MAX_ASY_BAUD_RATE)) { + printk(KERN_INFO "%s: Selected baud rate is invalid.\n", + wandev->name); + printk(KERN_INFO "Must be between %u and %u bps.\n", + MIN_ASY_BAUD_RATE, MAX_ASY_BAUD_RATE); + + err=-EINVAL; + goto new_if_error; + } + + card->u.c.api_options = 0; + if (conf->asy_data_trans == WANOPT_YES) { + card->u.c.api_options |= ASY_RX_DATA_TRANSPARENT; + } + + card->u.c.protocol_options = 0; + if (conf->rts_hs_for_receive == WANOPT_YES) { + card->u.c.protocol_options |= ASY_RTS_HS_FOR_RX; + } + if (conf->xon_xoff_hs_for_receive == WANOPT_YES) { + card->u.c.protocol_options |= ASY_XON_XOFF_HS_FOR_RX; + } + if (conf->xon_xoff_hs_for_transmit == WANOPT_YES) { + card->u.c.protocol_options |= ASY_XON_XOFF_HS_FOR_TX; + } + if (conf->dcd_hs_for_transmit == WANOPT_YES) { + card->u.c.protocol_options |= ASY_DCD_HS_FOR_TX; + } + if (conf->cts_hs_for_transmit == WANOPT_YES) { + card->u.c.protocol_options |= ASY_CTS_HS_FOR_TX; + } + + card->u.c.tx_bits_per_char = conf->tx_bits_per_char; + card->u.c.rx_bits_per_char = conf->rx_bits_per_char; + card->u.c.stop_bits = conf->stop_bits; + card->u.c.parity = conf->parity; + card->u.c.break_timer = conf->break_timer; + card->u.c.inter_char_timer = conf->inter_char_timer; + card->u.c.rx_complete_length = conf->rx_complete_length; + card->u.c.xon_char = conf->xon_char; + + }else{ + + /* Setup wanpipe as a router (WANPIPE) or as an API */ + if( strcmp(conf->usedby, "WANPIPE") == 0) { + + printk(KERN_INFO "%s:%s: Interface running in WANPIPE mode!\n", + wandev->name,chan->if_name); + + chan->common.usedby=WANPIPE; + + pppdev=kmalloc(sizeof(struct ppp_device),GFP_KERNEL); + if (!pppdev){ + err = -ENOMEM; + goto new_if_error; + } + + memset(pppdev,0,sizeof(struct ppp_device)); + + chan->common.prot_ptr=(void*)pppdev; + + /* Attach PPP protocol layer to pppdev + * The wp_sppp_attach() will initilize the dev structure + * and setup ppp layer protocols. + * All we have to do is to bind in: + * if_open(), if_close(), if_send() and get_stats() functions. + */ + + pppdev->dev=dev; + + /* Get authentication info. */ + if(conf->pap == WANOPT_YES){ + pppdev->sppp.myauth.proto = PPP_PAP; + }else if(conf->chap == WANOPT_YES){ + pppdev->sppp.myauth.proto = PPP_CHAP; + }else{ + pppdev->sppp.myauth.proto = 0; + } + + if(pppdev->sppp.myauth.proto){ + memcpy(pppdev->sppp.myauth.name, conf->userid, AUTHNAMELEN); + memcpy(pppdev->sppp.myauth.secret, conf->passwd, AUTHNAMELEN); + } + + pppdev->sppp.gateway = conf->gateway; + if (conf->if_down){ + pppdev->sppp.dynamic_ip = 1; + } + + sprintf(pppdev->sppp.hwdevname,"%s",card->devname); + + wp_sppp_attach(pppdev); + sp = &pppdev->sppp; + + /* Enable PPP Debugging */ + if (conf->protocol == WANCONFIG_CHDLC){ + printk(KERN_INFO "%s: Starting Kernel CISCO HDLC protocol\n", + card->devname); + sp->pp_flags |= PP_CISCO; + conf->ignore_dcd = WANOPT_YES; + conf->ignore_cts = WANOPT_YES; + }else{ + printk(KERN_INFO "%s: Starting Kernel Sync PPP protocol\n", + card->devname); + sp->pp_flags &= ~PP_CISCO; + dev->type = ARPHRD_PPP; + } + + #ifdef CONFIG_PRODUCT_WANPIPE_ANNEXG + }else if (strcmp(conf->usedby, "ANNEXG") == 0) { + printk(KERN_INFO "%s:%s: Interface running in ANNEXG mode!\n", + wandev->name,chan->if_name); + chan->common.usedby=ANNEXG; + + if (strlen(conf->label)){ + strncpy(chan->label,conf->label,WAN_IF_LABEL_SZ); + } + #endif + + }else if (strcmp(conf->usedby, "STACK") == 0) { + chan->common.usedby = STACK; + DEBUG_EVENT( "%s:%s: Running in Stack mode.\n", + card->devname,chan->if_name); + + }else if (strcmp(conf->usedby, "API") == 0) { + chan->common.usedby = API; + wan_reg_api(chan, dev, card->devname); + DEBUG_EVENT( "%s:%s: Running in API mode.\n", + card->devname,chan->if_name); + + }else{ + printk(KERN_INFO + "%s:%s: Error: Unsupported operation mode!\n", + wandev->name,chan->if_name); + err=-EINVAL; + goto new_if_error; + } + } + + /* Get Multicast Information */ + chan->mc = conf->mc; + + /* prepare network device data space for registration */ + + if (conf->ignore_dcd == WANOPT_YES || conf->ignore_cts == WANOPT_YES){ + printk(KERN_INFO "%s: Ignore modem changes DCD/CTS\n",card->devname); + chan->ignore_modem=1; + }else{ + printk(KERN_INFO "%s: Restart protocol on modem changes DCD/CTS\n", + card->devname); + } + + + dev->init = &if_init; + dev->priv = chan; + chan->dev=dev; + + /* + * Create interface file in proc fs. + */ + err = wanrouter_proc_add_interface(wandev, + &chan->dent, + card->u.c.if_name, + dev); + if (err){ + printk(KERN_INFO + "%s: can't create /proc/net/router/mprot/%s entry!\n", + card->devname, card->u.c.if_name); + err = -ENOMEM; + goto new_if_error; + } + + return 0; + + +new_if_error: + + --card->wandev.new_if_cnt; + if (chan->common.usedby == API){ + wan_unreg_api(chan, card->devname); + } + + if (chan){ + chan->common.prot_ptr=NULL; + kfree(chan); + } + + if (pppdev){ + wp_sppp_detach(dev); + kfree(pppdev); + } + + dev->priv=NULL; + + return err; +} + + + + +/*============================================================================ + * Delete logical channel. + */ +static int del_if (wan_device_t* wandev, netdevice_t* dev) +{ + private_area_t *chan = dev->priv; + sdla_t *card = chan->card; + unsigned long smp_flags; + +#ifdef CONFIG_PRODUCT_WANPIPE_ANNEXG + if (chan->common.usedby == ANNEXG && chan->annexg_dev){ + netdevice_t *tmp_dev; + int err; + + printk(KERN_INFO "%s: Unregistering Lapb Protocol\n",wandev->name); + + if (!IS_FUNC_CALL(lapb_protocol,lapb_unregister)){ + wan_spin_lock_irq(&wandev->lock, &smp_flags); + chan->annexg_dev = NULL; + wan_spin_unlock_irq(&wandev->lock, &smp_flags); + return 0; + } + + wan_spin_lock_irq(&wandev->lock, &smp_flags); + tmp_dev=chan->annexg_dev; + chan->annexg_dev=NULL; + wan_spin_unlock_irq(&wandev->lock, &smp_flags); + + if ((err=lapb_protocol.lapb_unregister(tmp_dev))){ + wan_spin_lock_irq(&wandev->lock, &smp_flags); + chan->annexg_dev=tmp_dev; + wan_spin_unlock_irq(&wandev->lock, &smp_flags); + return err; + } + } +#endif + + /* Delete interface name from proc fs. */ + wanrouter_proc_delete_interface(wandev, card->u.c.if_name); + + wan_spin_lock_irq(&wandev->lock,&smp_flags); + + if (chan->common.prot_ptr){ + /* Detach the PPP layer */ + printk(KERN_INFO "%s: Detaching SyncPPP Module from %s\n", + wandev->name,dev->name); + wp_sppp_detach(dev); + } + + /* Bug Fix: Kernel 2.2.X + * We must manually remove the ioctl call binding + * since in some cases (mrouted) daemons continue + * to call ioctl() after the device has gone down */ + dev->do_ioctl = NULL; + dev->hard_header = NULL; + dev->rebuild_header = NULL; + + if (chan->common.prot_ptr){ + kfree(chan->common.prot_ptr); + chan->common.prot_ptr= NULL; + } + + chdlc_set_intr_mode(card, 0); + + if (card->u.c.comm_enabled){ + chdlc_comm_disable(card); + } + + wan_spin_unlock_irq(&wandev->lock,&smp_flags); + + port_set_state(card, WAN_DISCONNECTED); + + wan_unreg_api(chan, card->devname); + + /* TE1 - Unconfiging, only on shutdown */ + if (IS_TE1_CARD(card)) { + if (card->wandev.fe_iface.unconfig){ + card->wandev.fe_iface.unconfig(&card->fe); + } + } + return 0; +} + + +/****** Network Device Interface ********************************************/ + +/*============================================================================ + * Initialize Linux network interface. + * + * This routine is called only once for each interface, during Linux network + * interface registration. Returning anything but zero will fail interface + * registration. + */ +static int if_init (netdevice_t* dev) + { + private_area_t* chan = dev->priv; + sdla_t* card = chan->card; + wan_device_t* wandev = &card->wandev; + + /* NOTE: Most of the dev initialization was + * done in wp_sppp_attach(), called by new_if() + * function. All we have to do here is + * to link four major routines below. + */ + + /* Initialize device driver entry points */ + dev->open = &if_open; + dev->stop = &if_close; + dev->hard_start_xmit = &if_send; + dev->get_stats = &if_stats; +#if defined(LINUX_2_4)||defined(LINUX_2_6) + dev->tx_timeout = &if_tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; +#endif + + if (!chan->common.prot_ptr){ + dev->flags |= IFF_POINTOPOINT; + dev->flags |= IFF_NOARP; + dev->type = ARPHRD_PPP; + dev->mtu = card->wandev.mtu; + dev->hard_header_len = 0; + dev->hard_header = NULL; + dev->rebuild_header = NULL; + } + + /* Overwrite the sppp ioctl, because we need to run + * our debugging commands via ioctl(). However + * call syncppp ioctl with in it :) */ + dev->do_ioctl = &if_do_ioctl; + + /* Initialize hardware parameters */ + dev->irq = wandev->irq; + dev->dma = wandev->dma; + dev->base_addr = wandev->ioport; + card->hw_iface.getcfg(card->hw, SDLA_MEMBASE, &dev->mem_start); //ALEX_TODAY wandev->maddr; + card->hw_iface.getcfg(card->hw, SDLA_MEMEND, &dev->mem_end); //ALEX_TODAY wandev->maddr + wandev->msize - 1; + + /* Set transmit buffer queue length + * If we over fill this queue the packets will + * be droped by the kernel. + * wp_sppp_attach() sets this to 10, but + * 100 will give us more room at low speeds. + */ + dev->tx_queue_len = 100; + + return 0; +} + + +/*============================================================================ + * Handle transmit timeout event from netif watchdog + */ +static void if_tx_timeout (netdevice_t *dev) +{ + private_area_t* chan = dev->priv; + sdla_t *card = chan->card; + + /* If our device stays busy for at least 5 seconds then we will + * kick start the device by making dev->tbusy = 0. We expect + * that our device never stays busy more than 5 seconds. So this + * is only used as a last resort. + */ + + ++card->wandev.stats.collisions; + + chan->tick_counter = jiffies; + card->hw_iface.set_bit(card->hw, card->intr_perm_off, APP_INT_ON_TX_FRAME); + + printk (KERN_INFO "%s: Transmit timed out on %s\n", card->devname,dev->name); + netif_wake_queue (dev); + dev->trans_start = jiffies; + + if (chan->common.usedby == STACK){ + wanpipe_lip_kick(chan,0); + } +} + + + +/*============================================================================ + * Open network interface. + * o enable communications and interrupts. + * o prevent module from unloading by incrementing use count + * + * Return 0 if O.k. or errno. + */ +static int if_open (netdevice_t* dev) +{ + private_area_t* chan = dev->priv; + sdla_t* card = chan->card; + struct timeval tv; + + /* Only one open per interface is allowed */ + + if (open_dev_check(dev)) + return -EBUSY; + + + /* Start PPP Layer */ + if (chan->common.prot_ptr){ + if (wp_sppp_open(dev)){ + return -EIO; + } + } + + do_gettimeofday(&tv); + chan->router_start_time = tv.tv_sec; + + WAN_NETIF_START_QUEUE(dev); + WAN_NETIF_CARRIER_OFF(dev); + + if (chan->common.state == WAN_CONNECTED){ + WAN_NETIF_CARRIER_ON(dev); + } + + wanpipe_open(card); + + card->u.c.timer_int_enabled |= TMR_INT_ENABLED_CONFIG; + card->hw_iface.set_bit(card->hw, card->intr_perm_off, APP_INT_ON_TIMER); + return 0; +} + +/*============================================================================ + * Close network interface. + * o if this is the last close, then disable communications and interrupts. + * o reset flags. + */ +static int if_close (netdevice_t* dev) +{ + private_area_t* chan = dev->priv; + sdla_t* card = chan->card; + + WAN_TASKLET_KILL((&chan->tasklet)); + + /* Stop the PPP Layer */ + if (chan->common.prot_ptr){ + wp_sppp_close(dev); + } + + stop_net_queue(dev); + +#if defined(LINUX_2_1) + dev->start=0; +#endif + + wanpipe_close(card); + + return 0; +} + +/*============================================================================ + * Send a packet on a network interface. + * o set tbusy flag (marks start of the transmission) to block a timer-based + * transmit from overlapping. + * o check link state. If link is not up, then drop the packet. + * o execute adapter send command. + * o free socket buffer + * + * Return: 0 complete (socket buffer must be freed) + * non-0 packet may be re-transmitted (tbusy must be set) + * + * Notes: + * 1. This routine is called either by the protocol stack or by the "net + * bottom half" (with interrupts enabled). + * 2. Setting tbusy flag will inhibit further transmit requests from the + * protocol stack and can be used for flow control with protocol layer. + */ +static int if_send (struct sk_buff* skb, netdevice_t* dev) +{ + private_area_t *chan = dev->priv; + sdla_t *card = chan->card; + int udp_type = 0; + unsigned long smp_flags; + int err=0; + + if (skb == NULL){ + /* If we get here, some higher layer thinks we've missed an + * tx-done interrupt. + */ + printk(KERN_INFO "%s: Received NULL skb buffer! interface %s got kicked!\n", + card->devname, dev->name); + + wake_net_dev(dev); + return 0; + } + +#if defined(LINUX_2_1) + if (dev->tbusy){ + + /* If our device stays busy for at least 5 seconds then we will + * kick start the device by making dev->tbusy = 0. We expect + * that our device never stays busy more than 5 seconds. So this + * is only used as a last resort. + */ + ++card->wandev.stats.collisions; + + if((jiffies - chan->tick_counter) < (5 * HZ)) { + return 1; + } + if_tx_timeout(dev); + } +#else + netif_stop_queue(dev); +#endif + + if (chan->common.usedby != ANNEXG && + chan->common.usedby != STACK && + ntohs(skb->protocol) != htons(PVC_PROT)){ + /* check the udp packet type */ + + udp_type = udp_pkt_type(skb, card); + if (udp_type == UDP_CPIPE_TYPE){ + if(store_udp_mgmt_pkt(UDP_PKT_FRM_STACK, card, skb, dev, + chan)){ + card->hw_iface.set_bit(card->hw, card->intr_perm_off, APP_INT_ON_TIMER); + } + start_net_queue(dev); + return 0; + } + } + + /* Lock the 508 Card: SMP is supported */ + if(card->type != SDLA_S514){ + s508_lock(card,&smp_flags); + } + + err=0; + + if (wan_test_and_set_bit(SEND_CRIT, (void*)&card->wandev.critical)){ + + printk(KERN_INFO "%s: Critical in if_send: %lx\n", + card->wandev.name,card->wandev.critical); + ++card->wandev.stats.tx_dropped; + start_net_queue(dev); + goto if_send_crit_exit; + } + + if (card->wandev.state != WAN_CONNECTED){ + ++card->wandev.stats.tx_carrier_errors; + stop_net_queue(dev); + dev->trans_start = jiffies; + err=1; + goto if_send_crit_exit_down; + } + + /* If it's an API packet pull off the API + * header. Also check that the packet size + * is larger than the API header + */ + if (chan->common.usedby == API){ + /* discard the frame if we are configured for */ + /* 'receive only' mode or if there is no data */ + if (card->u.c.receive_only || + (wan_skb_len(skb) <= sizeof(api_tx_hdr_t))) { + + ++card->wandev.stats.tx_dropped; + goto if_send_crit_exit; + } + + wan_skb_pull(skb,sizeof(api_tx_hdr_t)); + } + + if ((err=chdlc_send(card, skb->data, skb->len))){ + err=1; + stop_net_queue(dev); + }else{ + ++card->wandev.stats.tx_packets; + card->wandev.stats.tx_bytes += skb->len; + dev->trans_start = jiffies; + start_net_queue(dev); + + wan_capture_trace_packet(card, &chan->trace_info, skb, TRC_OUTGOING_FRM); + + } + +if_send_crit_exit: + if (err==0){ + wan_skb_free(skb); + }else{ + chan->tick_counter = jiffies; + card->hw_iface.set_bit(card->hw, card->intr_perm_off, APP_INT_ON_TX_FRAME); + } + +if_send_crit_exit_down: + wan_clear_bit(SEND_CRIT, (void*)&card->wandev.critical); + if(card->type != SDLA_S514){ + s508_unlock(card,&smp_flags); + } + + return err; +} + +/*============================================================================ + * Get ethernet-style interface statistics. + * Return a pointer to struct enet_statistics. + */ +static struct net_device_stats gstats; +static struct net_device_stats* if_stats (netdevice_t* dev) +{ + sdla_t *my_card; + private_area_t* chan; + + /* Shutdown bug fix. In del_if() we kill + * dev->priv pointer. This function, gets + * called after del_if(), thus check + * if pointer has been deleted */ + if ((chan=dev->priv) == NULL) + return &gstats; + + my_card = chan->card; + if (!my_card){ + return &gstats; + } + + return &my_card->wandev.stats; +} + +/****** Cisco HDLC Firmware Interface Functions *******************************/ + +/*============================================================================ + * Read firmware code version. + * Put code version as ASCII string in str. + */ +static int chdlc_read_version (sdla_t* card, char* str) +{ + wan_mbox_t* mb = &card->wan_mbox; + int len; + char err; + mb->wan_data_len = 0; + mb->wan_command = READ_CHDLC_CODE_VERSION; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + + if(err != COMMAND_OK) { + chdlc_error(card,err,mb); + } + else if (str) { /* is not null */ + len = mb->wan_data_len; + memcpy(str, mb->wan_data, len); + str[len] = '\0'; + } + return (err); +} + +/*----------------------------------------------------------------------------- + * Configure CHDLC firmware. + */ +static int chdlc_configure (sdla_t* card, void* data) +{ + int err; + wan_mbox_t *mb = &card->wan_mbox; + int data_length = sizeof(CHDLC_CONFIGURATION_STRUCT); + + mb->wan_data_len = data_length; + memcpy(mb->wan_data, data, data_length); + mb->wan_command = SET_CHDLC_CONFIGURATION; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + + if (err != COMMAND_OK) chdlc_error (card, err, mb); + + return err; +} + + +/*============================================================================ + * Set interrupt mode -- HDLC Version. + */ + +static int chdlc_set_intr_mode (sdla_t* card, unsigned mode) +{ + wan_mbox_t* mb = &card->wan_mbox; + CHDLC_INT_TRIGGERS_STRUCT* int_data = + (CHDLC_INT_TRIGGERS_STRUCT *)mb->wan_data; + int err; + + int_data->CHDLC_interrupt_triggers = mode; + int_data->IRQ = card->wandev.irq; //ALEX_TODAY card->hw.irq; + int_data->interrupt_timer = 1; + + mb->wan_data_len = sizeof(CHDLC_INT_TRIGGERS_STRUCT); + mb->wan_command = SET_CHDLC_INTERRUPT_TRIGGERS; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != COMMAND_OK) + chdlc_error (card, err, mb); + return err; +} + + +/*============================================================================ + * Enable communications. + */ + +static int chdlc_comm_enable (sdla_t* card) +{ + int err; + wan_mbox_t* mb = &card->wan_mbox; + + mb->wan_data_len = 0; + mb->wan_command = ENABLE_CHDLC_COMMUNICATIONS; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != COMMAND_OK) + chdlc_error(card, err, mb); + else + card->u.c.comm_enabled=1; + + return err; +} + +/*============================================================================ + * Disable communications and Drop the Modem lines (DCD and RTS). + */ +static int chdlc_comm_disable (sdla_t* card) +{ + int err; + wan_mbox_t* mb = &card->wan_mbox; + + mb->wan_data_len = 0; + mb->wan_command = DISABLE_CHDLC_COMMUNICATIONS; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != COMMAND_OK) + chdlc_error(card,err,mb); + + return err; +} + +/*============================================================================ + * Read communication error statistics. + */ +static int chdlc_read_comm_err_stats (sdla_t* card) +{ + int err; + wan_mbox_t* mb = &card->wan_mbox; + + mb->wan_data_len = 0; + mb->wan_command = READ_COMMS_ERROR_STATS; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != COMMAND_OK) + chdlc_error(card,err,mb); + return err; +} + + +/*============================================================================ + * Read CHDLC operational statistics. + */ +static int chdlc_read_op_stats (sdla_t* card) +{ + int err; + wan_mbox_t* mb = &card->wan_mbox; + + mb->wan_data_len = 0; + mb->wan_command = READ_CHDLC_OPERATIONAL_STATS; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != COMMAND_OK) + chdlc_error(card,err,mb); + return err; +} + + +/*============================================================================ + * Update communications error and general packet statistics. + */ +static int update_comms_stats(sdla_t* card, + private_area_t* chan) +{ + wan_mbox_t* mb = &card->wan_mbox; + COMMS_ERROR_STATS_STRUCT* err_stats; + CHDLC_OPERATIONAL_STATS_STRUCT *op_stats; + + /* 1. On the first timer interrupt, update T1/E1 alarms + * and PMON counters (only for T1/E1 card) (TE1) + */ + /* TE1 Update T1/E1 alarms */ + if (IS_TE1_CARD(card)) { + card->wandev.fe_iface.read_alarm(&card->fe, 0); + /* TE1 Update T1/E1 perfomance counters */ + card->wandev.fe_iface.read_pmon(&card->fe, 0); + }else if (IS_56K_CARD(card)) { + /* 56K Update CSU/DSU alarms */ + card->wandev.fe_iface.read_alarm(&card->fe, 1); + } + + if(chdlc_read_comm_err_stats(card)) + return 1; + err_stats = (COMMS_ERROR_STATS_STRUCT *)mb->wan_data; + card->wandev.stats.rx_over_errors = + err_stats->Rx_overrun_err_count; + card->wandev.stats.rx_crc_errors = + err_stats->CRC_err_count; + card->wandev.stats.rx_frame_errors = + err_stats->Rx_abort_count; + card->wandev.stats.rx_fifo_errors = + err_stats->Rx_dis_pri_bfrs_full_count; + card->wandev.stats.rx_missed_errors = + card->wandev.stats.rx_fifo_errors; + card->wandev.stats.tx_aborted_errors = + err_stats->sec_Tx_abort_count; + + /* on the second timer interrupt, read the operational statistics */ + if(chdlc_read_op_stats(card)) + return 1; + + op_stats = (CHDLC_OPERATIONAL_STATS_STRUCT *)mb->wan_data; + card->wandev.stats.rx_length_errors = + (op_stats->Rx_Data_discard_short_count + + op_stats->Rx_Data_discard_long_count); + + return 0; +} + +/*============================================================================ + * Send packet. + * Return: 0 - o.k. + * 1 - no transmit buffers available + */ +static int chdlc_send (sdla_t* card, void* data, unsigned len) +{ + CHDLC_DATA_TX_STATUS_EL_STRUCT txbuf; + + card->hw_iface.peek(card->hw, card->u.c.txbuf_off, &txbuf, sizeof(txbuf)); + + if (txbuf.opp_flag) + return 1; + + card->hw_iface.poke(card->hw, txbuf.ptr_data_bfr, data, len); + + txbuf.frame_length = len; + card->hw_iface.poke(card->hw, card->u.c.txbuf_off, &txbuf, sizeof(txbuf)); + + txbuf.opp_flag = 1; /* start transmission */ + card->hw_iface.poke_byte(card->hw, + card->u.c.txbuf_off+offsetof(CHDLC_DATA_TX_STATUS_EL_STRUCT, opp_flag), + txbuf.opp_flag); + + /* Update transmit buffer control fields */ + card->u.c.txbuf_off += sizeof(txbuf); + + if (card->u.c.txbuf_off > card->u.c.txbuf_last_off) + card->u.c.txbuf_off = card->u.c.txbuf_base_off; + return 0; +} +/*============================================================================ + * TE1 + * Read value from PMC register. + */ +static unsigned char read_front_end_reg (void* card1, ...) +{ + va_list args; + sdla_t *card = (sdla_t*)card1; + wan_mbox_t* mb = &card->wan_mbox; + char* data = mb->wan_data; + u16 reg; + int err; + + va_start(args, card1); + reg = (u16)va_arg(args, int); + va_end(args); + + ((FRONT_END_REG_STRUCT *)data)->register_number = (unsigned short)reg; + mb->wan_data_len = sizeof(FRONT_END_REG_STRUCT); + mb->wan_command = READ_FRONT_END_REGISTER; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != COMMAND_OK) + chdlc_error(card,err,mb); + return(((FRONT_END_REG_STRUCT *)data)->register_value); +} + +/*============================================================================ + * TE1 + * Write value to PMC register. + */ +static int write_front_end_reg (void* card1, ... ) +{ + va_list args; + sdla_t* card = (sdla_t*)card1; + wan_mbox_t* mb = &card->wan_mbox; + u16 reg; + u8 value; + char* data = mb->wan_data; + int err; + int retry=15; + + va_start(args, card1); + reg = (u16)va_arg(args, int); + value = (u8)va_arg(args, int); + va_end(args); + + do { + + ((FRONT_END_REG_STRUCT *)data)->register_number = (unsigned short)reg; + ((FRONT_END_REG_STRUCT *)data)->register_value = value; + mb->wan_data_len = sizeof(FRONT_END_REG_STRUCT); + mb->wan_command = WRITE_FRONT_END_REGISTER; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != COMMAND_OK){ + chdlc_error(card,err,mb); + } + }while(err && --retry); + + return err; +} + +/****** Firmware Error Handler **********************************************/ + +/*============================================================================ + * Firmware error handler. + * This routine is called whenever firmware command returns non-zero + * return code. + * + * Return zero if previous command has to be cancelled. + */ +static int chdlc_error (sdla_t *card, int err, wan_mbox_t *mb) +{ + unsigned cmd = mb->wan_command; + + switch (err) { + + case CMD_TIMEOUT: + printk(KERN_INFO "%s: command 0x%02X timed out!\n", + card->devname, cmd); + break; + + case S514_BOTH_PORTS_SAME_CLK_MODE: + if(cmd == SET_CHDLC_CONFIGURATION) { + printk(KERN_INFO + "%s: Configure both ports for the same clock source\n", + card->devname); + break; + } + + default: + printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n", + card->devname, cmd, err); + } + + return 0; +} + +/****** Interrupt Handlers **************************************************/ + +/*============================================================================ + * Cisco HDLC interrupt service routine. + */ +STATIC void wsppp_isr (sdla_t* card) +{ + netdevice_t* dev; + SHARED_MEMORY_INFO_STRUCT flags; + private_area_t *chan; + int i; + + /* Check for which port the interrupt has been generated + * Since Secondary Port is piggybacking on the Primary + * the check must be done here. + */ + + if (!card->hw){ + return; + } + + /* Start card isr critical area */ + wan_set_bit(0,&card->in_isr); + card->spurious = 0; + + card->hw_iface.peek(card->hw, card->flags_off, &flags, sizeof(flags)); + + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + /* If we get an interrupt with no network device, stop the interrupts + * and issue an error */ + if ((!dev || !dev->priv) && flags.interrupt_info_struct.interrupt_type != + COMMAND_COMPLETE_APP_INT_PEND){ + goto isr_done; + } + + /* if critical due to peripheral operations + * ie. update() or getstats() then reset the interrupt and + * wait for the board to retrigger. + */ + if(wan_test_bit(PERI_CRIT, (void*)&card->wandev.critical)) { + card->hw_iface.poke_byte(card->hw, card->intr_type_off, 0x00); + goto isr_done; + } + + + /* On a 508 Card, if critical due to if_send + * Major Error !!! + */ + if(card->type != SDLA_S514) { + if(wan_test_bit(0, (void*)&card->wandev.critical)) { + printk(KERN_INFO "%s: Critical while in ISR: %lx\n", + card->devname, card->wandev.critical); + goto isr_done; + } + } + + switch(flags.interrupt_info_struct.interrupt_type) { + + case RX_APP_INT_PEND: /* 0x01: receive interrupt */ + rx_intr(card); + break; + + case TX_APP_INT_PEND: /* 0x02: transmit interrupt */ + + chan=dev->priv; + + card->hw_iface.clear_bit(card->hw, card->intr_perm_off, APP_INT_ON_TX_FRAME); + if (chan->common.usedby == STACK){ + start_net_queue(dev); + wanpipe_lip_kick(chan,0); + break; + } + +#ifdef CONFIG_PRODUCT_WANPIPE_ANNEXG + if (chan->common.usedby == ANNEXG && + chan->annexg_dev){ + + start_net_queue(dev); + if (IS_FUNC_CALL(lapb_protocol,lapb_mark_bh)){ + lapb_protocol.lapb_mark_bh(chan->annexg_dev); + } + break; + } +#endif + + wake_net_dev(dev); + break; + + case COMMAND_COMPLETE_APP_INT_PEND:/* 0x04: cmd cplt */ + ++card->timer_int_enabled; + break; + + case CHDLC_EXCEP_COND_APP_INT_PEND: /* 0x20 */ + process_chdlc_exception(card); + break; + + case GLOBAL_EXCEP_COND_APP_INT_PEND: + + process_global_exception(card); + + /* Reset the 56k or T1/E1 front end exception condition */ + if(IS_56K_CARD(card) || IS_TE1_CARD(card)) { + FRONT_END_STATUS_STRUCT FE_status; + card->hw_iface.peek(card->hw, + card->fe_status_off, + &FE_status, + sizeof(FE_status)); + FE_status.opp_flag = 0x01; + card->hw_iface.poke(card->hw, + card->fe_status_off, + &FE_status, + sizeof(FE_status)); + } + + break; + + case TIMER_APP_INT_PEND: + timer_intr(card); + break; + + default: + + if (card->next){ + wan_set_bit(0,&card->spurious); + break; + } + + printk(KERN_INFO "%s: spurious interrupt 0x%02X!\n", + card->devname, + flags.interrupt_info_struct.interrupt_type); + printk(KERN_INFO "Code name: "); + for(i = 0; i < 4; i ++) + printk("%c", + flags.global_info_struct.codename[i]); + printk("\n"); + printk(KERN_INFO "Code version: "); + for(i = 0; i < 4; i ++) + printk("%c", + flags.global_info_struct.codeversion[i]); + printk("\n"); + break; + } + +isr_done: + card->in_isr = 0; + card->hw_iface.poke_byte(card->hw, card->intr_type_off, 0x00); +} + +/*============================================================================ + * Receive interrupt handler. + */ +static void rx_intr (sdla_t* card) +{ + netdevice_t *dev; + private_area_t *chan; + SHARED_MEMORY_INFO_STRUCT flags; + CHDLC_DATA_RX_STATUS_EL_STRUCT rxbuf; + struct sk_buff *skb; + unsigned len; + unsigned addr; + void *buf; + int i,udp_type; + unsigned int tmp_prev_error; + + + card->hw_iface.peek(card->hw, card->flags_off, &flags, sizeof(flags)); + card->hw_iface.peek(card->hw, card->u.c.rxmb_off, &rxbuf, sizeof(rxbuf)); + addr = rxbuf.ptr_data_bfr; + if (rxbuf.opp_flag != 0x01) { + printk(KERN_INFO + "%s: corrupted Rx buffer @ 0x%X, flag = 0x%02X!\n", + card->devname, (unsigned)card->u.c.rxmb_off, rxbuf.opp_flag); + printk(KERN_INFO "Code name: "); + for(i = 0; i < 4; i ++) + printk(KERN_INFO "%c", + flags.global_info_struct.codename[i]); + printk(KERN_INFO "\n"); + printk(KERN_INFO "Code version: "); + for(i = 0; i < 4; i ++) + printk(KERN_INFO "%c", + flags.global_info_struct.codeversion[i]); + printk(KERN_INFO "\n"); + + /* Bug Fix: Mar 6 2000 + * If we get a corrupted mailbox, it measn that driver + * is out of sync with the firmware. There is no recovery. + * If we don't turn off all interrupts for this card + * the machine will crash. + */ + printk(KERN_INFO "%s: Critical router failure ...!!!\n", + card->devname); + printk(KERN_INFO "Please contact Sangoma Technologies !\n"); + chdlc_set_intr_mode(card,0); + return; + } + + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + if (!dev){ + goto rx_exit; + } + +#if defined(LINUX_2_4)||defined(LINUX_2_6) + if (!netif_running(dev)){ + goto rx_exit; + } +#else + if (!dev->start){ + goto rx_exit; + } +#endif + + chan = dev->priv; + + tmp_prev_error=chan->prev_error; + chan->prev_error=rxbuf.error_flag; + + if (rxbuf.error_flag){ + goto rx_exit; + } + + if (tmp_prev_error){ + goto rx_exit; + } + + if (chan->common.usedby == ANNEXG || chan->common.usedby == STACK){ + if (rxbuf.frame_length <= 2 || rxbuf.frame_length > 4103){ + DEBUG_EVENT("%s: Bad Rx Frame Length %i\n", + card->devname,rxbuf.frame_length); + goto rx_exit; + } + }else{ + if (rxbuf.frame_length < 7 || rxbuf.frame_length > 4103){ + goto rx_exit; + } + } + + /* Make sure that data len is greater than CRC_LEN + * before we remove the CRC bytes */ + if (rxbuf.frame_length <= CRC_LENGTH){ + ++card->wandev.stats.rx_dropped; + goto rx_exit; + } + + /* Take off two CRC bytes */ + if (chan->common.usedby == API){ + len = rxbuf.frame_length; + }else{ + len = rxbuf.frame_length - CRC_LENGTH; + } + + /* Allocate socket buffer */ + skb = dev_alloc_skb(len+2); + if (skb == NULL) { + if (net_ratelimit()){ + printk(KERN_INFO "%s: Error: No memory available!\n", + card->devname); + } + ++card->wandev.stats.rx_dropped; + goto rx_exit; + } + + /* Copy data to the socket buffer */ + if ((addr + len) > card->u.c.rx_top_off + 1) { + unsigned tmp = card->u.c.rx_top_off - addr + 1; + buf = skb_put(skb, tmp); + card->hw_iface.peek(card->hw, addr, buf, tmp); + addr = card->u.c.rx_base_off; + len -= tmp; + } + + buf = skb_put(skb, len); + card->hw_iface.peek(card->hw, addr, buf, len); + + wan_capture_trace_packet(card, &chan->trace_info, skb, TRC_INCOMING_FRM); + + udp_type = udp_pkt_type(skb, card); + + if(udp_type == UDP_CPIPE_TYPE) { + + card->wandev.stats.rx_packets ++; + card->wandev.stats.rx_bytes += skb->len; + + skb->protocol = htons(ETH_P_IP); + + if(store_udp_mgmt_pkt(UDP_PKT_FRM_NETWORK, + card, skb, dev, chan)) { + card->hw_iface.set_bit(card->hw, card->intr_perm_off, APP_INT_ON_TIMER); + } + + }else if (chan->common.usedby == ANNEXG){ + + if (chan->annexg_dev){ + skb->protocol = htons(ETH_P_X25); + skb->dev = chan->annexg_dev; + skb->mac.raw = skb->data; + + if (wan_skb_queue_len(&chan->rx_queue) > MAX_RX_QUEUE){ + wan_skb_free(skb); + if (net_ratelimit()){ + DEBUG_EVENT("%s: Error Rx queue full, dropping pkt!\n", + card->devname); + } + ++card->wandev.stats.rx_dropped; + goto rx_exit; + } + + wan_skb_queue_tail(&chan->rx_queue,skb); + + WAN_TASKLET_SCHEDULE((&chan->tasklet)); + + }else{ + wan_skb_free(skb); + ++card->wandev.stats.rx_errors; + } + }else if (chan->common.usedby == STACK){ + skb->dev = chan->annexg_dev; + skb->mac.raw = skb->data; + + if (wan_skb_queue_len(&chan->rx_queue) > MAX_RX_QUEUE){ + wan_skb_free(skb); + if (net_ratelimit()){ + DEBUG_EVENT("%s: Error:(STACK) Rx queue full, dropping pkt!\n", + card->devname); + } + ++card->wandev.stats.rx_dropped; + goto rx_exit; + } + + wan_skb_queue_tail(&chan->rx_queue,skb); + + WAN_TASKLET_SCHEDULE((&chan->tasklet)); + }else{ + + if (wan_skb_queue_len(&chan->rx_queue) > MAX_RX_QUEUE){ + wan_skb_free(skb); + if (net_ratelimit()){ + DEBUG_EVENT("%s: Error Rx queue full, dropping pkt!\n", + card->devname); + } + ++card->wandev.stats.rx_dropped; + goto rx_exit; + } + + /* Pass it up the protocol stack */ + skb->protocol = htons(ETH_P_WAN_PPP); + skb->dev = dev; + skb->mac.raw = skb->data; + + wan_skb_queue_tail(&chan->rx_queue,skb); + WAN_TASKLET_SCHEDULE((&chan->tasklet)); + } + +rx_exit: + /* Release buffer element and calculate a pointer to the next one */ + rxbuf.opp_flag = 0x00; + card->hw_iface.poke(card->hw, card->u.c.rxmb_off, &rxbuf, sizeof(rxbuf)); + card->u.c.rxmb_off += sizeof(rxbuf); + if (card->u.c.rxmb_off > card->u.c.rxbuf_last_off){ + card->u.c.rxmb_off = card->u.c.rxbuf_base_off; + } +} + +/*============================================================================ + * Timer interrupt handler. + * The timer interrupt is used for two purposes: + * 1) Processing udp calls from 'cpipemon'. + * 2) Reading board-level statistics for updating the proc file system. + */ +void timer_intr(sdla_t *card) +{ + netdevice_t *dev; + private_area_t *chan = NULL; + + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + if (!dev){ + return; + } + + if (!(chan = dev->priv)){ + return; + } + + /* TE timer interrupt */ + if (card->u.c.timer_int_enabled & TMR_INT_ENABLED_TE) { + card->wandev.fe_iface.polling(&card->fe); + card->u.c.timer_int_enabled &= ~TMR_INT_ENABLED_TE; + } + + if (card->u.c.timer_int_enabled & TMR_INT_ENABLED_CONFIG) { + config_chdlc(card); + card->u.c.timer_int_enabled &= ~TMR_INT_ENABLED_CONFIG; + } + + /* process a udp call if pending */ + if(card->u.c.timer_int_enabled & TMR_INT_ENABLED_UDP) { + process_udp_mgmt_pkt(card, dev, + chan,0); + card->u.c.timer_int_enabled &= ~TMR_INT_ENABLED_UDP; + } + + /* only disable the timer interrupt if there are no udp or statistic */ + /* updates pending */ + if(!card->u.c.timer_int_enabled) { + card->hw_iface.clear_bit(card->hw, card->intr_perm_off, APP_INT_ON_TIMER); + } +} + + +/*----------------------------------------------------------------------------- + set_asy_config() used to set asynchronous configuration options on the board +------------------------------------------------------------------------------*/ + +static int set_asy_config(sdla_t* card) +{ + + ASY_CONFIGURATION_STRUCT cfg; + wan_mbox_t *mb = &card->wan_mbox; + int err; + + memset(&cfg, 0, sizeof(ASY_CONFIGURATION_STRUCT)); + + if(card->wandev.clocking) + cfg.baud_rate = card->wandev.bps; + + cfg.line_config_options = (card->wandev.interface == WANOPT_RS232) ? + INTERFACE_LEVEL_RS232 : INTERFACE_LEVEL_V35; + + cfg.modem_config_options = 0; + cfg.asy_API_options = card->u.c.api_options; + cfg.asy_protocol_options = card->u.c.protocol_options; + cfg.Tx_bits_per_char = card->u.c.tx_bits_per_char; + cfg.Rx_bits_per_char = card->u.c.rx_bits_per_char; + cfg.stop_bits = card->u.c.stop_bits; + cfg.parity = card->u.c.parity; + cfg.break_timer = card->u.c.break_timer; + cfg.asy_Rx_inter_char_timer = card->u.c.inter_char_timer; + cfg.asy_Rx_complete_length = card->u.c.rx_complete_length; + cfg.XON_char = card->u.c.xon_char; + cfg.XOFF_char = card->u.c.xoff_char; + cfg.asy_statistics_options = (CHDLC_TX_DATA_BYTE_COUNT_STAT | + CHDLC_RX_DATA_BYTE_COUNT_STAT); + + mb->wan_data_len = sizeof(ASY_CONFIGURATION_STRUCT); + memcpy(mb->wan_data, &cfg, mb->wan_data_len); + mb->wan_command = SET_ASY_CONFIGURATION; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != COMMAND_OK) + chdlc_error (card, err, mb); + + if (err == 0x4F){ + DEBUG_EVENT("%s: Error: ASYNC Not Supported by Firmware!\n", + card->devname); + } + return err; +} + +/*============================================================================ + * Enable asynchronous communications. + */ + +static int asy_comm_enable (sdla_t* card) +{ + netdevice_t *dev; + int err; + wan_mbox_t *mb = &card->wan_mbox; + + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + if (dev == NULL){ + return -EINVAL; + } + mb->wan_data_len = 0; + mb->wan_command = ENABLE_ASY_COMMUNICATIONS; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != COMMAND_OK && dev) + chdlc_error(card, err, mb); + + if (!err) + card->u.c.comm_enabled = 1; + + return err; +} + + + + +/*------------------------------------------------------------------------------ + Miscellaneous Functions + - set_chdlc_config() used to set configuration options on the board +------------------------------------------------------------------------------*/ + +static int set_chdlc_config(sdla_t* card) +{ + + CHDLC_CONFIGURATION_STRUCT cfg; + + memset(&cfg, 0, sizeof(CHDLC_CONFIGURATION_STRUCT)); + + if(card->wandev.clocking) + cfg.baud_rate = card->wandev.bps; + + cfg.line_config_options = (card->wandev.interface == WANOPT_RS232) ? + INTERFACE_LEVEL_RS232 : INTERFACE_LEVEL_V35; + + cfg.modem_config_options = 0; + //API OPTIONS + cfg.CHDLC_API_options = 0; + cfg.modem_status_timer = 100; + cfg.CHDLC_protocol_options = card->u.c.protocol_options | HDLC_STREAMING_MODE; + cfg.percent_data_buffer_for_Tx = 50; + cfg.CHDLC_statistics_options = (CHDLC_TX_DATA_BYTE_COUNT_STAT | + CHDLC_RX_DATA_BYTE_COUNT_STAT); + cfg.max_CHDLC_data_field_length = card->wandev.mtu+CRC_LENGTH; + + cfg.transmit_keepalive_timer = 0; + cfg.receive_keepalive_timer = 0; + cfg.keepalive_error_tolerance = 0; + cfg.SLARP_request_timer = 0; + + cfg.IP_address = 0; + cfg.IP_netmask = 0; + + return chdlc_configure(card, &cfg); +} + +/*============================================================================ + * Process global exception condition + */ +static int process_global_exception(sdla_t *card) +{ + wan_mbox_t* mb = &card->wan_mbox; + int err; + + mb->wan_data_len = 0; + mb->wan_command = READ_GLOBAL_EXCEPTION_CONDITION; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + + if(err != CMD_TIMEOUT ){ + + switch(mb->wan_return_code) { + + case EXCEP_MODEM_STATUS_CHANGE: + + if (IS_56K_CARD(card)) { + FRONT_END_STATUS_STRUCT FE_status; + card->hw_iface.peek(card->hw, + card->fe_status_off, + &FE_status, + sizeof(FE_status)); + + card->fe.fe_param.k56_param.RR8_reg_56k = + FE_status.FE_U.stat_56k.RR8_56k; + card->fe.fe_param.k56_param.RRA_reg_56k = + FE_status.FE_U.stat_56k.RRA_56k; + card->fe.fe_param.k56_param.RRC_reg_56k = + FE_status.FE_U.stat_56k.RRC_56k; + card->wandev.fe_iface.read_alarm(&card->fe, 0); + + handle_front_end_state(card); + break; + } + + if (IS_TE1_CARD(card)) { + /* TE_INTR */ + card->wandev.fe_iface.isr(&card->fe); + handle_front_end_state(card); + break; + } + + if ((mb->wan_data[0] & (DCD_HIGH | CTS_HIGH)) == (DCD_HIGH | CTS_HIGH)){ + card->fe.fe_status = FE_CONNECTED; + }else{ + card->fe.fe_status = FE_DISCONNECTED; + } + + printk(KERN_INFO "%s: Modem status change\n", + card->devname); + + switch(mb->wan_data[0] & (DCD_HIGH | CTS_HIGH)) { + case (DCD_HIGH): + printk(KERN_INFO "%s: DCD high, CTS low\n",card->devname); + break; + case (CTS_HIGH): + printk(KERN_INFO "%s: DCD low, CTS high\n",card->devname); + break; + case ((DCD_HIGH | CTS_HIGH)): + printk(KERN_INFO "%s: DCD high, CTS high\n",card->devname); + break; + default: + printk(KERN_INFO "%s: DCD low, CTS low\n",card->devname); + break; + } + + handle_front_end_state(card); + break; + + case EXCEP_TRC_DISABLED: + printk(KERN_INFO "%s: Line trace disabled\n", + card->devname); + break; + + case EXCEP_IRQ_TIMEOUT: + printk(KERN_INFO "%s: IRQ timeout occurred\n", + card->devname); + break; + + default: + printk(KERN_INFO "%s: Global exception %x\n", + card->devname, mb->wan_return_code); + break; + } + } + return 0; +} + +static void handle_front_end_state(void* card_id) +{ + sdla_t* card = (sdla_t*)card_id; + + if (card->wandev.ignore_front_end_status == WANOPT_YES){ + return; + } + + if (card->fe.fe_status == FE_CONNECTED){ + if (card->u.c.state == WAN_CONNECTED){ + port_set_state(card,WAN_CONNECTED); + } + }else{ + netdevice_t *dev; + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + send_ppp_term_request(dev); + port_set_state(card,WAN_DISCONNECTED); + } +} + + + + +/*============================================================================ + * Process chdlc exception condition + */ +static int process_chdlc_exception(sdla_t *card) +{ + wan_mbox_t* mb = &card->wan_mbox; + int err; + + mb->wan_data_len = 0; + mb->wan_command = READ_CHDLC_EXCEPTION_CONDITION; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if(err != CMD_TIMEOUT) { + + switch (err) { + + case EXCEP_LINK_ACTIVE: + card->u.c.state = WAN_CONNECTED; + DEBUG_EVENT("%s: Exception condition: Link active!\n", + card->devname); + if (card->wandev.ignore_front_end_status == WANOPT_YES || + card->fe.fe_status == FE_CONNECTED){ + port_set_state(card, WAN_CONNECTED); + } + break; + + case EXCEP_LINK_INACTIVE_MODEM: + DEBUG_EVENT("%s: Exception condition: Link active!\n", + card->devname); + card->u.c.state = WAN_DISCONNECTED; + port_set_state(card, WAN_DISCONNECTED); + break; + + case EXCEP_LOOPBACK_CONDITION: + printk(KERN_INFO "%s: Loopback Condition Detected.\n", + card->devname); + break; + + case NO_CHDLC_EXCEP_COND_TO_REPORT: + printk(KERN_INFO "%s: No exceptions reported.\n", + card->devname); + break; + default: + printk(KERN_INFO "%s: Exception Condition %x!\n", + card->devname,err); + break; + } + + } + return 0; +} + + +/*============================================================================= + * Store a UDP management packet for later processing. + */ + +static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, + struct sk_buff *skb, netdevice_t* dev, + private_area_t* chan ) +{ + int udp_pkt_stored = 0; + + if(!atomic_read(&chan->udp_pkt_len) && + (skb->len <= MAX_LGTH_UDP_MGNT_PKT)) { + atomic_set(&chan->udp_pkt_len, skb->len); + chan->udp_pkt_src = udp_pkt_src; + memcpy(chan->udp_pkt_data, skb->data+4, skb->len-4); + card->u.c.timer_int_enabled = TMR_INT_ENABLED_UDP; + udp_pkt_stored = 1; + } + + wan_skb_free(skb); + + return(udp_pkt_stored); +} + + +/** + * if_do_ioctl - Ioctl handler for fr + * @dev: Device subject to ioctl + * @ifr: Interface request block from the user + * @cmd: Command that is being issued + * + * This function handles the ioctls that may be issued by the user + * to control the settings of a FR. It does both busy + * and security checks. This function is intended to be wrapped by + * callers who wish to add additional ioctl calls of their own. + */ +/* SNMP */ +static int if_do_ioctl(netdevice_t *dev, struct ifreq *ifr, int cmd) +{ + private_area_t* chan= (private_area_t*)dev->priv; + unsigned long smp_flags; + sdla_t *card; + int err=-EINVAL; + wan_udp_pkt_t *wan_udp_pkt; + + if (!chan){ + return -ENODEV; + } + card=chan->card; + + switch(cmd) + { + + case SIOC_WANPIPE_BIND_SK: + if (!ifr){ + err= -EINVAL; + break; + } + + spin_lock_irqsave(&card->wandev.lock,smp_flags); + err=wan_bind_api_to_svc(chan,ifr->ifr_data); + spin_unlock_irqrestore(&card->wandev.lock,smp_flags); + break; + + case SIOC_WANPIPE_UNBIND_SK: + if (!ifr){ + err= -EINVAL; + break; + } + + spin_lock_irqsave(&card->wandev.lock,smp_flags); + err=wan_unbind_api_from_svc(chan,ifr->ifr_data); + spin_unlock_irqrestore(&card->wandev.lock,smp_flags); + break; + + case SIOC_WANPIPE_CHECK_TX: + case SIOC_ANNEXG_CHECK_TX: + err=0; + break; + + case SIOC_WANPIPE_DEV_STATE: + err = chan->common.state; + break; + + case SIOC_ANNEXG_KICK: + err=0; + break; + + case SIOC_WANPIPE_PIPEMON: + + NET_ADMIN_CHECK(); + + if (atomic_read(&chan->udp_pkt_len) != 0){ + return -EBUSY; + } + + atomic_set(&chan->udp_pkt_len,MAX_LGTH_UDP_MGNT_PKT); + + /* For performance reasons test the critical + * here before spin lock */ + if (wan_test_bit(0,&card->in_isr)){ + atomic_set(&chan->udp_pkt_len,0); + return -EBUSY; + } + + + wan_udp_pkt=(wan_udp_pkt_t*)chan->udp_pkt_data; + if (copy_from_user(&wan_udp_pkt->wan_udp_hdr,ifr->ifr_data,sizeof(wan_udp_hdr_t))){ + atomic_set(&chan->udp_pkt_len,0); + return -EFAULT; + } + + spin_lock_irqsave(&card->wandev.lock, smp_flags); + + /* We have to check here again because we don't know + * what happened during spin_lock */ + if (wan_test_bit(0,&card->in_isr)) { + printk(KERN_INFO "%s:%s Pipemon command failed, Driver busy: try again.\n", + card->devname,dev->name); + atomic_set(&chan->udp_pkt_len,0); + spin_unlock_irqrestore(&card->wandev.lock, smp_flags); + return -EBUSY; + } + + process_udp_mgmt_pkt(card,dev,chan,1); + + spin_unlock_irqrestore(&card->wandev.lock, smp_flags); + + /* This area will still be critical to other + * PIPEMON commands due to udp_pkt_len + * thus we can release the irq */ + + if (atomic_read(&chan->udp_pkt_len) > sizeof(wan_udp_pkt_t)){ + printk(KERN_INFO "%s: Error: Pipemon buf too bit on the way up! %i\n", + card->devname,atomic_read(&chan->udp_pkt_len)); + atomic_set(&chan->udp_pkt_len,0); + return -EINVAL; + } + + if (copy_to_user(ifr->ifr_data,&wan_udp_pkt->wan_udp_hdr,sizeof(wan_udp_hdr_t))){ + atomic_set(&chan->udp_pkt_len,0); + return -EFAULT; + } + + atomic_set(&chan->udp_pkt_len,0); + return 0; + + + default: + if (chan->common.prot_ptr){ + return wp_sppp_do_ioctl(dev,ifr,cmd); + } + + return -EINVAL; + } + return err; +} + + +/*============================================================================= + * Process UDP management packet. + */ + +static int process_udp_mgmt_pkt(sdla_t* card, netdevice_t* dev, + private_area_t* chan, int local_dev ) +{ + unsigned char *buf; + unsigned int len; + struct sk_buff *new_skb; + unsigned short buffer_length; + int udp_mgmt_req_valid = 1; + wan_mbox_t *mb = &card->wan_mbox; + SHARED_MEMORY_INFO_STRUCT flags; + wan_udp_pkt_t *wan_udp_pkt; + struct timeval tv; + int err; + netskb_t *skb; + + wan_udp_pkt = (wan_udp_pkt_t *) chan->udp_pkt_data; + + if (!local_dev){ + + if(chan->udp_pkt_src == UDP_PKT_FRM_NETWORK){ + + /* Only these commands are support for remote debugging. + * All others are not */ + switch(wan_udp_pkt->wan_udp_command) { + + case READ_GLOBAL_STATISTICS: + case READ_MODEM_STATUS: + case READ_CHDLC_LINK_STATUS: + case CPIPE_ROUTER_UP_TIME: + case READ_COMMS_ERROR_STATS: + case READ_CHDLC_OPERATIONAL_STATS: + /* These two commands are executed for + * each request */ + case READ_CHDLC_CONFIGURATION: + case READ_CHDLC_CODE_VERSION: + case WAN_GET_MEDIA_TYPE: + case WAN_FE_GET_CFG: + case WAN_FE_GET_STAT: + case WAN_GET_PROTOCOL: + case WAN_GET_PLATFORM: + udp_mgmt_req_valid = 1; + break; + default: + udp_mgmt_req_valid = 0; + break; + } + } + } + + if(!udp_mgmt_req_valid) { + + /* set length to 0 */ + wan_udp_pkt->wan_udp_data_len = 0; + + /* set return code */ + wan_udp_pkt->wan_udp_return_code = 0xCD; + + if (net_ratelimit()){ + printk(KERN_INFO + "%s: Warning, Illegal UDP command attempted from network: %x\n", + card->devname,wan_udp_pkt->wan_udp_command); + } + + } else { + + wan_udp_hdr_t* udp_hdr = &wan_udp_pkt->wan_udp_hdr; + wan_trace_t *trace_info = &chan->trace_info; + + wan_udp_pkt->wan_udp_opp_flag = 0; + + switch(wan_udp_pkt->wan_udp_command) { + + case CPIPE_ENABLE_TRACING: + + udp_hdr->wan_udphdr_return_code = WAN_CMD_OK; + udp_hdr->wan_udphdr_data_len = 0; + + if (!wan_test_bit(0,&trace_info->tracing_enabled)){ + + trace_info->trace_timeout = SYSTEM_TICKS; + + wan_trace_purge(trace_info); + DEBUG_UDP("%s: Traceing enabled!\n", + card->devname); + wan_set_bit (0,&trace_info->tracing_enabled); + + }else{ + DEBUG_EVENT("%s: Error: Trace running!\n", + card->devname); + udp_hdr->wan_udphdr_return_code = 2; + } + + break; + + + case CPIPE_DISABLE_TRACING: + + + udp_hdr->wan_udphdr_return_code = WAN_CMD_OK; + + if(wan_test_bit(0,&trace_info->tracing_enabled)) { + + wan_clear_bit(0,&trace_info->tracing_enabled); + wan_trace_purge(trace_info); + + DEBUG_UDP("%s: Disabling ADSL trace\n", + card->devname); + + }else{ + /* set return code to line trace already + disabled */ + udp_hdr->wan_udphdr_return_code = 1; + } + + break; + + case CPIPE_GET_TRACE_INFO: + + if(wan_test_bit(0,&trace_info->tracing_enabled)){ + trace_info->trace_timeout = SYSTEM_TICKS; + }else{ + DEBUG_EVENT("%s: Error trace not enabled\n", + card->devname); + /* set return code */ + udp_hdr->wan_udphdr_return_code = 1; + break; + } + + buffer_length = 0; + udp_hdr->wan_udphdr_chdlc_num_frames = 0; + udp_hdr->wan_udphdr_chdlc_ismoredata = 0; + +#if defined(__FreeBSD__) || defined(__OpenBSD__) + while (wan_trace_queue_len(trace_info)){ + WAN_IFQ_POLL(&trace_info->trace_queue, skb); + if (skb == NULL){ + DEBUG_EVENT("%s: No more trace packets in trace queue!\n", + card->devname); + break; + } + if ((WAN_MAX_DATA_SIZE - buffer_length) < skb->m_pkthdr.len){ + /* indicate there are more frames on board & exit */ + udp_hdr->wan_udphdr_chdlc_ismoredata = 0x01; + break; + } + + m_copydata(skb, + 0, + skb->m_pkthdr.len, + &udp_hdr->wan_udphdr_data[buffer_length]); + buffer_length += skb->m_pkthdr.len; + WAN_IFQ_DEQUEUE(&trace_info->trace_queue, skb); + if (skb){ + m_freem(skb); + } + udp_hdr->wan_udphdr_chdlc_num_frames++; + } +#elif defined(__LINUX__) + while ((skb=skb_dequeue(&trace_info->trace_queue)) != NULL){ + + if((MAX_TRACE_BUFFER - buffer_length) < wan_skb_len(skb)){ + + /* indicate there are more frames on board & exit */ + udp_hdr->wan_udphdr_chdlc_ismoredata = 0x01; + + if (buffer_length != 0){ + wan_skb_queue_head(&trace_info->trace_queue, skb); + }else{ + + /* If rx buffer length is greater than the + * whole udp buffer copy only the trace + * header and drop the trace packet */ + + memcpy(&udp_hdr->wan_udphdr_chdlc_data[buffer_length], + wan_skb_data(skb), + sizeof(wan_trace_pkt_t)); + + buffer_length = sizeof(wan_trace_pkt_t); + udp_hdr->wan_udphdr_chdlc_num_frames++; + wan_skb_free(skb); + } + + break; + } + + memcpy(&udp_hdr->wan_udphdr_chdlc_data[buffer_length], + wan_skb_data(skb), + wan_skb_len(skb)); + + buffer_length += wan_skb_len(skb); + wan_skb_free(skb); + udp_hdr->wan_udphdr_chdlc_num_frames++; + } +#endif + /* set the data length and return code */ + udp_hdr->wan_udphdr_data_len = buffer_length; + udp_hdr->wan_udphdr_return_code = WAN_CMD_OK; + break; + + case CPIPE_FT1_READ_STATUS: + card->hw_iface.peek(card->hw, card->flags_off, &flags, sizeof(flags)); + ((unsigned char *)wan_udp_pkt->wan_udp_data )[0] = + flags.FT1_info_struct.parallel_port_A_input; + + ((unsigned char *)wan_udp_pkt->wan_udp_data )[1] = + flags.FT1_info_struct.parallel_port_B_input; + wan_udp_pkt->wan_udp_return_code = COMMAND_OK; + wan_udp_pkt->wan_udp_data_len = 2; + mb->wan_data_len = 2; + break; + + case CPIPE_ROUTER_UP_TIME: + do_gettimeofday( &tv ); + chan->router_up_time = tv.tv_sec - + chan->router_start_time; + *(u_int32_t *)&wan_udp_pkt->wan_udp_data = + chan->router_up_time; + mb->wan_data_len = sizeof(u_int32_t); + wan_udp_pkt->wan_udp_data_len = sizeof(u_int32_t); + wan_udp_pkt->wan_udp_return_code = COMMAND_OK; + break; + + case FT1_MONITOR_STATUS_CTRL: + /* Enable FT1 MONITOR STATUS */ + if ((wan_udp_pkt->wan_udp_data[0] & ENABLE_READ_FT1_STATUS) || + (wan_udp_pkt->wan_udp_data[0] & ENABLE_READ_FT1_OP_STATS)) { + + if( rCount++ != 0 ) { + wan_udp_pkt->wan_udp_return_code = COMMAND_OK; + mb->wan_data_len = 1; + break; + } + } + + /* Disable FT1 MONITOR STATUS */ + if( wan_udp_pkt->wan_udp_data[0] == 0) { + + if( --rCount != 0) { + wan_udp_pkt->wan_udp_return_code = COMMAND_OK; + mb->wan_data_len = 1; + break; + } + } + goto dflt_1; + + case WAN_GET_MEDIA_TYPE: + case WAN_FE_GET_STAT: + case WAN_FE_SET_LB_MODE: + case WAN_FE_FLUSH_PMON: + case WAN_FE_GET_CFG: + if (IS_TE1_CARD(card)){ + card->wandev.fe_iface.process_udp( + &card->fe, + &wan_udp_pkt->wan_udp_cmd, + &wan_udp_pkt->wan_udp_data[0]); + }else if (IS_56K_CARD(card)){ + card->wandev.fe_iface.process_udp( + &card->fe, + &wan_udp_pkt->wan_udp_cmd, + &wan_udp_pkt->wan_udp_data[0]); + }else{ + if (wan_udp_pkt->wan_udp_command == WAN_GET_MEDIA_TYPE){ + wan_udp_pkt->wan_udp_data_len = sizeof(unsigned char); + wan_udp_pkt->wan_udp_return_code = CMD_OK; + }else{ + wan_udp_pkt->wan_udp_return_code = WAN_UDP_INVALID_CMD; + } + } + mb->wan_data_len = wan_udp_pkt->wan_udp_data_len; + break; + + case WAN_GET_PROTOCOL: + wan_udp_pkt->wan_udp_chdlc_num_frames = WANCONFIG_CHDLC; + wan_udp_pkt->wan_udp_return_code = CMD_OK; + mb->wan_data_len = wan_udp_pkt->wan_udp_data_len = 1; + break; + + case WAN_GET_PLATFORM: + wan_udp_pkt->wan_udp_data[0] = WAN_LINUX_PLATFORM; + wan_udp_pkt->wan_udp_return_code = CMD_OK; + mb->wan_data_len = wan_udp_pkt->wan_udp_data_len = 1; + break; + + case WAN_GET_MASTER_DEV_NAME: + wan_udp_pkt->wan_udp_data_len = 0; + wan_udp_pkt->wan_udp_return_code = 0xCD; + break; + + default: +dflt_1: + /* it's a board command */ + mb->wan_command = wan_udp_pkt->wan_udp_command; + mb->wan_data_len = wan_udp_pkt->wan_udp_data_len; + if (mb->wan_data_len) { + memcpy(&mb->wan_data, (unsigned char *) wan_udp_pkt-> + wan_udp_data, mb->wan_data_len); + } + /* run the command on the board */ + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + if (err != COMMAND_OK) { + break; + } + + /* copy the result back to our buffer */ + memcpy(&wan_udp_pkt->wan_udp_hdr.wan_cmd, mb, sizeof(wan_cmd_t)); + + if (mb->wan_data_len) { + memcpy(&wan_udp_pkt->wan_udp_data, &mb->wan_data, + mb->wan_data_len); + } + + } /* end of switch */ + } /* end of else */ + + /* Fill UDP TTL */ + wan_udp_pkt->wan_ip_ttl= card->wandev.ttl; + + if (local_dev){ + wan_udp_pkt->wan_udp_request_reply = UDPMGMT_REPLY; + return 1; + } + + len = wan_reply_udp(card,chan->udp_pkt_data, mb->wan_data_len); + + if(chan->udp_pkt_src == UDP_PKT_FRM_NETWORK){ + + /* Must check if we interrupted if_send() routine. The + * tx buffers might be used. If so drop the packet */ + if (!wan_test_bit(SEND_CRIT,&card->wandev.critical)) { + + if(!chdlc_send(card, chan->udp_pkt_data, len)) { + ++ card->wandev.stats.tx_packets; + card->wandev.stats.tx_bytes += len; + } + } + } else { + + /* Pass it up the stack + Allocate socket buffer */ + if ((new_skb = dev_alloc_skb(len)) != NULL) { + /* copy data into new_skb */ + + buf = skb_put(new_skb, len); + memcpy(buf, chan->udp_pkt_data, len); + + /* Decapsulate pkt and pass it up the protocol stack */ + new_skb->protocol = htons(ETH_P_IP); + new_skb->dev = dev; + new_skb->mac.raw = new_skb->data; + + netif_rx(new_skb); + } else { + + printk(KERN_INFO "%s: no socket buffers available!\n", + card->devname); + } + } + + atomic_set(&chan->udp_pkt_len,0); + + return 0; +} + + + +/*============================================================================ + * Initialize Receive and Transmit Buffers. + */ + +static void init_chdlc_tx_rx_buff( sdla_t* card, netdevice_t *dev ) +{ + wan_mbox_t* mb = &card->wan_mbox; + unsigned long tx_config_off; + unsigned long rx_config_off; + CHDLC_TX_STATUS_EL_CFG_STRUCT tx_config; + CHDLC_RX_STATUS_EL_CFG_STRUCT rx_config; + char err; + + mb->wan_data_len = 0; + mb->wan_command = READ_CHDLC_CONFIGURATION; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + + if(err != COMMAND_OK) { + chdlc_error(card,err,mb); + return; + } + + /* Alex Apr 8 2004 Sangoma ISA card */ + tx_config_off = + ((CHDLC_CONFIGURATION_STRUCT *)mb->wan_data)-> + ptr_CHDLC_Tx_stat_el_cfg_struct; + rx_config_off = + ((CHDLC_CONFIGURATION_STRUCT *)mb->wan_data)-> + ptr_CHDLC_Rx_stat_el_cfg_struct; + /* Setup Head and Tails for buffers */ + card->hw_iface.peek(card->hw, tx_config_off, &tx_config, sizeof(tx_config)); + card->u.c.txbuf_base_off = + tx_config.base_addr_Tx_status_elements; + card->u.c.txbuf_last_off = + card->u.c.txbuf_base_off + + (tx_config.number_Tx_status_elements - 1) * + sizeof(CHDLC_DATA_TX_STATUS_EL_STRUCT); + card->hw_iface.peek(card->hw, rx_config_off, &rx_config, sizeof(rx_config)); + card->u.c.rxbuf_base_off = + rx_config.base_addr_Rx_status_elements; + card->u.c.rxbuf_last_off = + card->u.c.rxbuf_base_off + + (rx_config.number_Rx_status_elements - 1) * + sizeof(CHDLC_DATA_RX_STATUS_EL_STRUCT); + /* Set up next pointer to be used */ + card->u.c.txbuf_off = + tx_config.next_Tx_status_element_to_use; + card->u.c.rxmb_off = + rx_config.next_Rx_status_element_to_use; + + /* Setup Actual Buffer Start and end addresses */ + card->u.c.rx_base_off = rx_config.base_addr_Rx_buffer; + card->u.c.rx_top_off = rx_config.end_addr_Rx_buffer; + +} + +/*============================================================================= + * Perform Interrupt Test by running READ_CHDLC_CODE_VERSION command MAX_INTR + * _TEST_COUNTER times. + */ +static int intr_test( sdla_t* card) +{ + wan_mbox_t* mb = &card->wan_mbox; + int err,i; + + card->timer_int_enabled = 0; + + /* The critical flag is unset because during intialization (if_open) + * we want the interrupts to be enabled so that when the wpc_isr is + * called it does not exit due to critical flag set. + */ + + err = chdlc_set_intr_mode(card, APP_INT_ON_COMMAND_COMPLETE); + + if (err == CMD_OK) { + for (i = 0; i < MAX_INTR_TEST_COUNTER; i ++) { + memset(mb,0,sizeof(wan_mbox_t)); + mb->wan_data_len = 0; + mb->wan_command = READ_CHDLC_CODE_VERSION; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + + if (err != CMD_OK) + chdlc_error(card, err, mb); + + udelay(10000); + schedule(); + } + }else{ + return err; + } + + card->hw_iface.poke_byte(card->hw, card->intr_type_off, 0x00); + + err = chdlc_set_intr_mode(card, 0); + if (err != CMD_OK) + return err; + + return 0; +} + +/*============================================================================== + * Determine what type of UDP call it is. CPIPEAB ? + */ +static int udp_pkt_type(struct sk_buff *skb, sdla_t* card) +{ + wan_udp_pkt_t *wan_udp_pkt = (wan_udp_pkt_t *)(skb->data+4); + + if (skb->len < sizeof(wan_udp_pkt_t)){ + return UDP_INVALID_TYPE; + } + + +#ifdef _WAN_UDP_DEBUG + printk(KERN_INFO "SIG %s = %s\n\ + UPP %x = %x\n\ + PRT %x = %x\n\ + REQ %i = %i\n\ + 36 th = %x 37th = %x\n", + wan_udp_pkt->wan_udp_signature, + UDPMGMT_SIGNATURE, + wan_udp_pkt->wan_udp_dport, + ntohs(card->wandev.udp_port), + wan_udp_pkt->wan_ip_p, + UDPMGMT_UDP_PROTOCOL, + wan_udp_pkt->wan_udp_request_reply, + UDPMGMT_REQUEST, + skb->data[36], skb->data[37]); +#endif + + if ((wan_udp_pkt->wan_udp_dport == ntohs(card->wandev.udp_port)) && + (wan_udp_pkt->wan_ip_p == UDPMGMT_UDP_PROTOCOL) && + (wan_udp_pkt->wan_udp_request_reply == UDPMGMT_REQUEST)) { + if (!strncmp(wan_udp_pkt->wan_udp_signature,UDPMGMT_SIGNATURE,8)){ + return UDP_CPIPE_TYPE; + } + if (!strncmp(wan_udp_pkt->wan_udp_signature,GLOBAL_UDP_SIGNATURE,8)){ + return UDP_CPIPE_TYPE; + } + } + return UDP_INVALID_TYPE; +} + + +/*============================================================================ + * Set PORT state. + */ +static void port_set_state (sdla_t *card, int state) +{ + netdevice_t *dev; + private_area_t *chan; + + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + if (!dev || !dev->priv){ + return; + } + + chan=dev->priv; + + if (card->wandev.state != state) + { + switch (state) + { + case WAN_CONNECTED: + printk (KERN_INFO "%s: HDLC link connected!\n", + card->devname); + + WAN_NETIF_WAKE_QUEUE(dev); + WAN_NETIF_CARRIER_ON(dev); + +#ifdef CONFIG_PRODUCT_WANPIPE_ANNEXG + if (chan->common.usedby == ANNEXG && + chan->annexg_dev){ + if (IS_FUNC_CALL(lapb_protocol,lapb_link_up)){ + lapb_protocol.lapb_link_up(chan->annexg_dev); + } + } +#endif + + + if (chan->common.usedby == STACK){ + wanpipe_lip_connect(chan,0); + break; + } + + break; + + case WAN_CONNECTING: + printk (KERN_INFO "%s: HDLC link connecting...\n", + card->devname); + WAN_NETIF_STOP_QUEUE(dev); + WAN_NETIF_CARRIER_OFF(dev); + break; + + case WAN_DISCONNECTED: + printk (KERN_INFO "%s: HDLC link disconnected!\n", + card->devname); + + WAN_NETIF_STOP_QUEUE(dev); + WAN_NETIF_CARRIER_OFF(dev); + +#ifdef CONFIG_PRODUCT_WANPIPE_ANNEXG + if (chan->common.usedby == ANNEXG && + chan->annexg_dev){ + if (IS_FUNC_CALL(lapb_protocol,lapb_link_down)) + lapb_protocol.lapb_link_down(chan->annexg_dev); + break; + } +#endif + if (chan->common.usedby == STACK){ + wanpipe_lip_disconnect(chan,0); + break; + } + + break; + } + + card->wandev.state = state; + chan->common.state = state; + } +} + +void s508_lock (sdla_t *card, unsigned long *smp_flags) +{ + spin_lock_irqsave(&card->wandev.lock, *smp_flags); + if (card->next){ + /* It is ok to use spin_lock here, since we + * already turned off interrupts */ + spin_lock(&card->next->wandev.lock); + } +} + +void s508_unlock (sdla_t *card, unsigned long *smp_flags) +{ + if (card->next){ + spin_unlock(&card->next->wandev.lock); + } + spin_unlock_irqrestore(&card->wandev.lock, *smp_flags); +} + + + +/*=========================================================================== + * config_chdlc + * + * Configure the chdlc protocol and enable communications. + * + * The if_open() function binds this function to the poll routine. + * Therefore, this function will run every time the chdlc interface + * is brought up. We cannot run this function from the if_open + * because if_open does not have access to the remote IP address. + * + * If the communications are not enabled, proceed to configure + * the card and enable communications. + * + * If the communications are enabled, it means that the interface + * was shutdown by ether the user or driver. In this case, we + * have to check that the IP addresses have not changed. If + * the IP addresses have changed, we have to reconfigure the firmware + * and update the changed IP addresses. Otherwise, just exit. + * + */ + +static int config_chdlc (sdla_t *card) +{ + netdevice_t *dev; + + dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); + if (card->u.c.comm_enabled){ + chdlc_comm_disable(card); + port_set_state(card, WAN_DISCONNECTED); + } + + /* Setup the Board for asynchronous mode */ + if (card->u.c.async_mode){ + if (set_asy_config(card)) { + printk (KERN_INFO "%s: Failed Async configuration!\n", + card->devname); + port_set_state(card, WAN_DISCONNECTED); + return -EINVAL; + } + }else{ + if (set_chdlc_config(card)) { + printk(KERN_INFO "%s: HDLC Configuration Failed!\n", + card->devname); + port_set_state(card, WAN_DISCONNECTED); + return -EINVAL; + } + } + + card->hw_iface.poke_byte(card->hw, card->intr_type_off, 0x00); + card->hw_iface.poke_byte(card->hw, card->intr_perm_off, 0x00); + if (IS_TE1_CARD(card)) { + int err = -EINVAL; + printk(KERN_INFO "%s: Configuring onboard %s CSU/DSU\n", + card->devname, + (IS_T1_CARD(card))?"T1":"E1"); + if (card->wandev.fe_iface.config){ + err = card->wandev.fe_iface.config(&card->fe); + } + if (err){ + printk(KERN_INFO "%s: Failed %s configuratoin!\n", + card->devname, + (IS_T1_CARD(card))?"T1":"E1"); + return -EINVAL; + } + } + + if (IS_56K_CARD(card)) { + int err = -EINVAL; + printk(KERN_INFO "%s: Configuring 56K onboard CSU/DSU\n", + card->devname); + if (card->wandev.fe_iface.config){ + err = card->wandev.fe_iface.config(&card->fe); + } + if(err){ + printk (KERN_INFO "%s: Failed 56K configuration!\n", + card->devname); + return -EINVAL; + } + } + + + /* Set interrupt mode and mask */ + if (chdlc_set_intr_mode(card, APP_INT_ON_RX_FRAME | + APP_INT_ON_GLOBAL_EXCEP_COND | + APP_INT_ON_TX_FRAME | + APP_INT_ON_CHDLC_EXCEP_COND | APP_INT_ON_TIMER)){ + printk (KERN_INFO "%s: Failed to set interrupt triggers!\n", + card->devname); + return 0; + } + + /* Mask All interrupts */ + card->hw_iface.clear_bit(card->hw, card->intr_perm_off, + (APP_INT_ON_RX_FRAME | APP_INT_ON_TX_FRAME | + APP_INT_ON_TIMER | APP_INT_ON_GLOBAL_EXCEP_COND | + APP_INT_ON_CHDLC_EXCEP_COND)); + + init_chdlc_tx_rx_buff(card, dev); + + if (card->u.c.async_mode){ + if (asy_comm_enable(card) != 0) { + printk(KERN_INFO "%s: Failed to enable async commnunication!\n", + card->devname); + card->hw_iface.poke_byte(card->hw, card->intr_perm_off, 0x00); + card->u.c.comm_enabled=0; + chdlc_set_intr_mode(card,0); + port_set_state(card, WAN_DISCONNECTED); + return 0; + } + }else{ + if (chdlc_comm_enable(card) != 0) { + printk(KERN_INFO "%s: Failed to enable chdlc communications!\n", + card->devname); + card->hw_iface.poke_byte(card->hw, card->intr_perm_off, 0x00); + card->u.c.comm_enabled=0; + chdlc_set_intr_mode(card,0); + port_set_state(card, WAN_DISCONNECTED); + return 0; + } + } + + /* Initialize Rx/Tx buffer control fields */ + init_chdlc_tx_rx_buff(card, dev); + card->u.c.state = WAN_CONNECTING; + port_set_state(card, WAN_CONNECTING); + + /* Manually poll the 56K CSU/DSU to get the status */ + if (IS_56K_CARD(card)) { + /* 56K Update CSU/DSU alarms */ + card->wandev.fe_iface.read_alarm(&card->fe, 1); + } + + /* Unmask all interrupts except the Transmit and Timer interrupts */ + card->hw_iface.set_bit(card->hw, card->intr_perm_off, + (APP_INT_ON_RX_FRAME | APP_INT_ON_GLOBAL_EXCEP_COND | + APP_INT_ON_CHDLC_EXCEP_COND)); + card->hw_iface.poke_byte(card->hw, card->intr_type_off, 0); + return 0; +} + + +static void send_ppp_term_request (netdevice_t *dev) +{ + struct sk_buff *new_skb; + unsigned char *buf; + private_area_t *chan=dev->priv; + + if (!chan->common.prot_ptr){ + return; + } + + if (chan->ignore_modem) + return; + + if ((new_skb = dev_alloc_skb(8)) != NULL) { + /* copy data into new_skb */ + + buf = skb_put(new_skb, 8); + sprintf(buf,"%c%c%c%c%c%c%c%c", 0xFF,0x03,0xC0,0x21,0x05,0x98,0x00,0x07); + + /* Decapsulate pkt and pass it up the protocol stack */ + new_skb->protocol = htons(ETH_P_WAN_PPP); + new_skb->dev = dev; + new_skb->mac.raw = new_skb->data; + + wan_skb_queue_tail(&chan->rx_queue,new_skb); + WAN_TASKLET_SCHEDULE((&chan->tasklet)); + } +} + +/* + * ****************************************************************** + * Proc FS function + */ +#define PROC_CFG_FRM "%-15s| %-12s|\n" +#define PROC_STAT_FRM "%-15s| %-12s| %-14s|\n" +static char chdlc_config_hdr[] = + "Interface name | Device name |\n"; +static char chdlc_status_hdr[] = + "Interface name | Device name | Status |\n"; + +static int chdlc_get_config_info(void* priv, struct seq_file* m, int* stop_cnt) +{ + private_area_t* chan = priv; + sdla_t* card = NULL; + + if (chan == NULL) + return m->count; + card = chan->card; + + if ((m->from == 0 && m->count == 0) || (m->from && m->from == *stop_cnt)){ + PROC_ADD_LINE(m, + "%s", chdlc_config_hdr); + } + + PROC_ADD_LINE(m, + PROC_CFG_FRM, card->u.c.if_name, card->devname); + return m->count; +} + +static int chdlc_get_status_info(void* priv, struct seq_file* m, int* stop_cnt) +{ + private_area_t* chan = priv; + sdla_t* card = NULL; + + if (chan == NULL) + return m->count; + card = chan->card; + + if ((m->from == 0 && m->count == 0) || (m->from && m->from == *stop_cnt)){ + PROC_ADD_LINE(m, + "%s", chdlc_status_hdr); + } + + PROC_ADD_LINE(m, + PROC_STAT_FRM, + card->u.c.if_name, card->devname, STATE_DECODE(chan->common.state)); + return m->count; +} + +#define PROC_DEV_FR_S_FRM "%-20s| %-14s|\n" +#define PROC_DEV_FR_D_FRM "%-20s| %-14d|\n" +#define PROC_DEV_SEPARATE "=====================================\n" + + +static int chdlc_set_dev_config(struct file *file, + const char *buffer, + unsigned long count, + void *data) +{ + int cnt = 0; + wan_device_t* wandev = (void*)data; + sdla_t* card = NULL; + + if (wandev == NULL) + return cnt; + + card = (sdla_t*)wandev->private; + + printk(KERN_INFO "%s: New device config (%s)\n", + wandev->name, buffer); + /* Parse string */ + + return count; +} + + +#define PROC_IF_FR_S_FRM "%-30s\t%-14s\n" +#define PROC_IF_FR_D_FRM "%-30s\t%-14d\n" +#define PROC_IF_FR_L_FRM "%-30s\t%-14ld\n" +#define PROC_IF_SEPARATE "====================================================\n" + + +static int chdlc_set_if_info(struct file *file, + const char *buffer, + unsigned long count, + void *data) +{ + netdevice_t* dev = (void*)data; + private_area_t* chan = NULL; + sdla_t* card = NULL; + + if (dev == NULL || dev->priv == NULL) + return count; + chan = (private_area_t*)dev->priv; + if (chan->card == NULL) + return count; + card = chan->card; + + printk(KERN_INFO "%s: New interface config (%s)\n", + card->u.c.if_name, buffer); + /* Parse string */ + + return count; +} + +static int set_adapter_config (sdla_t* card) +{ + wan_mbox_t* mb = &card->wan_mbox; + ADAPTER_CONFIGURATION_STRUCT* cfg = (ADAPTER_CONFIGURATION_STRUCT*)mb->wan_data; + int err; + + card->hw_iface.getcfg(card->hw, SDLA_ADAPTERTYPE, &cfg->adapter_type); + cfg->adapter_config = 0x00; + cfg->operating_frequency = 00; + mb->wan_data_len = sizeof(ADAPTER_CONFIGURATION_STRUCT); + mb->wan_command = SET_ADAPTER_CONFIGURATION; + err = card->hw_iface.cmd(card->hw, card->mbox_off, mb); + + if(err != COMMAND_OK) { + chdlc_error(card,err,mb); + } + return (err); +} + +/*============================================================================ + * Enable timer interrupt + */ +static void chdlc_enable_timer (void* card_id) +{ + sdla_t* card = (sdla_t*)card_id; + + card->u.c.timer_int_enabled |= TMR_INT_ENABLED_TE; + card->hw_iface.set_bit(card->hw, card->intr_perm_off, APP_INT_ON_TIMER); + return; +} + + + +/**SECTION************************************************** + * + * Bottom Half Handlers + * + **********************************************************/ + +static void wp_bh (unsigned long data) +{ + private_area_t *chan = (private_area_t *)data; + sdla_t *card = chan->card; + netskb_t *skb; + int len; + + if (wan_test_bit(PERI_CRIT, (void*)&card->wandev.critical)){ + DEBUG_EVENT("%s: WpBH PERI Critical\n", + card->devname); + WAN_TASKLET_END((&chan->tasklet)); + return; + } + + if (!WAN_NETIF_UP(chan->dev)){ + DEBUG_EVENT("%s: WpBH Dev done\n", + card->devname); + WAN_TASKLET_END((&chan->tasklet)); + return; + } + + while ((skb=wan_skb_dequeue(&chan->rx_queue))){ + + len=skb->len; + + if (chan->common.usedby == WANPIPE){ + + card->wandev.stats.rx_packets ++; + card->wandev.stats.rx_bytes += skb->len; + + wp_sppp_input(skb->dev,skb); + + }else if (chan->common.usedby == API){ + + if (wan_skb_headroom(skb) >= sizeof(api_rx_hdr_t)){ + api_rx_hdr_t *rx_hdr= + (api_rx_hdr_t*)wan_skb_push(skb,sizeof(api_rx_hdr_t)); + memset(rx_hdr,0,sizeof(api_rx_hdr_t)); + }else{ + if (WAN_NET_RATELIMIT()){ + DEBUG_EVENT("%s: Error Rx pkt headroom %d < %d\n", + chan->if_name, + wan_skb_headroom(skb), + sizeof(api_rx_hdr_t)); + } + ++card->wandev.stats.rx_dropped; + wan_skb_free(skb); + continue; + } + + skb->protocol = htons(PVC_PROT); + skb->mac.raw = wan_skb_data(skb); + skb->dev = chan->common.dev; + skb->pkt_type = WAN_PACKET_DATA; + + if (wan_api_rx(chan,skb) == 0){ + card->wandev.stats.rx_packets++; + card->wandev.stats.rx_bytes += len; + }else{ + ++card->wandev.stats.rx_dropped; + wan_skb_free(skb); + } + + }else if (chan->common.usedby == STACK){ + + if (wanpipe_lip_rx(chan,skb) != 0){ + ++card->wandev.stats.rx_dropped; + wan_skb_free(skb); + }else{ + card->wandev.stats.rx_packets++; + card->wandev.stats.rx_bytes += len; + } + + }else{ + +#ifdef CONFIG_PRODUCT_WANPIPE_ANNEXG + if (chan->annexg_dev){ + if (IS_FUNC_CALL(lapb_protocol,lapb_rx)){ + lapb_protocol.lapb_rx(chan->annexg_dev,skb); + card->wandev.stats.rx_packets++; + card->wandev.stats.rx_bytes += len; + }else{ + wan_skb_free(skb); + ++card->wandev.stats.rx_dropped; + } + }else{ + wan_skb_free(skb); + ++card->wandev.stats.rx_dropped; + } +#else + wan_skb_free(skb); + ++card->wandev.stats.rx_dropped; +#endif + } + } + + WAN_TASKLET_END((&chan->tasklet)); + return; +} + +#ifdef CONFIG_PRODUCT_WANPIPE_ANNEXG +static int bind_annexg(netdevice_t *dev, netdevice_t *annexg_dev) +{ + unsigned long smp_flags=0; + private_area_t* chan = dev->priv; + sdla_t *card = chan->card; + if (!chan) + return -EINVAL; + + if (chan->common.usedby != ANNEXG) + return -EPROTONOSUPPORT; + + if (chan->annexg_dev) + return -EBUSY; + + spin_lock_irqsave(&card->wandev.lock,smp_flags); + chan->annexg_dev = annexg_dev; + spin_unlock_irqrestore(&card->wandev.lock,smp_flags); + return 0; +} + + +static netdevice_t * un_bind_annexg(wan_device_t *wandev, netdevice_t *annexg_dev) +{ + struct wan_dev_le *devle; + netdevice_t *dev; + unsigned long smp_flags=0; + sdla_t *card = wandev->private; + + WAN_LIST_FOREACH(devle, &card->wandev.dev_head, dev_link){ + private_area_t* chan; + + dev = WAN_DEVLE2DEV(devle); + if (dev == NULL || (chan = wan_netif_priv(dev)) == NULL) + continue; + + if (!chan->annexg_dev || chan->common.usedby != ANNEXG) + continue; + + if (chan->annexg_dev == annexg_dev){ + spin_lock_irqsave(&card->wandev.lock,smp_flags); + chan->annexg_dev = NULL; + spin_unlock_irqrestore(&card->wandev.lock,smp_flags); + return dev; + } + } + return NULL; +} + + +static void get_active_inactive(wan_device_t *wandev, netdevice_t *dev, + void *wp_stats_ptr) +{ + private_area_t* chan = dev->priv; + wp_stack_stats_t *wp_stats = (wp_stack_stats_t *)wp_stats_ptr; + + if (chan->common.usedby == ANNEXG && chan->annexg_dev){ + if (IS_FUNC_CALL(lapb_protocol,lapb_get_active_inactive)){ + lapb_protocol.lapb_get_active_inactive(chan->annexg_dev,wp_stats); + } + } + + if (chan->common.state == WAN_CONNECTED){ + wp_stats->fr_active++; + }else{ + wp_stats->fr_inactive++; + } +} + +static int +get_map(wan_device_t *wandev, netdevice_t *dev, struct seq_file* m, int* stop_cnt) +{ + private_area_t* chan = dev->priv; + + if (!(dev->flags&IFF_UP)){ + return m->count; + } + + if (chan->common.usedby == ANNEXG && chan->annexg_dev){ + if (IS_FUNC_CALL(lapb_protocol,lapb_get_map)){ + return lapb_protocol.lapb_get_map(chan->annexg_dev, + m); + } + } + + PROC_ADD_LINE(m, + "%15s:%s:%c:%s:%c\n", + chan->label, + wandev->name,(wandev->state == WAN_CONNECTED) ? '*' : ' ', + dev->name,(chan->common.state == WAN_CONNECTED) ? '*' : ' '); + + return m->count; +} + +#endif + +/****** End ****************************************************************/ diff -Nur linux.org/drivers/net/wan/wanpipe_syncppp.c linux-2.6.17/drivers/net/wan/wanpipe_syncppp.c --- linux.org/drivers/net/wan/wanpipe_syncppp.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/drivers/net/wan/wanpipe_syncppp.c 2006-08-30 10:07:17.000000000 +0000 @@ -0,0 +1,3558 @@ +/* + * NET3: A (fairly minimal) implementation of synchronous PPP for Linux + * as well as a CISCO HDLC implementation. See the copyright + * message below for the original source. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the license, or (at your option) any later version. + * + * Note however. This code is also used in a different form by FreeBSD. + * Therefore when making any non OS specific change please consider + * contributing it back to the original author under the terms + * below in addition. + * -- Alan + * + * Port for Linux-2.1 by Jan "Yenya" Kasprzak + */ + +/* + * Synchronous PPP/Cisco link level subroutines. + * Keepalive protocol implemented in both Cisco and PPP modes. + * + * Copyright (C) 1994 Cronyx Ltd. + * Author: Serge Vakulenko, + * + * This software is distributed with NO WARRANTIES, not even the implied + * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Authors grant any other persons or organisations permission to use + * or modify this software as long as this message is kept with the software, + * all derivative works or modified versions. + * + * Version 1.9, Wed Oct 4 18:58:15 MSK 1995 + * Version 2.0, Fri Aug 30 09:59:07 EDT 2002 + * Version 2.1, Wed Mar 26 10:03:00 EDT 2003 + * + * $Id$ + * $Id$ + */ + +/* + * + * Changes: v2.1 by David Rokhvarg + * + * Added PAP and CHAP support. + * o Only as a peer, not an authenticator. + * + * Changes: v2.0 by Nenad Corbic + * + * Added /proc/net/wanrouter/syncppp support. + * o It displays all PPP protocol statistics + * o Allows the user to enable debugging + * dynamically via /proc file system by + * writting commands to the /proc/net/syncppp file. + * o Replaced all cli() instances with spin_lock_irqsave(). + * o The state of the ppp link can be determined via + * /proc file system. + * + * FIXME: A next step would be to create /proc/net/syncppp + * directory and have the mib,config,status files + * instead of one big file. + */ + +#undef DEBUG +#define _K22X_MODULE_FIX_ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,10) +#define snprintf(a,b,c,d...) sprintf(a,c,##d) +#endif + +#define MAXALIVECNT 6 /* max. alive packets */ + +#define LCP_CONF_REQ 1 /* PPP LCP configure request */ +#define LCP_CONF_ACK 2 /* PPP LCP configure acknowledge */ +#define LCP_CONF_NAK 3 /* PPP LCP configure negative ack */ +#define LCP_CONF_REJ 4 /* PPP LCP configure reject */ +#define LCP_TERM_REQ 5 /* PPP LCP terminate request */ +#define LCP_TERM_ACK 6 /* PPP LCP terminate acknowledge */ +#define LCP_CODE_REJ 7 /* PPP LCP code reject */ +#define LCP_PROTO_REJ 8 /* PPP LCP protocol reject */ +#define LCP_ECHO_REQ 9 /* PPP LCP echo request */ +#define LCP_ECHO_REPLY 10 /* PPP LCP echo reply */ +#define LCP_DISC_REQ 11 /* PPP LCP discard request */ + +#define LCP_OPT_MRU 1 /* maximum receive unit */ +#define LCP_OPT_ASYNC_MAP 2 /* async control character map */ +#define LCP_OPT_AUTH_PROTO 3 /* authentication protocol */ +#define LCP_OPT_QUAL_PROTO 4 /* quality protocol */ +#define LCP_OPT_MAGIC 5 /* magic number */ +#define LCP_OPT_RESERVED 6 /* reserved */ +#define LCP_OPT_PROTO_COMP 7 /* protocol field compression */ +#define LCP_OPT_ADDR_COMP 8 /* address/control field compression */ + +#define IPCP_CONF_REQ LCP_CONF_REQ /* PPP IPCP configure request */ +#define IPCP_CONF_ACK LCP_CONF_ACK /* PPP IPCP configure acknowledge */ +#define IPCP_CONF_NAK LCP_CONF_NAK /* PPP IPCP configure negative ack */ +#define IPCP_CONF_REJ LCP_CONF_REJ /* PPP IPCP configure reject */ +#define IPCP_TERM_REQ LCP_TERM_REQ /* PPP IPCP terminate request */ +#define IPCP_TERM_ACK LCP_TERM_ACK /* PPP IPCP terminate acknowledge */ +#define IPCP_CODE_REJ LCP_CODE_REJ /* PPP IPCP code reject */ + +#define CISCO_MULTICAST 0x8f /* Cisco multicast address */ +#define CISCO_UNICAST 0x0f /* Cisco unicast address */ +#define CISCO_KEEPALIVE 0x8035 /* Cisco keepalive protocol */ +#define CISCO_ADDR_REQ 0 /* Cisco address request */ +#define CISCO_ADDR_REPLY 1 /* Cisco address reply */ +#define CISCO_KEEPALIVE_REQ 2 /* Cisco keepalive request */ + +/* states are named and numbered according to RFC 1661 */ +#define STATE_INITIAL 0 +#define STATE_STARTING 1 +#define STATE_CLOSED 2 +#define STATE_STOPPED 3 +#define STATE_CLOSING 4 +#define STATE_STOPPING 5 +#define STATE_REQ_SENT 6 +#define STATE_ACK_RCVD 7 +#define STATE_ACK_SENT 8 +#define STATE_OPENED 9 + +#define PAP_REQ 1 /* PAP name/password request */ +#define PAP_ACK 2 /* PAP acknowledge */ +#define PAP_NAK 3 /* PAP fail */ + +#define CHAP_CHALLENGE 1 /* CHAP challenge request */ +#define CHAP_RESPONSE 2 /* CHAP challenge response */ +#define CHAP_SUCCESS 3 /* CHAP response ok */ +#define CHAP_FAILURE 4 /* CHAP response failed */ + +#define CHAP_MD5 5 /* hash algorithm - MD5 */ + + + +struct ppp_header { + u8 address; + u8 control; + u16 protocol; +}; +#define PPP_HEADER_LEN sizeof (struct ppp_header) + +struct lcp_header { + u8 type; + u8 ident; + u16 len; +}; + +struct ipcp_header { + u8 type; + u8 len; + unsigned char data[1]; +}; + + +#define LCP_HEADER_LEN sizeof (struct lcp_header) + +struct cisco_packet { + u32 type; + u32 par1; + u32 par2; + u16 rel; + u16 time0; + u16 time1; +}; +#define CISCO_PACKET_LEN 18 +#define CISCO_BIG_PACKET_LEN 20 + +#define MAX_AUTHENTICATE_PACKET_LEN 256 + +///////////////////////////// + +/* + * We follow the spelling and capitalization of RFC 1661 here, to make + * it easier comparing with the standard. Please refer to this RFC in + * case you can't make sense out of these abbreviation; it will also + * explain the semantics related to the various events and actions. + */ +struct cp { + u_short proto; /* PPP control protocol number */ + u_char protoidx; /* index into state table in struct sppp */ + u_char flags; +#define CP_LCP 0x01 /* this is the LCP */ +#define CP_AUTH 0x02 /* this is an authentication protocol */ +#define CP_NCP 0x04 /* this is a NCP */ +#define CP_QUAL 0x08 /* this is a quality reporting protocol */ + const char *name; /* name of this control protocol */ + /* event handlers */ + void (*Up)(struct sppp *sp); + void (*Down)(struct sppp *sp); + void (*Open)(struct sppp *sp); + void (*Close)(struct sppp *sp); + void (*TO)(void *sp); + int (*RCR)(struct sppp *sp, struct lcp_header *h, int len); + void (*RCN_rej)(struct sppp *sp, struct lcp_header *h, int len); + void (*RCN_nak)(struct sppp *sp, struct lcp_header *h, int len); + /* actions */ + void (*tlu)(struct sppp *sp); + void (*tld)(struct sppp *sp); + void (*tls)(struct sppp *sp); + void (*tlf)(struct sppp *sp); + void (*scr)(struct sppp *sp); +}; + +//static struct sppp *spppq; +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +static struct callout_handle keepalive_ch; +#endif + +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#define SPP_FMT "%s%d: " +#define SPP_ARGS(ifp) (ifp)->if_name, (ifp)->if_unit +#else +#define SPP_FMT "%s: " +#define SPP_ARGS(ifp) (ifp)->name +#endif + +/* almost every function needs these */ +#define STDDCL \ + struct net_device *dev = sp->pp_if; \ + int debug = sp->pp_flags & PP_DEBUG + +# define UNTIMEOUT( arg ) auth_clear_timeout(arg) +# define TIMEOUT(fun, arg, time_in_seconds) auth_timeout(fun, arg, time_in_seconds) +# define IOCTL_CMD_T int + +//////////////////////////// + +static struct sppp *spppq; +static struct timer_list sppp_keepalive_timer; + +wan_spinlock_t spppq_lock; +wan_spinlock_t authenticate_lock; + +static void sppp_keepalive (unsigned long dummy); +static void sppp_cp_send (struct sppp *sp, u16 proto, u8 type, + u8 ident, u16 len, void *data); +static void sppp_cisco_send (struct sppp *sp, int type, long par1, long par2); +static void sppp_lcp_input (struct sppp *sp, struct sk_buff *m); +static void sppp_cisco_input (struct sppp *sp, struct sk_buff *m); +static void sppp_ipcp_input (struct sppp *sp, struct sk_buff *m); +static void sppp_lcp_open (struct sppp *sp); +static void sppp_ipcp_open (struct sppp *sp); +static int sppp_lcp_conf_parse_options (struct sppp *sp, struct lcp_header *h, + int len, u32 *magic); +static void sppp_cp_timeout (unsigned long arg); +static char *sppp_lcp_type_name (u8 type); +static char *sppp_ipcp_type_name (u8 type); +static void sppp_print_bytes (u8 *p, u16 len); + +static int sppp_strnlen(u_char *p, int max); +static const char * sppp_auth_type_name(u_short proto, u_char type); +static void sppp_print_string(const char *p, u_short len); +static void sppp_cp_change_state(const struct cp *cp, struct sppp *sp, + int newstate); +static void +sppp_auth_send(struct sppp *sp, + unsigned int protocol, unsigned int type, unsigned int id, + ...); + +static void auth_timeout(void * function, struct sppp *p, unsigned int seconds); +static void auth_clear_timeout(struct sppp *p); +static void sppp_phase_network(struct sppp *sp); +static const char * sppp_phase_name(enum ppp_phase phase); + +static const char * sppp_proto_name(u_short proto); +static const char * sppp_state_name(int state); +static void sppp_null(struct sppp *unused); + +static void sppp_pap_scr(struct sppp *sp); + +static void sppp_chap_input(struct sppp *sp, struct sk_buff *skb); +static void sppp_chap_init(struct sppp *sp); +static void sppp_chap_open(struct sppp *sp); +static void sppp_chap_close(struct sppp *sp); +static void sppp_chap_TO(void *sp); +static void sppp_chap_tlu(struct sppp *sp); +static void sppp_chap_tld(struct sppp *sp); +static void sppp_chap_scr(struct sppp *sp); + +#ifdef CONFIG_PROC_FS +#include +#include /* copy_to_user */ +#include + +/* Proc filesystem interface */ + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) +static int router_proc_perms(struct inode *, int); +static ssize_t router_proc_read(struct file *file, char *buf, size_t count, loff_t *ppos); +static ssize_t router_proc_write(struct file *file, const char *buf, size_t count, + loff_t *ppos); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) +static int status_get_info(char* buf, char** start, off_t offs, int len); +#else +static int status_get_info(char* buf, char** start, off_t offs, int len, int dummy); +#endif + +static char *decode_lcp_state(int state); +static char *decode_ipcp_state(int state); + +int sppp_proc_init (void); +void sppp_proc_cleanup (void); +#endif + +#endif + +/*Added by Nenad Corbic + *Dynamically configurable PPP options*/ +static unsigned int sppp_keepalive_interval; +static unsigned int sppp_max_keepalive_count; + +static void sppp_bh (void *); + +extern unsigned long wan_get_ip_address (netdevice_t *dev, int option); +extern unsigned long wan_set_ip_address (netdevice_t *dev, int option, unsigned long ip); +extern void wan_add_gateway(netdevice_t *dev); + +static int debug; + +/* + * + */ +static const struct cp chap = { + PPP_CHAP, IDX_CHAP, CP_AUTH, "chap", + sppp_null, sppp_null, sppp_chap_open, sppp_chap_close, + sppp_chap_TO, 0, 0, 0, + sppp_chap_tlu, sppp_chap_tld, sppp_null, sppp_null, + sppp_chap_scr +}; + + +/* + * Interface down stub + */ + +static void if_down(struct net_device *dev) +{ + struct sppp *sp = (struct sppp *)sppp_of(dev); + WAN_ASSERT1((!sp)); + + sp->pp_link_state=SPPP_LINK_DOWN; +} + +/* + * Timeout routine activations. + */ + +static void sppp_set_timeout(struct sppp *p,int s) +{ + if (! (p->pp_flags & PP_TIMO)) + { + init_timer(&p->pp_timer); + p->pp_timer.function=sppp_cp_timeout; + p->pp_timer.expires=jiffies+s*HZ; + p->pp_timer.data=(unsigned long)p; + p->pp_flags |= PP_TIMO; + add_timer(&p->pp_timer); + } +} + +static void sppp_clear_timeout(struct sppp *p) +{ + if (p->pp_flags & PP_TIMO) + { + del_timer(&p->pp_timer); + p->pp_flags &= ~PP_TIMO; + } +} + +/* + * Timeout routines for authentication protocols + */ + +static void auth_timeout(void * function, struct sppp *p, unsigned int seconds) +{ + //do nothing for now!! + return; + + //printk(KERN_INFO "auth_timeout() : seconds : %u, p->pp_auth_flags : 0x%X\n", + // seconds, p->pp_auth_flags); + + //only one of them can be waiting to timeout at a time + if (! (p->pp_auth_flags & PP_TIMO1)) + { + printk(KERN_INFO "starting pp_auth_timer...\n"); + init_timer(&p->pp_auth_timer); + p->pp_auth_timer.function = function; + p->pp_auth_timer.expires = jiffies + seconds * HZ; + p->pp_auth_timer.data = (unsigned long)p; + p->pp_auth_flags |= PP_TIMO1; + add_timer(&p->pp_auth_timer); + } +} + +static void auth_clear_timeout(struct sppp *p) +{ + //do nothing for now!! + return; + + //printk(KERN_INFO "auth_clear_timeout()\n"); + + if (p->pp_auth_flags & PP_TIMO1) + { + printk("deleting pp_auth_timer timer...\n"); + del_timer(&p->pp_auth_timer); + p->pp_auth_flags &= ~PP_TIMO1; + } +} + + +/** + * wp_sppp_input - receive and process a WAN PPP frame + * @skb: The buffer to process + * @dev: The device it arrived on + * + * This can be called directly by cards that do not have + * timing constraints but is normally called from the network layer + * after interrupt servicing to process frames queued via netif_rx(). + * + * We process the options in the card. If the frame is destined for + * the protocol stacks then it requeues the frame for the upper level + * protocol. If it is a control from it is processed and discarded + * here. + */ + +void wp_sppp_input (struct net_device *dev, struct sk_buff *skb) +{ + struct ppp_header *h; + struct sppp *sp = (struct sppp *)sppp_of(dev); + + skb->dev=dev; + skb->mac.raw=skb->data; + skb->nh.raw=skb->data; + + + if (dev->flags & IFF_RUNNING) + { + /* Count received bytes, add FCS and one flag */ + sp->ibytes+= skb->len + 3; + sp->ipkts++; + } + + if (skb->len <= PPP_HEADER_LEN) { + /* Too small packet, drop it. */ + if (sp->pp_flags & PP_DEBUG) + printk (KERN_DEBUG "%s: input packet is too small, %d bytes\n", + dev->name, skb->len); +drop: kfree_skb(skb); + return; + } + + /* Get PPP header. */ + h = (struct ppp_header *)skb->data; + skb_pull(skb,sizeof(struct ppp_header)); + + switch (h->address) { + default: /* Invalid PPP packet. */ +invalid: if (sp->pp_flags & PP_DEBUG) + printk (KERN_WARNING "%s: invalid input packet <0x%x 0x%x 0x%x>\n", + dev->name, + h->address, h->control, ntohs (h->protocol)); + goto drop; + case PPP_ALLSTATIONS: + if (h->control != PPP_UI) + goto invalid; + if (sp->pp_flags & PP_CISCO) { + if (sp->pp_flags & PP_DEBUG) + printk (KERN_WARNING "%s: PPP packet in Cisco mode <0x%x 0x%x 0x%x>\n", + dev->name, + h->address, h->control, ntohs (h->protocol)); + goto drop; + } + + switch (ntohs (h->protocol)) { + default: + if (sp->lcp.state == LCP_STATE_OPENED) + sppp_cp_send (sp, PPP_LCP, LCP_PROTO_REJ, + ++sp->pp_seq[IDX_LCP], skb->len + 2, + &h->protocol); + if (sp->pp_flags & PP_DEBUG) + printk (KERN_WARNING "%s: invalid input protocol <0x%x 0x%x 0x%x>\n", + dev->name, + h->address, h->control, ntohs (h->protocol)); + goto drop; + case PPP_LCP: + sppp_lcp_input (sp, skb); + kfree_skb(skb); + return; + case PPP_IPCP: + if (sp->lcp.state == LCP_STATE_OPENED) + sppp_ipcp_input (sp, skb); + else + printk(KERN_DEBUG "IPCP when still waiting LCP finish.\n"); + kfree_skb(skb); + return; + case PPP_IP: + if (sp->ipcp.state == IPCP_STATE_OPENED) { + if(sp->pp_flags&PP_DEBUG) + printk(KERN_DEBUG "Yow an IP frame.\n"); + skb->protocol=htons(ETH_P_IP); + skb->mac.raw=skb->data; + skb->nh.raw=skb->data; + netif_rx(skb); + return; + } + break; +#ifdef IPX + case PPP_IPX: + /* IPX IPXCP not implemented yet */ + if (sp->lcp.state == LCP_STATE_OPENED) { + skb->protocol=htons(ETH_P_IPX); + skb->mac.raw=skb->data; + skb->nh.raw=skb->data; + netif_rx(skb); + return; + } + break; +#endif + case PPP_PAP: + { + struct lcp_header * lcph = (struct lcp_header *)skb->data; + int len = skb->len; + + switch (lcph->type) { + + case PAP_REQ: + //Should not get here if peer. It is valid only for authenticator. + printk(KERN_INFO "%s: Error : Got PAP_REQ !!\n", dev->name); + break; + + case PAP_ACK: + skb->data[len] = '\0'; + //print the message in ack packet + printk(KERN_INFO "%s: Pap Ack: Remote Message : %s\n", dev->name, + &skb->data[sizeof(struct lcp_header) + sizeof(u8)]); + + //set LCP state to opened + sp->lcp.state = LCP_STATE_OPENED; + sppp_ipcp_open (sp); + break; + + case PAP_NAK: + skb->data[len] = '\0'; + //print the message in nak packet + printk(KERN_INFO "%s: Pap Nack: Remote Message : %s\n", dev->name, + &skb->data[sizeof(struct lcp_header) + sizeof(u8)]); + + //await LCP shutdown by authenticator + break; + + default: + printk(KERN_INFO "%s : Unknown PAP packet !!!\n", dev->name); + break; + } + } + + break; + + case PPP_CHAP: + sppp_chap_input(sp, skb); + break; + } + break; + case CISCO_MULTICAST: + case CISCO_UNICAST: + /* Don't check the control field here (RFC 1547). */ + if (! (sp->pp_flags & PP_CISCO)) { + if (sp->pp_flags & PP_DEBUG) + printk (KERN_WARNING "%s: Cisco packet in PPP mode <0x%x 0x%x 0x%x>\n", + dev->name, + h->address, h->control, ntohs (h->protocol)); + goto drop; + } + switch (ntohs (h->protocol)) { + default: + goto invalid; + case CISCO_KEEPALIVE: + sppp_cisco_input (sp, skb); + kfree_skb(skb); + return; +#ifdef CONFIG_INET + case ETH_P_IP: + skb->protocol=htons(ETH_P_IP); + skb->mac.raw=skb->data; + skb->nh.raw=skb->data; + netif_rx(skb); + return; +#endif +#ifdef CONFIG_IPX + case ETH_P_IPX: + skb->protocol=htons(ETH_P_IPX); + skb->mac.raw=skb->data; + skb->nh.raw=skb->data; + netif_rx(skb); + return; +#endif + } + break; + } + kfree_skb(skb); +} + +EXPORT_SYMBOL(wp_sppp_input); + + +/* + *--------------------------------------------------------------------------* + * * + * The CHAP implementation. * + * * + *--------------------------------------------------------------------------* + */ + +/* + * The authentication protocols don't employ a full-fledged state machine as + * the control protocols do, since they do have Open and Close events, but + * not Up and Down, nor are they explicitly terminated. Also, use of the + * authentication protocols may be different in both directions (this makes + * sense, think of a machine that never accepts incoming calls but only + * calls out, it doesn't require the called party to authenticate itself). + * + * Our state machine for the local authentication protocol (we are requesting + * the peer to authenticate) looks like: + * + * RCA- + * +--------------------------------------------+ + * V scn,tld| + * +--------+ Close +---------+ RCA+ + * | |<----------------------------------| |------+ + * +--->| Closed | TO* | Opened | sca | + * | | |-----+ +-------| |<-----+ + * | +--------+ irc | | +---------+ + * | ^ | | ^ + * | | | | | + * | | | | | + * | TO-| | | | + * | |tld TO+ V | | + * | | +------->+ | | + * | | | | | | + * | +--------+ V | | + * | | |<----+<--------------------+ | + * | | Req- | scr | + * | | Sent | | + * | | | | + * | +--------+ | + * | RCA- | | RCA+ | + * +------+ +------------------------------------------+ + * scn,tld sca,irc,ict,tlu + * + * + * with: + * + * Open: LCP reached authentication phase + * Close: LCP reached terminate phase + * + * RCA+: received reply (pap-req, chap-response), acceptable + * RCN: received reply (pap-req, chap-response), not acceptable + * TO+: timeout with restart counter >= 0 + * TO-: timeout with restart counter < 0 + * TO*: reschedule timeout for CHAP + * + * scr: send request packet (none for PAP, chap-challenge) + * sca: send ack packet (pap-ack, chap-success) + * scn: send nak packet (pap-nak, chap-failure) + * ict: initialize re-challenge timer (CHAP only) + * + * tlu: this-layer-up, LCP reaches network phase + * tld: this-layer-down, LCP enters terminate phase + * + * Note that in CHAP mode, after sending a new challenge, while the state + * automaton falls back into Req-Sent state, it doesn't signal a tld + * event to LCP, so LCP remains in network phase. Only after not getting + * any response (or after getting an unacceptable response), CHAP closes, + * causing LCP to enter terminate phase. + * + * With PAP, there is no initial request that can be sent. The peer is + * expected to send one based on the successful negotiation of PAP as + * the authentication protocol during the LCP option negotiation. + * + * Incoming authentication protocol requests (remote requests + * authentication, we are peer) don't employ a state machine at all, + * they are simply answered. Some peers [Ascend P50 firmware rev + * 4.50] react allergically when sending IPCP requests while they are + * still in authentication phase (thereby violating the standard that + * demands that these NCP packets are to be discarded), so we keep + * track of the peer demanding us to authenticate, and only proceed to + * phase network once we've seen a positive acknowledge for the + * authentication. + */ + +/* + * Handle incoming CHAP packets. + */ +static void +sppp_chap_input(struct sppp *sp, struct sk_buff *skb) +{ + STDDCL; + struct lcp_header *h; + int len;//, x; + u_char *value, *name, digest[AUTHKEYLEN], dsize; + int value_len, name_len; + struct wp_MD5Context ctx; + + //strcpy(sp->hisauth.name, "RYELLE_LINX"); + //strcpy(sp->hisauth.secret, "ryelle"); + + len = skb->len; + + if (len < 4) { + if (debug){ + printk(KERN_INFO "%s: chap invalid packet length: %d bytes\n", + dev->name, len); + } + return; + } + + h = (struct lcp_header *)skb->data; + + if (len > ntohs (h->len)) + len = ntohs (h->len); + + switch (h->type) { + /* challenge, failure and success are his authproto */ + case CHAP_CHALLENGE: + + value = 1 + (u_char*)(h+1); + value_len = value[-1]; + name = value + value_len; + name_len = len - value_len - 5; + + if (name_len < 0) { + if (debug){ + printk( KERN_INFO "%s: chap corrupted challenge <%s id=0x%x len=%d", + dev->name, + sppp_auth_type_name(PPP_CHAP, h->type), + h->ident, ntohs(h->len)); + + sppp_print_bytes((u_char*) (h+1), len-4); + printk(">\n"); + } + break; + } + + if (debug){ + printk(KERN_INFO + "%s: chap input <%s id=0x%x len=%d name=", + dev->name, + sppp_auth_type_name(PPP_CHAP, h->type), + h->ident, + ntohs(h->len)); + + sppp_print_string((char*) name, name_len); + + printk(" value-size=%d value=", value_len); + sppp_print_bytes(value, value_len); + printk(">\n"); + } + + /* Compute reply value. */ + wp_MD5Init(&ctx); + wp_MD5Update(&ctx, &h->ident, 1); + wp_MD5Update(&ctx, sp->myauth.secret, sppp_strnlen(sp->myauth.secret, AUTHKEYLEN)); + wp_MD5Update(&ctx, value, value_len); + wp_MD5Final(digest, &ctx); + dsize = sizeof digest; + + sppp_auth_send(sp, PPP_CHAP, CHAP_RESPONSE, h->ident, + sizeof dsize, (const char *)&dsize, + sizeof digest, digest, + (size_t)sppp_strnlen(sp->myauth.name, AUTHNAMELEN), + sp->myauth.name, + 0); + + break; + + case CHAP_SUCCESS: + + if (debug){ + printk(KERN_INFO "%s: chap success ", dev->name); + if (len > 4) { + printk(": "); + sppp_print_string((char*)(h + 1), len - 4); + } + printk("\n"); + } + + sp->pp_flags &= ~PP_NEEDAUTH; + + //set LCP state to opened + sp->lcp.state = LCP_STATE_OPENED; + sppp_ipcp_open (sp); + + break; + + case CHAP_FAILURE: + + if (debug){ + printk(KERN_INFO "%s: chap failure", dev->name); + if (len > 4) { + printk(": "); + sppp_print_string((char*)(h + 1), len - 4); + } + printk("\n"); + }else + printk(KERN_INFO "%s: chap failure\n", dev->name); + + /* await LCP shutdown by authenticator */ + break; + + /* response is my authproto */ + case CHAP_RESPONSE: + + printk(KERN_INFO "%s : CHAP_RESPONSE - not implemented yet.\n", + dev->name); + break; + + value = 1 + (u_char*)(h+1); + value_len = value[-1]; + name = value + value_len; + name_len = len - value_len - 5; + if (name_len < 0) { + if (debug) { + printk(KERN_INFO + SPP_FMT "chap corrupted response " + "<%s id=0x%x len=%d", + SPP_ARGS(dev), + sppp_auth_type_name(PPP_CHAP, h->type), + h->ident, ntohs(h->len)); + sppp_print_bytes((u_char*)(h+1), len-4); + printk(">\n"); + } + break; + } + if (h->ident != sp->confid[IDX_CHAP]) { + if (debug) + printk(KERN_INFO SPP_FMT "chap dropping response for old ID " + "(got %d, expected %d)\n", + SPP_ARGS(dev), + h->ident, sp->confid[IDX_CHAP]); + break; + } + if (name_len != sppp_strnlen(sp->hisauth.name, AUTHNAMELEN) + || memcmp(name, sp->hisauth.name, name_len) != 0) { + printk( KERN_INFO SPP_FMT "chap response, his name ", + SPP_ARGS(dev)); + sppp_print_string(name, name_len); + printk(" != expected "); + sppp_print_string(sp->hisauth.name, + sppp_strnlen(sp->hisauth.name, AUTHNAMELEN)); + printk("\n"); + } + if (debug) { + printk( KERN_INFO SPP_FMT "chap input(%s) " + "<%s id=0x%x len=%d name=", + SPP_ARGS(dev), + sppp_state_name(sp->state[IDX_CHAP]), + sppp_auth_type_name(PPP_CHAP, h->type), + h->ident, ntohs (h->len)); + sppp_print_string((char*)name, name_len); + printk(" value-size=%d value=", value_len); + sppp_print_bytes(value, value_len); + printk(">\n"); + } + if (value_len != AUTHKEYLEN) { + if (debug) + printk( KERN_INFO SPP_FMT "chap bad hash value length: " + "%d bytes, should be %d\n", + SPP_ARGS(dev), value_len, + AUTHKEYLEN); + break; + } + + wp_MD5Init(&ctx); + wp_MD5Update(&ctx, &h->ident, 1); + wp_MD5Update(&ctx, sp->hisauth.secret, + sppp_strnlen(sp->hisauth.secret, AUTHKEYLEN)); + wp_MD5Update(&ctx, sp->myauth.challenge, AUTHKEYLEN); + wp_MD5Final(digest, &ctx); + +#define FAILMSG "Failed..." +#define SUCCMSG "Welcome!" + + if (value_len != sizeof digest || + memcmp(digest, value, value_len) != 0) { + // action scn, tld + sppp_auth_send(sp, PPP_CHAP, CHAP_FAILURE, h->ident, + sizeof(FAILMSG) - 1, (u_char *)FAILMSG, + 0); + chap.tld(sp); + break; + } + // action sca, perhaps tlu + if (sp->state[IDX_CHAP] == STATE_REQ_SENT || + sp->state[IDX_CHAP] == STATE_OPENED) + sppp_auth_send(sp, PPP_CHAP, CHAP_SUCCESS, h->ident, + sizeof(SUCCMSG) - 1, (u_char *)SUCCMSG, + 0); + if (sp->state[IDX_CHAP] == STATE_REQ_SENT) { + sppp_cp_change_state(&chap, sp, STATE_OPENED); + chap.tlu(sp); + } + break; + + default: + printk(KERN_INFO "Unknown CHAP packet type !!\n"); + + /* Unknown CHAP packet type -- ignore. */ + + if (sp->pp_flags & PP_DEBUG){ + printk(KERN_INFO "%s: chap unknown input name, + h->type, h->ident, ntohs(h->len)); + + sppp_print_bytes((u_char*)(h+1), len-4); + + printk(">\n"); + } + + break; + + } +} + +/* + * Send a PAP or CHAP proto packet. + * + * Varadic function, each of the elements for the ellipsis is of type + * ``size_t mlen, const u_char *msg''. Processing will stop iff + * mlen == 0. + * NOTE: never declare variadic functions with types subject to type + * promotion (i.e. u_char). This is asking for big trouble depending + * on the architecture you are on... + */ + +static void +sppp_auth_send(struct sppp *sp, unsigned int protocol, unsigned int type, + unsigned int id, ...) +{ + struct net_device *dev = sp->pp_if; + + u8 * data_buf; + unsigned int len, mlen; + const char *msg; + va_list ap; + u_char *p; + + p = data_buf = kmalloc (MAX_AUTHENTICATE_PACKET_LEN, GFP_ATOMIC); + + if (data_buf == NULL){ + printk(KERN_INFO "%s: sppp_auth_send() : Failed to allocate memory !!\n", + dev->name); + return; + } + + va_start(ap, id); + len = 0; + + while ((mlen = (unsigned int)va_arg(ap, size_t)) != 0) { + msg = va_arg(ap, const char *); + len += mlen; + + //???? + if (len > MAX_AUTHENTICATE_PACKET_LEN) { + printk(KERN_INFO "%s: sppp_auth_send() : Parameter array is too long !!\n", + dev->name); + va_end(ap); + kfree(data_buf); + return; + } + + memmove(p, msg, mlen); + p += mlen; + } + va_end(ap); + +#if 0 + if (sp->pp_flags & PP_DEBUG){ + printk(KERN_INFO "%s: %s output <%s id=0x%x len=%d", + dev->name, + (protocol == PPP_PAP ? "pap" : "chap"), + sppp_auth_type_name(protocol, type), + id, len); + + sppp_print_bytes((u_char*) (data_buf), len); + printk(">\n"); + } +#endif + sppp_cp_send (sp, protocol, type, id, len, data_buf); + kfree(data_buf); +} + +static const char * +sppp_auth_type_name(u_short proto, u_char type) +{ + static char buf[12]; + switch (proto) { + case PPP_CHAP: + switch (type) { + case CHAP_CHALLENGE: return "challenge"; + case CHAP_RESPONSE: return "response"; + case CHAP_SUCCESS: return "success"; + case CHAP_FAILURE: return "failure"; + } + case PPP_PAP: + switch (type) { + case PAP_REQ: return "req"; + case PAP_ACK: return "ack"; + case PAP_NAK: return "nak"; + } + } + + snprintf (buf, sizeof(buf), "auth/0x%x", type); + return buf; +} + +static void +sppp_print_string(const char *p, u_short len) +{ + u_char c; + + while (len-- > 0) { + c = *p++; + /* + * Print only ASCII chars directly. RFC 1994 recommends + * using only them, but we don't rely on it. */ + if (c < ' ' || c > '~') + printk( "\\x%x", c); + else + printk( "%c", c); + } +} + +static void +sppp_chap_init(struct sppp *sp) +{ + /* Chap doesn't have STATE_INITIAL at all. */ + sp->state[IDX_CHAP] = STATE_CLOSED; + sp->fail_counter[IDX_CHAP] = 0; + sp->pp_seq[IDX_CHAP] = 0; + sp->pp_rseq[IDX_CHAP] = 0; +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 + callout_handle_init(&sp->ch[IDX_CHAP]); +#endif +} + +static void +sppp_chap_open(struct sppp *sp) +{ + printk(KERN_INFO "sppp_chap_open()\n"); + + if (sp->myauth.proto == PPP_CHAP && + (sp->lcp.opts & (1 << LCP_OPT_AUTH_PROTO)) != 0) { + /* we are authenticator for CHAP, start it */ + chap.scr(sp); + sp->rst_counter[IDX_CHAP] = sp->lcp.max_configure; + sppp_cp_change_state(&chap, sp, STATE_REQ_SENT); + } + /* nothing to be done if we are peer, await a challenge */ +} + +static void +sppp_chap_close(struct sppp *sp) +{ + printk(KERN_INFO "sppp_chap_close()\n"); + + if (sp->state[IDX_CHAP] != STATE_CLOSED) + sppp_cp_change_state(&chap, sp, STATE_CLOSED); +} + +static void +sppp_chap_TO(void *cookie) +{ + struct sppp *sp = (struct sppp *)cookie; + STDDCL; + unsigned long flags; + + printk(KERN_INFO "sppp_chap_TO()\n"); + + wan_spin_lock_irq(&authenticate_lock,&flags); + + if (debug) + printk(KERN_INFO SPP_FMT "chap TO(%s) rst_counter = %d\n", + SPP_ARGS(dev), + sppp_state_name(sp->state[IDX_CHAP]), + sp->rst_counter[IDX_CHAP]); + + if (--sp->rst_counter[IDX_CHAP] < 0) + /* TO- event */ + switch (sp->state[IDX_CHAP]) { + case STATE_REQ_SENT: + chap.tld(sp); + sppp_cp_change_state(&chap, sp, STATE_CLOSED); + break; + } + else + /* TO+ (or TO*) event */ + switch (sp->state[IDX_CHAP]) { + case STATE_OPENED: + /* TO* event */ + sp->rst_counter[IDX_CHAP] = sp->lcp.max_configure; + /* FALLTHROUGH */ + case STATE_REQ_SENT: + chap.scr(sp); + /* sppp_cp_change_state() will restart the timer */ + sppp_cp_change_state(&chap, sp, STATE_REQ_SENT); + break; + } + + wan_spin_unlock_irq(&authenticate_lock,&flags); +} + +static void +sppp_chap_tlu(struct sppp *sp) +{ + STDDCL; + int i; + unsigned long flags; + + printk(KERN_INFO "sppp_chap_tlu()\n"); + + i = 0; + sp->rst_counter[IDX_CHAP] = sp->lcp.max_configure; + + /* + * Some broken CHAP implementations (Conware CoNet, firmware + * 4.0.?) don't want to re-authenticate their CHAP once the + * initial challenge-response exchange has taken place. + * Provide for an option to avoid rechallenges. + */ + if ((sp->hisauth.flags & AUTHFLAG_NORECHALLENGE) == 0) { + /* + * Compute the re-challenge timeout. This will yield + * a number between 300 and 810 seconds. + */ + //i = 300 + ((unsigned)(random() & 0xff00) >> 7); + i = 300;// + ((jiffies & 0x0000ff00) >> 7); + TIMEOUT(chap.TO, (void *)sp, i); + + } + + if (debug) { + printk( KERN_INFO SPP_FMT "chap %s, ", + SPP_ARGS(dev), + sp->pp_phase == PHASE_NETWORK? "reconfirmed": "tlu"); + + if ((sp->hisauth.flags & AUTHFLAG_NORECHALLENGE) == 0) + printk(KERN_INFO "next re-challenge in %d seconds\n", i); + else + printk(KERN_INFO "re-challenging supressed\n"); + } + + wan_spin_lock_irq(&authenticate_lock,&flags); + + /* indicate to LCP that we need to be closed down */ + sp->lcp.protos |= (1 << IDX_CHAP); + + if (sp->pp_flags & PP_NEEDAUTH) { + /* + * Remote is authenticator, but his auth proto didn't + * complete yet. Defer the transition to network + * phase. + */ + + wan_spin_unlock_irq(&authenticate_lock,&flags); + return; + } + + wan_spin_unlock_irq(&authenticate_lock,&flags); + + /* + * If we are already in phase network, we are done here. This + * is the case if this is a dummy tlu event after a re-challenge. + */ + if (sp->pp_phase != PHASE_NETWORK) + sppp_phase_network(sp); +} + +static void +sppp_chap_tld(struct sppp *sp) +{ + STDDCL; + + if (debug) + printk(KERN_INFO SPP_FMT "chap tld\n", SPP_ARGS(dev)); + UNTIMEOUT( (void *)sp ); + sp->lcp.protos &= ~(1 << IDX_CHAP); + + //lcp.Close(sp); + + //???? + /* Shut down the PPP link. */ + sp->lcp.magic = jiffies; + sp->lcp.state = LCP_STATE_CLOSED; + sp->ipcp.state = IPCP_STATE_CLOSED; + //sppp_clear_timeout (sp); + /* Initiate negotiation. */ + sppp_lcp_open (sp); +} + +static void +sppp_chap_scr(struct sppp *sp) +{ + u_long *ch, seed; + u_char clen; + + printk(KERN_INFO "sppp_chap_scr()\n"); + + /* Compute random challenge. */ + ch = (u_long *)sp->myauth.challenge; + +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 + read_random(&seed, sizeof seed); +#else + { + //struct timeval tv; + //microtime(&tv); + //seed = tv.tv_sec ^ tv.tv_usec; + seed = jiffies; + } +#endif + ch[0] = jiffies & 0x000000ff;//seed ^ random(); + ch[1] = jiffies & 0x0000ff00;//seed ^ random(); + ch[2] = jiffies & 0x00ff0000;//seed ^ random(); + ch[3] = jiffies & 0xff000000;//seed ^ random(); + clen = AUTHKEYLEN; + + sp->confid[IDX_CHAP] = ++sp->pp_seq[IDX_CHAP]; + + sppp_auth_send(sp, PPP_CHAP, CHAP_CHALLENGE, sp->confid[IDX_CHAP], + sizeof clen, (const char *)&clen, + (size_t)AUTHKEYLEN, sp->myauth.challenge, + (size_t)sppp_strnlen(sp->myauth.name, AUTHNAMELEN), + sp->myauth.name, + 0); +} + +/* + * Change the state of a control protocol in the state automaton. + * Takes care of starting/stopping the restart timer. + */ +static void +sppp_cp_change_state(const struct cp *cp, struct sppp *sp, int newstate) +{ + sp->state[cp->protoidx] = newstate; + + UNTIMEOUT((void *)sp); + + switch (newstate) { + case STATE_INITIAL: + case STATE_STARTING: + case STATE_CLOSED: + case STATE_STOPPED: + case STATE_OPENED: + break; + case STATE_CLOSING: + case STATE_STOPPING: + case STATE_REQ_SENT: + case STATE_ACK_RCVD: + case STATE_ACK_SENT: + + TIMEOUT(cp->TO, (void *)sp, sp->lcp.timeout); + break; + } +} + + +/* a dummy, used to drop uninteresting events */ +static void +sppp_null(struct sppp *unused) +{ + printk(KERN_INFO "sppp_null()\n"); + //UNTIMEOUT( unused ); + /* do just nothing */ +} + +static void +sppp_phase_network(struct sppp *sp) +{ + STDDCL; + //int i; + //u32 mask; + + sp->pp_phase = PHASE_NETWORK; + + if (debug) + printk(KERN_INFO SPP_FMT "phase %s\n", SPP_ARGS(dev), + sppp_phase_name(sp->pp_phase)); + + /* Notify NCPs now. */ + //???????? + /* + for (i = 0; i < IDX_COUNT; i++) + if ((cps[i])->flags & CP_NCP) + (cps[i])->Open(sp); + */ + /* Send Up events to all NCPs. */ + //???????? + /* + for (i = 0, mask = 1; i < IDX_COUNT; i++, mask <<= 1) + if ((sp->lcp.protos & mask) && ((cps[i])->flags & CP_NCP)) + (cps[i])->Up(sp); + */ + /* if no NCP is starting, all this was in vain, close down */ + //sppp_lcp_check_and_close(sp); + + sp->ipcp.state = IPCP_STATE_CLOSED; + /* Initiate renegotiation. */ + sppp_ipcp_open (sp); +} + +/* + * Check the open NCPs, return true if at least one NCP is open. + */ +/* +static int +sppp_ncp_check(struct sppp *sp) +{ + int i, mask; + + //????? + for (i = 0, mask = 1; i < IDX_COUNT; i++, mask <<= 1) + if ((sp->lcp.protos & mask) && (cps[i])->flags & CP_NCP) + return 1; + return 0; + + +} +*/ + +/* + * Re-check the open NCPs and see if we should terminate the link. + * Called by the NCPs during their tlf action handling. + */ +/* +static void +sppp_lcp_check_and_close(struct sppp *sp) +{ + + if (sp->pp_phase < PHASE_NETWORK) + // don't bother, we are already going down + return; + + if (sppp_ncp_check(sp)) + return; + + lcp.Close(sp); +} +*/ + +static const char * +sppp_state_name(int state) +{ + switch (state) { + case STATE_INITIAL: return "initial"; + case STATE_STARTING: return "starting"; + case STATE_CLOSED: return "closed"; + case STATE_STOPPED: return "stopped"; + case STATE_CLOSING: return "closing"; + case STATE_STOPPING: return "stopping"; + case STATE_REQ_SENT: return "req-sent"; + case STATE_ACK_RCVD: return "ack-rcvd"; + case STATE_ACK_SENT: return "ack-sent"; + case STATE_OPENED: return "opened"; + } + return "illegal"; +} + +static const char * +sppp_phase_name(enum ppp_phase phase) +{ + switch (phase) { + case PHASE_DEAD: return "dead"; + case PHASE_ESTABLISH: return "establish"; + case PHASE_TERMINATE: return "terminate"; + case PHASE_AUTHENTICATE: return "authenticate"; + case PHASE_NETWORK: return "network"; + } + return "illegal"; +} + +//////////////////////////// + +/* + * Handle transmit packets. + */ + +static int sppp_hard_header(struct sk_buff *skb, struct net_device *dev, __u16 type, + void *daddr, void *saddr, unsigned int len) +{ + struct sppp *sp = (struct sppp *)sppp_of(dev); + struct ppp_header *h; + + WAN_ASSERT2((!sp),0); + + if (skb_headroom(skb) < sizeof(struct ppp_header)){ + DEBUG_EVENT("%s: Error in hard_header() headroom (%d) < ppp hdr (%d)\n", + dev->name, + skb_headroom(skb), + sizeof(struct ppp_header)); + return 0; + } + + skb_push(skb,sizeof(struct ppp_header)); + h=(struct ppp_header *)skb->data; + if(sp->pp_flags&PP_CISCO) + { + h->address = CISCO_UNICAST; + h->control = 0; + } + else + { + h->address = PPP_ALLSTATIONS; + h->control = PPP_UI; + } + if(sp->pp_flags & PP_CISCO) + { + h->protocol = htons(type); + } + else switch(type) + { + case ETH_P_IP: + h->protocol = htons(PPP_IP); + break; + case ETH_P_IPX: + h->protocol = htons(PPP_IPX); + break; + } + return sizeof(struct ppp_header); +} + +static int sppp_rebuild_header(struct sk_buff *skb) +{ + return 0; +} + +/* + * Send keepalive packets, every 10 seconds. + */ + +static void sppp_keepalive (unsigned long dummy) +{ + struct sppp *sp; + //unsigned long flags; + + //wan_spin_lock_irq(&spppq_lock, flags); + + for (sp=spppq; sp; sp=sp->pp_next) + { + struct net_device *dev = sp->pp_if; + + /* Keepalive mode disabled or channel down? */ + if (! (sp->pp_flags & PP_KEEPALIVE) || + ! (dev->flags & IFF_UP)) + continue; + + /* No keepalive in PPP mode if LCP not opened yet. */ + if (! (sp->pp_flags & PP_CISCO) && + sp->lcp.state != LCP_STATE_OPENED) + continue; + + if (sp->pp_alivecnt == sppp_max_keepalive_count) { + /* No keepalive packets got. Stop the interface. */ + printk (KERN_WARNING "%s: protocol down\n", dev->name); + if_down (dev); + if (! (sp->pp_flags & PP_CISCO)) { + /* Shut down the PPP link. */ + sp->lcp.magic = jiffies; + sp->lcp.state = LCP_STATE_CLOSED; + sp->ipcp.state = IPCP_STATE_CLOSED; + sppp_clear_timeout (sp); + /* Initiate negotiation. */ + sppp_lcp_open (sp); + } + } + if (sp->pp_alivecnt <= sppp_max_keepalive_count) + ++sp->pp_alivecnt; + if (sp->pp_flags & PP_CISCO) + sppp_cisco_send (sp, CISCO_KEEPALIVE_REQ, ++sp->pp_seq[IDX_LCP], + sp->pp_rseq[IDX_LCP]); + else if (sp->lcp.state == LCP_STATE_OPENED) { + long nmagic = htonl (sp->lcp.magic); + sp->lcp.echoid = ++sp->pp_seq[IDX_LCP]; + sppp_cp_send (sp, PPP_LCP, LCP_ECHO_REQ, + sp->lcp.echoid, 4, &nmagic); + } + } + //wan_spin_unlock_irq(&spppq_lock, &flags); + sppp_keepalive_timer.expires=jiffies+sppp_keepalive_interval*HZ; + add_timer(&sppp_keepalive_timer); +} + +/* + * Handle incoming PPP Link Control Protocol packets. + */ + +static void sppp_lcp_input (struct sppp *sp, struct sk_buff *skb) +{ + struct lcp_header *h; + struct net_device *dev = sp->pp_if; + int len = skb->len; + u8 *p, opt[6]; + u32 rmagic; + int rc_from_lcp_options = 0; + + if (len < 4) { + if (sp->pp_flags & PP_DEBUG) + printk (KERN_WARNING "%s: invalid lcp packet length: %d bytes\n", + dev->name, len); + return; + } + h = (struct lcp_header *)skb->data; + skb_pull(skb,sizeof(struct lcp_header *)); + + if (sp->pp_flags & PP_DEBUG) + { + char state = '?'; + switch (sp->lcp.state) { + case LCP_STATE_CLOSED: state = 'C'; break; + case LCP_STATE_ACK_RCVD: state = 'R'; break; + case LCP_STATE_ACK_SENT: state = 'S'; break; + case LCP_STATE_OPENED: state = 'O'; break; + } + printk (KERN_WARNING "%s: lcp input(%c): %d bytes <%s id=%xh len=%xh", + dev->name, state, len, + sppp_lcp_type_name (h->type), h->ident, ntohs (h->len)); + if (len > 4) + sppp_print_bytes ((u8*) (h+1), len-4); + printk (">\n"); + } + + if (len > ntohs (h->len)) + len = ntohs (h->len); + switch (h->type) { + default: + /* Unknown packet type -- send Code-Reject packet. */ + sppp_cp_send (sp, PPP_LCP, LCP_CODE_REJ, ++sp->pp_seq[IDX_LCP], + skb->len, h); + break; + case LCP_CONF_REQ: + + if (len < 4) { + if (sp->pp_flags & PP_DEBUG) + printk (KERN_DEBUG"%s: invalid lcp configure request packet length: %d bytes\n", + dev->name, len); + break; + } + + rc_from_lcp_options = sppp_lcp_conf_parse_options (sp, h, len, &rmagic); + + if (len>4 && !rc_from_lcp_options) + goto badreq; + + if (rmagic == sp->lcp.magic) { + /* Local and remote magics equal -- loopback? */ + if (sp->pp_loopcnt >= sppp_max_keepalive_count*5) { + printk (KERN_WARNING "%s: loopback\n", + dev->name); + sp->pp_loopcnt = 0; + if (dev->flags & IFF_UP) { + if_down (dev); + } + } else if (sp->pp_flags & PP_DEBUG) + printk (KERN_DEBUG "%s: conf req: magic glitch\n", + dev->name); + ++sp->pp_loopcnt; + + /* MUST send Conf-Nack packet. */ + rmagic = ~sp->lcp.magic; + opt[0] = LCP_OPT_MAGIC; + opt[1] = sizeof (opt); + opt[2] = rmagic >> 24; + opt[3] = rmagic >> 16; + opt[4] = rmagic >> 8; + opt[5] = rmagic; + sppp_cp_send (sp, PPP_LCP, LCP_CONF_NAK, + h->ident, sizeof (opt), &opt); +badreq: + switch (sp->lcp.state) { + case LCP_STATE_OPENED: + /* Initiate renegotiation. */ + sppp_lcp_open (sp); + /* fall through... */ + case LCP_STATE_ACK_SENT: + /* Go to closed state. */ + sp->lcp.state = LCP_STATE_CLOSED; + sp->ipcp.state = IPCP_STATE_CLOSED; + } + break; + } + /* Send Configure-Ack packet. */ + sp->pp_loopcnt = 0; + + if (sp->lcp.state != LCP_STATE_OPENED) { + sppp_cp_send (sp, PPP_LCP, LCP_CONF_ACK, h->ident, len-4, h+1); + } + + //AFTER the ack send PAP request + //Wait until LCP is finished +#if 0 + if(rc_from_lcp_options == PPP_PAP){ + + //authenticator wants PAP. initiate PAP request. + sp->confid[IDX_PAP] = h->ident; + sppp_pap_scr(sp); + break; + } +#endif + //NC. Kernel change + //sppp_cp_send (sp, PPP_LCP, LCP_CONF_ACK, + // h->ident, len-4, h+1); + + /* Change the state. */ + switch (sp->lcp.state) { + case LCP_STATE_CLOSED: + sp->lcp.state = LCP_STATE_ACK_SENT; + break; + case LCP_STATE_ACK_RCVD: + sp->lcp.state = LCP_STATE_OPENED; + + /* 3/20/2006 CXH begin */ + if(sp->pp_flags & PP_NEEDAUTH){ + //authenticator wants PAP. initiate PAP request. + sp->confid[IDX_PAP] = h->ident; + sppp_pap_scr(sp); + + /* we don't want to continue to wpsppp_ipcp_open() + * yet, PAP_ACK will do it for us */ + break; + } + /* CXH end */ + + sppp_ipcp_open (sp); + break; + case LCP_STATE_OPENED: + /* Remote magic changed -- close session. */ + sp->lcp.state = LCP_STATE_CLOSED; + sp->ipcp.state = IPCP_STATE_CLOSED; + /* Initiate renegotiation. */ + sppp_lcp_open (sp); + + /* Send ACK after our REQ in attempt to break loop */ + sppp_cp_send (sp, PPP_LCP, LCP_CONF_ACK, + h->ident, len-4, h+1); + sp->lcp.state = LCP_STATE_ACK_SENT; + break; + } + break; + case LCP_CONF_ACK: + + if (h->ident != sp->lcp.confid) + break; + sppp_clear_timeout (sp); + + if ((sp->pp_link_state != SPPP_LINK_UP) && + (dev->flags & IFF_UP)) { + /* Coming out of loopback mode. */ + sp->pp_link_state=SPPP_LINK_UP; + printk (KERN_INFO "%s: protocol up\n", dev->name); + } + + switch (sp->lcp.state) { + case LCP_STATE_CLOSED: + sp->lcp.state = LCP_STATE_ACK_RCVD; + sppp_set_timeout (sp, 5); + break; + case LCP_STATE_ACK_SENT: + sp->lcp.state = LCP_STATE_OPENED; + + /* 3/20/2006 CXH begin */ + if(sp->pp_flags & PP_NEEDAUTH){ + //authenticator wants PAP. initiate PAP request. + sp->confid[IDX_PAP] = h->ident; + sppp_pap_scr(sp); + + /* we don't want to continue to wpsppp_ipcp_open() + * yet, PAP_ACK will do it for us */ + break; + } + /* CXH end */ + + sppp_ipcp_open (sp); + break; + } + break; + case LCP_CONF_NAK: + if (h->ident != sp->lcp.confid) + break; + p = (u8*) (h+1); + if (len>=10 && p[0] == LCP_OPT_MAGIC && p[1] >= 4) { + rmagic = (u32)p[2] << 24 | + (u32)p[3] << 16 | p[4] << 8 | p[5]; + if (rmagic == ~sp->lcp.magic) { + int newmagic; + if (sp->pp_flags & PP_DEBUG) + printk (KERN_DEBUG "%s: conf nak: magic glitch\n", + dev->name); + get_random_bytes(&newmagic, sizeof(newmagic)); + sp->lcp.magic += newmagic; + } else + sp->lcp.magic = rmagic; + } + if (sp->lcp.state != LCP_STATE_ACK_SENT) { + /* Go to closed state. */ + sp->lcp.state = LCP_STATE_CLOSED; + sp->ipcp.state = IPCP_STATE_CLOSED; + } + /* The link will be renegotiated after timeout, + * to avoid endless req-nack loop. */ + sppp_clear_timeout (sp); + sppp_set_timeout (sp, 2); + break; + case LCP_CONF_REJ: + if (h->ident != sp->lcp.confid) + break; + sppp_clear_timeout (sp); + /* Initiate renegotiation. */ + sppp_lcp_open (sp); + if (sp->lcp.state != LCP_STATE_ACK_SENT) { + /* Go to closed state. */ + sp->lcp.state = LCP_STATE_CLOSED; + sp->ipcp.state = IPCP_STATE_CLOSED; + } + break; + case LCP_TERM_REQ: + sppp_clear_timeout (sp); + /* Send Terminate-Ack packet. */ + sppp_cp_send (sp, PPP_LCP, LCP_TERM_ACK, h->ident, 0, 0); + /* Go to closed state. */ + sp->lcp.state = LCP_STATE_CLOSED; + sp->ipcp.state = IPCP_STATE_CLOSED; + + /* Added by Nenad Corbic + * The Link should go down if LCP_TERM_REQ is + * received. */ + if (sp->pp_link_state){ + printk (KERN_INFO "%s: protocol down\n", dev->name); + if_down(dev); + } + + /* Initiate renegotiation. */ + sppp_lcp_open (sp); + break; + case LCP_TERM_ACK: + case LCP_CODE_REJ: + case LCP_PROTO_REJ: + /* Ignore for now. */ + break; + case LCP_DISC_REQ: + /* Discard the packet. */ + break; + case LCP_ECHO_REQ: + if (sp->lcp.state != LCP_STATE_OPENED) + break; + if (len < 8) { + if (sp->pp_flags & PP_DEBUG) + printk (KERN_WARNING "%s: invalid lcp echo request packet length: %d bytes\n", + dev->name, len); + break; + } + if (ntohl (*(long*)(h+1)) == sp->lcp.magic) { + /* Line loopback mode detected. */ + printk (KERN_WARNING "%s: loopback\n", dev->name); + if_down (dev); + + /* Shut down the PPP link. */ + sp->lcp.state = LCP_STATE_CLOSED; + sp->ipcp.state = IPCP_STATE_CLOSED; + sppp_clear_timeout (sp); + /* Initiate negotiation. */ + sppp_lcp_open (sp); + break; + } + *(long*)(h+1) = htonl (sp->lcp.magic); + sppp_cp_send (sp, PPP_LCP, LCP_ECHO_REPLY, h->ident, len-4, h+1); + break; + case LCP_ECHO_REPLY: + if (h->ident != sp->lcp.echoid) + break; + if (len < 8) { + if (sp->pp_flags & PP_DEBUG) + printk (KERN_WARNING "%s: invalid lcp echo reply packet length: %d bytes\n", + dev->name, len); + break; + } + if (ntohl (*(long*)(h+1)) != sp->lcp.magic) + sp->pp_alivecnt = 0; + break; + } +} + + +static void sppp_pap_scr(struct sppp *sp) +{ + u_char idlen, pwdlen; + + //sp->confid[IDX_PAP] = ++sp->pp_seq[IDX_PAP]; + pwdlen = sppp_strnlen(sp->myauth.secret, AUTHKEYLEN); + idlen = sppp_strnlen(sp->myauth.name, AUTHNAMELEN); + + sppp_auth_send(sp, PPP_PAP, PAP_REQ, sp->confid[IDX_PAP], + sizeof idlen, (const char *)&idlen, + (size_t)idlen, sp->myauth.name, + sizeof pwdlen, (const char *)&pwdlen, + (size_t)pwdlen, sp->myauth.secret, + 0); +} + +static int +sppp_strnlen(u_char *p, int max) +{ + int len; + + for (len = 0; len < max && *p; ++p) + ++len; + return len; +} + + +/* + * Handle incoming Cisco keepalive protocol packets. + */ + +static void sppp_cisco_input (struct sppp *sp, struct sk_buff *skb) +{ + struct cisco_packet *h; + struct net_device *dev = sp->pp_if; + + if (skb->len != CISCO_PACKET_LEN && skb->len != CISCO_BIG_PACKET_LEN) { + if (sp->pp_flags & PP_DEBUG) + printk (KERN_WARNING "%s: invalid cisco packet length: %d bytes\n", + dev->name, skb->len); + return; + } + h = (struct cisco_packet *)skb->data; + skb_pull(skb, sizeof(struct cisco_packet*)); + if (sp->pp_flags & PP_DEBUG) + printk (KERN_WARNING "%s: cisco input: %d bytes <%xh %xh %xh %xh %xh-%xh>\n", + dev->name, skb->len, + ntohl (h->type), h->par1, h->par2, h->rel, + h->time0, h->time1); + switch (ntohl (h->type)) { + default: + if (sp->pp_flags & PP_DEBUG) + printk (KERN_WARNING "%s: unknown cisco packet type: 0x%x\n", + dev->name, ntohl (h->type)); + break; + case CISCO_ADDR_REPLY: + /* Reply on address request, ignore */ + break; + case CISCO_KEEPALIVE_REQ: + sp->pp_alivecnt = 0; + sp->pp_rseq[IDX_LCP] = ntohl (h->par1); + if (sp->pp_seq[IDX_LCP] == sp->pp_rseq[IDX_LCP]) { + /* Local and remote sequence numbers are equal. + * Probably, the line is in loopback mode. */ + int newseq; + if (sp->pp_loopcnt >= sppp_max_keepalive_count) { + printk (KERN_WARNING "%s: loopback\n", + dev->name); + sp->pp_loopcnt = 0; + if (dev->flags & IFF_UP) { + if_down (dev); + } + } + ++sp->pp_loopcnt; + + /* Generate new local sequence number */ + get_random_bytes(&newseq, sizeof(newseq)); + sp->pp_seq[IDX_LCP] ^= newseq; + break; + } + sp->pp_loopcnt = 0; + if (sp->pp_link_state==SPPP_LINK_DOWN && + (dev->flags & IFF_UP)) { + sp->pp_link_state=SPPP_LINK_UP; + printk (KERN_INFO "%s: protocol up\n", dev->name); + } + break; + case CISCO_ADDR_REQ: + /* Stolen from net/ipv4/devinet.c -- SIOCGIFADDR ioctl */ + { + struct in_device *in_dev; + struct in_ifaddr *ifa; + u32 addr = 0, mask = ~0; /* FIXME: is the mask correct? */ +#ifdef CONFIG_INET + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) + if ((in_dev=in_dev_get(dev)) != NULL) + { + wp_rcu_read_lock(in_dev); + for (ifa=in_dev->ifa_list; ifa != NULL; + ifa=ifa->ifa_next) { + if (strcmp(dev->name, ifa->ifa_label) == 0) + { + addr = ifa->ifa_local; + mask = ifa->ifa_mask; + break; + } + } + wp_rcu_read_unlock(in_dev); + in_dev_put(in_dev); + } +#else + if ((in_dev=dev->ip_ptr) != NULL) + { + for (ifa=in_dev->ifa_list; ifa != NULL; + ifa=ifa->ifa_next) + if (strcmp(dev->name, ifa->ifa_label) == 0) + { + addr = ifa->ifa_local; + mask = ifa->ifa_mask; + break; + } + } +#endif + +#endif + /* I hope both addr and mask are in the net order */ + sppp_cisco_send (sp, CISCO_ADDR_REPLY, addr, mask); + break; + } + } +} + +/* + * Send PPP LCP packet. + */ +static void sppp_cp_send (struct sppp *sp, u16 proto, u8 type, + u8 ident, u16 len, void *data) +{ + struct ppp_header *h; + struct lcp_header *lh; + struct sk_buff *skb; + struct net_device *dev = sp->pp_if; + + skb=alloc_skb(dev->hard_header_len+PPP_HEADER_LEN+LCP_HEADER_LEN+len, + GFP_ATOMIC); + if (skb==NULL) + return; + + skb_reserve(skb,dev->hard_header_len); + + h = (struct ppp_header *)skb_put(skb, sizeof(struct ppp_header)); + h->address = PPP_ALLSTATIONS; /* broadcast address */ + h->control = PPP_UI; /* Unnumbered Info */ + h->protocol = htons (proto); /* Link Control Protocol */ + + lh = (struct lcp_header *)skb_put(skb, sizeof(struct lcp_header)); + lh->type = type; + lh->ident = ident; + lh->len = htons (LCP_HEADER_LEN + len); + + if (len) + memcpy(skb_put(skb,len),data, len); + + if (sp->pp_flags & PP_DEBUG) { + + switch (proto){ + + case PPP_PAP: + case PPP_CHAP: + printk(KERN_INFO "%s: %s output <%s id=0x%x len=%d", + dev->name, + (proto == PPP_PAP ? "pap" : "chap"), + sppp_auth_type_name(proto, type), + lh->ident, len); + break; + + default: + printk (KERN_INFO "%s: %s output <%s id=%xh len=%xh", + dev->name, + proto==PPP_LCP ? "lcp" : "ipcp", + proto==PPP_LCP ? sppp_lcp_type_name (lh->type) : + sppp_ipcp_type_name (lh->type), lh->ident, + ntohs (lh->len)); + + break; + } + + if (len) + sppp_print_bytes ((u8*) (lh+1), len); + printk (">\n"); + } + sp->obytes += skb->len; + + /* Control is high priority so it doesnt get queued behind data */ + skb->priority=TC_PRIO_CONTROL; + skb->dev = dev; + skb->protocol = htons(PPP_IP); + skb->mac.raw=skb->data; + skb->nh.raw=skb->data; + dev_queue_xmit(skb); +} + +/* + * Send Cisco keepalive packet. + */ + +static void sppp_cisco_send (struct sppp *sp, int type, long par1, long par2) +{ + struct ppp_header *h; + struct cisco_packet *ch; + struct sk_buff *skb; + struct net_device *dev = sp->pp_if; + u32 t = jiffies * 1000/HZ; + + skb=alloc_skb(dev->hard_header_len+PPP_HEADER_LEN+CISCO_PACKET_LEN, + GFP_ATOMIC); + + if(skb==NULL) + return; + + skb_reserve(skb, dev->hard_header_len); + h = (struct ppp_header *)skb_put (skb, sizeof(struct ppp_header)); + h->address = CISCO_MULTICAST; + h->control = 0; + h->protocol = htons (CISCO_KEEPALIVE); + + ch = (struct cisco_packet*)skb_put(skb, CISCO_PACKET_LEN); + ch->type = htonl (type); + ch->par1 = htonl (par1); + ch->par2 = htonl (par2); + ch->rel = -1; + ch->time0 = htons ((u16) (t >> 16)); + ch->time1 = htons ((u16) t); + + if (sp->pp_flags & PP_DEBUG) + printk (KERN_WARNING "%s: cisco output: <%xh %xh %xh %xh %xh-%xh>\n", + dev->name, ntohl (ch->type), ch->par1, + ch->par2, ch->rel, ch->time0, ch->time1); + sp->obytes += skb->len; + skb->priority=TC_PRIO_CONTROL; + skb->dev = dev; + skb->mac.raw=skb->data; + skb->nh.raw=skb->data; + dev_queue_xmit(skb); +} + +/** + * wp_sppp_close - close down a synchronous PPP or Cisco HDLC link + * @dev: The network device to drop the link of + * + * This drops the logical interface to the channel. It is not + * done politely as we assume we will also be dropping DTR. Any + * timeouts are killed. + */ + +int wp_sppp_close (struct net_device *dev) +{ + struct sppp *sp = (struct sppp *)sppp_of(dev); + + WAN_ASSERT2((!sp),-ENODEV); + + sp->pp_link_state = SPPP_LINK_DOWN; + sp->lcp.state = LCP_STATE_CLOSED; + sp->ipcp.state = IPCP_STATE_CLOSED; + sppp_clear_timeout (sp); + auth_clear_timeout(sp); + + return 0; +} + +EXPORT_SYMBOL(wp_sppp_close); + +/** + * wp_sppp_open - open a synchronous PPP or Cisco HDLC link + * @dev: Network device to activate + * + * Close down any existing synchronous session and commence + * from scratch. In the PPP case this means negotiating LCP/IPCP + * and friends, while for Cisco HDLC we simply need to start sending + * keepalives + */ + +int wp_sppp_open (struct net_device *dev) +{ + struct sppp *sp = (struct sppp *)sppp_of(dev); + + WAN_ASSERT2((!sp),-ENODEV); + + wp_sppp_close(dev); + if (!(sp->pp_flags & PP_CISCO)) { + sppp_lcp_open (sp); + } + sp->pp_link_state = SPPP_LINK_DOWN; + return 0; +} + +EXPORT_SYMBOL(wp_sppp_open); + +/** + * wp_sppp_reopen - notify of physical link loss + * @dev: Device that lost the link + * + * This function informs the synchronous protocol code that + * the underlying link died (for example a carrier drop on X.21) + * + * We increment the magic numbers to ensure that if the other end + * failed to notice we will correctly start a new session. It happens + * do to the nature of telco circuits is that you can lose carrier on + * one endonly. + * + * Having done this we go back to negotiating. This function may + * be called from an interrupt context. + */ + +int wp_sppp_reopen (struct net_device *dev) +{ + struct sppp *sp = (struct sppp *)sppp_of(dev); + + WAN_ASSERT2((!sp),-ENODEV); + + wp_sppp_close(dev); + if (!(sp->pp_flags & PP_CISCO)) + { + sp->lcp.magic = jiffies; + ++sp->pp_seq[IDX_LCP]; + sp->lcp.state = LCP_STATE_CLOSED; + sp->ipcp.state = IPCP_STATE_CLOSED; + /* Give it a moment for the line to settle then go */ + sppp_set_timeout (sp, 1); + } + sp->pp_link_state=SPPP_LINK_DOWN; + return 0; +} + +EXPORT_SYMBOL(wp_sppp_reopen); + +/** + * wp_sppp_change_mtu - Change the link MTU + * @dev: Device to change MTU on + * @new_mtu: New MTU + * + * Change the MTU on the link. This can only be called with + * the link down. It returns an error if the link is up or + * the mtu is out of range. + */ + +int wp_sppp_change_mtu(struct net_device *dev, int new_mtu) +{ + if(new_mtu<128||new_mtu>PPP_MTU||(dev->flags&IFF_UP)) + return -EINVAL; + dev->mtu=new_mtu; + return 0; +} + +EXPORT_SYMBOL(wp_sppp_change_mtu); + +/** + * wp_sppp_do_ioctl - Ioctl handler for ppp/hdlc + * @dev: Device subject to ioctl + * @ifr: Interface request block from the user + * @cmd: Command that is being issued + * + * This function handles the ioctls that may be issued by the user + * to control the settings of a PPP/HDLC link. It does both busy + * and security checks. This function is intended to be wrapped by + * callers who wish to add additional ioctl calls of their own. + */ + +int wp_sppp_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + struct sppp *sp = (struct sppp *)sppp_of(dev); + + WAN_ASSERT2((!sp),-ENODEV); + + if(dev->flags&IFF_UP) + return -EBUSY; + + if(!capable(CAP_NET_ADMIN)) + return -EPERM; + + switch(cmd) + { + case SPPPIOCCISCO: + sp->pp_flags|=PP_CISCO; + dev->type = ARPHRD_HDLC; + break; + case SPPPIOCPPP: + sp->pp_flags&=~PP_CISCO; + dev->type = ARPHRD_PPP; + break; + case SPPPIOCDEBUG: + sp->pp_flags&=~PP_DEBUG; + if(ifr->ifr_flags) + sp->pp_flags|=PP_DEBUG; + break; + case SPPPIOCGFLAGS: + if(copy_to_user(ifr->ifr_data, &sp->pp_flags, sizeof(sp->pp_flags))) + return -EFAULT; + break; + case SPPPIOCSFLAGS: + if(copy_from_user(&sp->pp_flags, ifr->ifr_data, sizeof(sp->pp_flags))) + return -EFAULT; + break; + + default: + return -EINVAL; + } + return 0; +} + +EXPORT_SYMBOL(wp_sppp_do_ioctl); + +/** + * wp_sppp_attach - attach synchronous PPP/HDLC to a device + * @pd: PPP device to initialise + * + * This initialises the PPP/HDLC support on an interface. At the + * time of calling the dev element must point to the network device + * that this interface is attached to. The interface should not yet + * be registered. + */ + +void wp_sppp_attach(struct ppp_device *pd) +{ + struct net_device *dev = pd->dev; + struct sppp *sp = &pd->sppp; + unsigned long flags; + + wan_spin_lock_irq(&spppq_lock, &flags); + /* Initialize keepalive handler. */ + if (! spppq) + { + init_timer(&sppp_keepalive_timer); + sppp_keepalive_timer.expires=jiffies+10*HZ; + sppp_keepalive_timer.function=sppp_keepalive; + add_timer(&sppp_keepalive_timer); + } + /* Insert new entry into the keepalive list. */ + sp->pp_next = spppq; + spppq = sp; + wan_spin_unlock_irq(&spppq_lock, &flags); + + sp->pp_loopcnt = 0; + sp->pp_alivecnt = 0; + + sp->pp_seq[IDX_LCP] = 0; + sp->pp_rseq[IDX_LCP] = 0; + sppp_chap_init(sp); + sp->pp_auth_flags = 0; + + sp->pp_flags = PP_KEEPALIVE|PP_CISCO|debug;/*PP_DEBUG;*/ + sp->lcp.magic = 0; + sp->lcp.state = LCP_STATE_CLOSED; + sp->ipcp.state = IPCP_STATE_CLOSED; + sp->pp_if = dev; + + if (sp->dynamic_ip){ + DEBUG_EVENT("%s: Dynamic IP Addressing Enabled!\n",dev->name); + }else{ + DEBUG_EVENT("%s: Dynamic IP Addressing Disabled!\n",dev->name); + } + + if (strlen(sp->hwdevname) > WAN_IFNAME_SZ || + strlen(sp->hwdevname) == 0){ + DEBUG_EVENT("%s: Warning: hwdevname not initialized!\n", + dev->name); + } + + sp->task_working=0; + sp->local_ip=0; + sp->remote_ip=0; + + INIT_WORK((&sp->sppp_task),sppp_bh,sp); + sp->task_working=0; + + /* + * Device specific setup. All but interrupt handler and + * hard_start_xmit. + */ + + dev->hard_header = sppp_hard_header; + dev->rebuild_header = sppp_rebuild_header; + dev->tx_queue_len = 100; + dev->type = ARPHRD_HDLC; + dev->addr_len = 0; + dev->hard_header_len = sizeof(struct ppp_header); + dev->mtu = PPP_MTU; + /* + * These 4 are callers but MUST also call sppp_ functions + */ + dev->do_ioctl = wp_sppp_do_ioctl; +#if 0 + dev->get_stats = NULL; /* Let the driver override these */ + dev->open = wp_sppp_open; + dev->stop = wp_sppp_close; +#endif + dev->change_mtu = wp_sppp_change_mtu; + dev->hard_header_cache = NULL; + dev->header_cache_update = NULL; + dev->flags = IFF_MULTICAST|IFF_POINTOPOINT|IFF_NOARP; + +#if 0 + dev_init_buffers(dev); /* Let the driver do this */ +#endif +} + +EXPORT_SYMBOL(wp_sppp_attach); + +/** + * wp_sppp_detach - release PPP resources from a device + * @dev: Network device to release + * + * Stop and free up any PPP/HDLC resources used by this + * interface. This must be called before the device is + * freed. + */ + +void wp_sppp_detach (struct net_device *dev) +{ + struct sppp **q, *p, *sp = (struct sppp *)sppp_of(dev); + unsigned long flags; + WAN_ASSERT1((!sp)); + + wan_spin_lock_irq(&spppq_lock, &flags); + /* Remove the entry from the keepalive list. */ + for (q = &spppq; (p = *q); q = &p->pp_next) + if (p == sp) { + *q = p->pp_next; + break; + } + + /* Stop keepalive handler. */ + if (! spppq) + del_timer(&sppp_keepalive_timer); + sppp_clear_timeout (sp); + auth_clear_timeout(sp); + wan_spin_unlock_irq(&spppq_lock, &flags); +} + +EXPORT_SYMBOL(wp_sppp_detach); + + +/* + * Analyze the LCP Configure-Request options list + * for the presence of unknown options. + * If the request contains unknown options, build and + * send Configure-reject packet, containing only unknown options. + */ +static int +sppp_lcp_conf_parse_options (struct sppp *sp, struct lcp_header *h, + int len, u32 *magic) +{ + u8 *buf, *r, *p; + int rlen = 0; + + u8 * packet_length, * chap_algorithm; + u16 authproto; + struct net_device *dev = sp->pp_if; + + len -= 4; //sizeof(struct lcp_header); + buf = r = kmalloc (len, GFP_ATOMIC); + if (! buf) + return (0); + + p = (void*) (h+1); + + //p[0] is type + //p[1] is length + + for (rlen=0; len>1 && p[1]; len-=p[1], p+=p[1]) { + switch (*p) { + case LCP_OPT_MAGIC: + /* Magic number -- extract. */ + if (len >= 6 && p[1] == 6) { + *magic = (u32)p[2] << 24 | + (u32)p[3] << 16 | p[4] << 8 | p[5]; + continue; + } + break; + case LCP_OPT_ASYNC_MAP: + /* Async control character map -- check to be zero. */ + if (len >= 6 && p[1] == 6 && ! p[2] && ! p[3] && + ! p[4] && ! p[5]) + continue; + break; + case LCP_OPT_MRU: + /* Maximum receive unit -- always OK. */ + continue; + + case LCP_OPT_AUTH_PROTO: + //request to authenticate + packet_length = p + 1; + + if (*packet_length < 4) { + printk(KERN_INFO "%s: LCP_OPT_AUTH_PROTO packet is too short (%d)!\n", + dev->name, *packet_length); + break; + } + + //got request to authenticate + if (sp->myauth.proto == 0) { + // we are not configured to do auth + printk(KERN_INFO + "%s: Got authentication request, but not configured to authenticate.\n", + dev->name); + break; + } + + authproto = ntohs(*(unsigned short *)(p + 2)); + //printk(KERN_INFO "authentication protocol : 0x%X\n", authproto); + + if (sp->myauth.proto != authproto) { + /* not agreed, nak */ + printk(KERN_INFO "%s: Authentication protocols mismatch! (mine : %s , his : %s )\n", + dev->name, + sppp_proto_name(sp->myauth.proto), + sppp_proto_name(authproto)); + break; + } + + /* + * Remote want us to authenticate, remember this, + * so we stay in PHASE_AUTHENTICATE after LCP got + * up. + */ + sp->pp_flags |= PP_NEEDAUTH; + + //if we configured for PAP -- ack it + if(authproto == PPP_PAP){ + + kfree(buf); + return PPP_PAP; + }else if(authproto == PPP_CHAP){ + + chap_algorithm = p + 4; + + if(*chap_algorithm == CHAP_MD5){ + + kfree(buf); + return 1;//return ok + }else{ + printk(KERN_INFO "Got request for unsupported CHAP algorithm : 0x%X.\ + Only MD5 is supported.\n", *chap_algorithm); + break; + } + }else{ + printk(KERN_INFO "Got request for unsupported authentication protocol : 0x%X\n", + authproto); + break; + } + + default: + /* Others not supported. */ + printk(KERN_INFO "unknown lcp option : 0x%X\n", *p); + break; + } + /* Add the option to rejected list. */ + memcpy(r, p, p[1]); + r += p[1]; + rlen += p[1]; + } + if (rlen) + sppp_cp_send (sp, PPP_LCP, LCP_CONF_REJ, h->ident, rlen, buf); + + kfree(buf); + return (rlen == 0); +} + +static const char * +sppp_proto_name(u_short proto) +{ + static char buf[12]; + switch (proto) { + case PPP_LCP: return "lcp"; + case PPP_IPCP: return "ipcp"; + case PPP_PAP: return "pap"; + case PPP_CHAP: return "chap"; + //case PPP_IPV6CP: return "ipv6cp"; + } + snprintf(buf, sizeof(buf), "proto/0x%x", (unsigned)proto); + return buf; +} + + +#ifdef WORDS_BIGENDIAN +void +byteSwap(UWORD32 *buf, unsigned words) +{ + md5byte *p = (md5byte *)buf; + + do { + *buf++ = (UWORD32)((unsigned)p[3] << 8 | p[2]) << 16 | + ((unsigned)p[1] << 8 | p[0]); + p += 4; + } while (--words); +} +#else +#define byteSwap(buf,words) +#endif + +/* + * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious + * initialization constants. + */ +void +wp_MD5Init(struct wp_MD5Context *ctx) +{ + ctx->buf[0] = 0x67452301; + ctx->buf[1] = 0xefcdab89; + ctx->buf[2] = 0x98badcfe; + ctx->buf[3] = 0x10325476; + + ctx->bytes[0] = 0; + ctx->bytes[1] = 0; +} + +/* + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +void +wp_MD5Update(struct wp_MD5Context *ctx, md5byte const *buf, unsigned len) +{ + UWORD32 t; + + /* Update byte count */ + + t = ctx->bytes[0]; + if ((ctx->bytes[0] = t + len) < t) + ctx->bytes[1]++; /* Carry from low to high */ + + t = 64 - (t & 0x3f); /* Space available in ctx->in (at least 1) */ + if (t > len) { + memcpy((md5byte *)ctx->in + 64 - t, buf, len); + return; + } + /* First chunk is an odd size */ + memcpy((md5byte *)ctx->in + 64 - t, buf, t); + byteSwap(ctx->in, 16); + wp_MD5Transform(ctx->buf, ctx->in); + buf += t; + len -= t; + + /* Process data in 64-byte chunks */ + while (len >= 64) { + memcpy(ctx->in, buf, 64); + byteSwap(ctx->in, 16); + wp_MD5Transform(ctx->buf, ctx->in); + buf += 64; + len -= 64; + } + + /* Handle any remaining bytes of data. */ + memcpy(ctx->in, buf, len); +} + +/* + * Final wrapup - pad to 64-byte boundary with the bit pattern + * 1 0* (64-bit count of bits processed, MSB-first) + */ +void +wp_MD5Final(md5byte digest[16], struct wp_MD5Context *ctx) +{ + int count = ctx->bytes[0] & 0x3f; /* Number of bytes in ctx->in */ + md5byte *p = (md5byte *)ctx->in + count; + + /* Set the first char of padding to 0x80. There is always room. */ + *p++ = 0x80; + + /* Bytes of padding needed to make 56 bytes (-8..55) */ + count = 56 - 1 - count; + + if (count < 0) { /* Padding forces an extra block */ + memset(p, 0, count + 8); + byteSwap(ctx->in, 16); + wp_MD5Transform(ctx->buf, ctx->in); + p = (md5byte *)ctx->in; + count = 56; + } + memset(p, 0, count); + byteSwap(ctx->in, 14); + + /* Append length in bits and transform */ + ctx->in[14] = ctx->bytes[0] << 3; + ctx->in[15] = ctx->bytes[1] << 3 | ctx->bytes[0] >> 29; + wp_MD5Transform(ctx->buf, ctx->in); + + byteSwap(ctx->buf, 4); + memcpy(digest, ctx->buf, 16); + memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */ +} + +#ifndef ASM_MD5 + +/* The four core functions - F1 is optimized somewhat */ + +/* #define F1(x, y, z) (x & y | ~x & z) */ +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +/* This is the central step in the MD5 algorithm. */ +#define wp_MD5STEP(f,w,x,y,z,in,s) \ + (w += f(x,y,z) + in, w = (w<>(32-s)) + x) + +/* + * The core of the MD5 algorithm, this alters an existing MD5 hash to + * reflect the addition of 16 longwords of new data. MD5Update blocks + * the data and converts bytes into longwords for this routine. + */ +void +wp_MD5Transform(UWORD32 buf[4], UWORD32 const in[16]) +{ + register UWORD32 a, b, c, d; + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + wp_MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); + wp_MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); + wp_MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); + wp_MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); + wp_MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); + wp_MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); + wp_MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); + wp_MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); + wp_MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); + wp_MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); + wp_MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); + wp_MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); + wp_MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); + wp_MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); + wp_MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); + wp_MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); + + wp_MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); + wp_MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); + wp_MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); + wp_MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); + wp_MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); + wp_MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); + wp_MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); + wp_MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); + wp_MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); + wp_MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); + wp_MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); + wp_MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); + wp_MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); + wp_MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); + wp_MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); + wp_MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); + + wp_MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); + wp_MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); + wp_MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); + wp_MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); + wp_MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); + wp_MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); + wp_MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); + wp_MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); + wp_MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); + wp_MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); + wp_MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); + wp_MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); + wp_MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); + wp_MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); + wp_MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); + wp_MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); + + wp_MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); + wp_MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); + wp_MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); + wp_MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); + wp_MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); + wp_MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); + wp_MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); + wp_MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); + wp_MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); + wp_MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); + wp_MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); + wp_MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); + wp_MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); + wp_MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); + wp_MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); + wp_MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} + +#endif + +static void sppp_ipcp_input (struct sppp *sp, struct sk_buff *skb) +{ + struct lcp_header *h; + struct ipcp_header *ipcp_h; + struct net_device *dev = sp->pp_if; + int len = skb->len; + unsigned int remote_ip, local_ip; + + if (len < 4) + { + if (sp->pp_flags & PP_DEBUG) + printk (KERN_WARNING "%s: invalid ipcp packet length: %d bytes\n", + dev->name, len); + return; + } + h = (struct lcp_header *)skb->data; + skb_pull(skb,sizeof(struct lcp_header)); + if (sp->pp_flags & PP_DEBUG) { + char state = '?'; + switch (sp->ipcp.state) { + case IPCP_STATE_CLOSED: state = 'C'; break; + case IPCP_STATE_ACK_RCVD: state = 'R'; break; + case IPCP_STATE_ACK_SENT: state = 'S'; break; + case IPCP_STATE_OPENED: state = 'O'; break; + } + + printk (KERN_WARNING "%s: ipcp input(%c): %d bytes <%s id=%xh len=%xh", + dev->name, + state, + len, + sppp_ipcp_type_name (h->type), h->ident, ntohs (h->len)); + + if (len > 4) + sppp_print_bytes ((u8*) (h+1), len-4); + + printk (">\n"); + } + + if (len > ntohs (h->len)) + len = ntohs (h->len); + + ipcp_h = (struct ipcp_header*)(h+1); + + switch (h->type) { + default: + /* Unknown packet type -- send Code-Reject packet. */ + sppp_cp_send (sp, PPP_IPCP, IPCP_CODE_REJ, ++sp->pp_seq[IDX_LCP], len, h); + break; + + case IPCP_CONF_REQ: + + if (len < 4) { + if (sp->pp_flags & PP_DEBUG) + printk (KERN_WARNING "%s: invalid ipcp configure request packet length: %d bytes\n", + dev->name, len); + return; + } + if (len > 4) { + + if (!sp->dynamic_ip){ + + remote_ip=wan_get_ip_address(sp->pp_if,WAN_POINTOPOINT_IP); + + if (remote_ip == *(unsigned long*)&ipcp_h->data[0]){ + sppp_cp_send (sp, PPP_IPCP, LCP_CONF_ACK, h->ident, + len-4, h+1); + + sppp_clear_timeout (sp); + + remote_ip=*(unsigned long*)&ipcp_h->data[0]; + DEBUG_EVENT("%s: IPCP Static: P-to-P verified: %u.%u.%u.%u\n", + sp->pp_if->name, + NIPQUAD(remote_ip)); + + } else { + + remote_ip = *(unsigned long*)&ipcp_h->data[0]; + + sp->local_ip=wan_get_ip_address(sp->pp_if,WAN_LOCAL_IP); + sp->remote_ip=wan_get_ip_address(sp->pp_if,WAN_POINTOPOINT_IP); + DEBUG_EVENT("%s: IPCP Static Refusing P-to-P %u.%u.%u.%u: Dynamic ip disabled!\n", + sp->pp_if->name, NIPQUAD(remote_ip)); + + DEBUG_EVENT("%s: IPCP Current Cfg: Local %u.%u.%u.%u P-to-P %u.%u.%u.%u\n", + sp->pp_if->name, + NIPQUAD(sp->local_ip), + NIPQUAD(sp->remote_ip)); + + if (++sp->dynamic_failures > 10){ + + sppp_cp_send (sp, PPP_IPCP, IPCP_TERM_REQ, h->ident, 0, 0); + sp->ipcp.state = IPCP_STATE_CLOSED; + sppp_set_timeout (sp, 5); + sp->dynamic_failures=0; + + }else{ + + sppp_cp_send (sp, PPP_IPCP, LCP_CONF_REJ, h->ident, + len-4, h+1); + + switch (sp->ipcp.state) { + case IPCP_STATE_OPENED: + /* Initiate renegotiation. */ + sppp_ipcp_open (sp); + /* fall through... */ + case IPCP_STATE_ACK_SENT: + /* Go to closed state. */ + sp->ipcp.state = IPCP_STATE_CLOSED; + } + } + } + + } else { + sp->remote_ip = *(unsigned long*)&ipcp_h->data[0]; + sppp_cp_send (sp, PPP_IPCP, LCP_CONF_ACK, h->ident, + len-4, h+1); + + sppp_clear_timeout (sp); + } + + } else { + /* Send Configure-Ack packet. */ + sppp_cp_send (sp, PPP_IPCP, IPCP_CONF_ACK, h->ident, + 0, 0); + + /* Change the state. */ + if (sp->ipcp.state == IPCP_STATE_ACK_RCVD) + sp->ipcp.state = IPCP_STATE_OPENED; + else + sp->ipcp.state = IPCP_STATE_ACK_SENT; + } + break; + + case IPCP_CONF_ACK: + if (h->ident != sp->ipcp.confid) + break; + sppp_clear_timeout (sp); + switch (sp->ipcp.state) { + case IPCP_STATE_CLOSED: + sp->ipcp.state = IPCP_STATE_ACK_RCVD; + sppp_set_timeout (sp, 5); + break; + case IPCP_STATE_ACK_SENT: + sp->ipcp.state = IPCP_STATE_OPENED; + + if (sp->dynamic_ip){ + wan_schedule_task(&sp->sppp_task); + } + break; + } + break; + + case IPCP_CONF_NAK: + + if (h->ident != sp->ipcp.confid) + break; + + if (ipcp_h->len >= 6) { + + if (!sp->dynamic_ip) { + + local_ip=wan_get_ip_address(sp->pp_if,WAN_LOCAL_IP); + + if (local_ip == *(unsigned long*)&ipcp_h->data[0]) { + sppp_cp_send (sp, PPP_IPCP, LCP_CONF_REQ, h->ident, + len-4, h+1); + + sp->ipcp.state = IPCP_STATE_ACK_SENT; + + local_ip=*(unsigned long*)&ipcp_h->data[0]; + DEBUG_EVENT("%s: IPCP Static: Local IP verified: %u.%u.%u.%u\n", + sp->pp_if->name, + NIPQUAD(local_ip)); + + break; + } else { + local_ip=*(unsigned long*)&ipcp_h->data[0]; + DEBUG_EVENT("%s: IPCP Static: Refusing Local %u.%u.%u.%u: Dynamic ip disabled!\n", + sp->pp_if->name, NIPQUAD(local_ip)); + + DEBUG_EVENT("%s: IPCP Current Cfg: Local %u.%u.%u.%u P-to-P %u.%u.%u.%u\n", + sp->pp_if->name, + NIPQUAD(sp->local_ip), + NIPQUAD(sp->remote_ip)); + + sppp_cp_send (sp, PPP_IPCP, LCP_CONF_REJ, h->ident, + len-4, h+1); + + /* Drop down to reject */ + + } + + } else { + sp->local_ip = *(unsigned long*)&ipcp_h->data[0]; + sppp_cp_send (sp, PPP_IPCP, LCP_CONF_REQ, h->ident, + len-4, h+1); + + sp->ipcp.state = IPCP_STATE_ACK_SENT; + break; + } + } + /* Drop down to reject */ + + case IPCP_CONF_REJ: + if (h->ident != sp->ipcp.confid) + break; + sppp_clear_timeout (sp); + /* Initiate renegotiation. */ + sppp_ipcp_open (sp); + if (sp->ipcp.state != IPCP_STATE_ACK_SENT) + /* Go to closed state. */ + sp->ipcp.state = IPCP_STATE_CLOSED; + break; + + case IPCP_TERM_REQ: + /* Send Terminate-Ack packet. */ + sppp_cp_send (sp, PPP_IPCP, IPCP_TERM_ACK, h->ident, 0, 0); + /* Go to closed state. */ + sp->ipcp.state = IPCP_STATE_CLOSED; + /* Initiate renegotiation. */ + sppp_ipcp_open (sp); + break; + case IPCP_TERM_ACK: + /* Ignore for now. */ + case IPCP_CODE_REJ: + /* Ignore for now. */ + break; + } +} + +static void sppp_lcp_open (struct sppp *sp) +{ + char opt[6]; + + if (sp->dynamic_ip){ + sp->local_ip=0; + sp->remote_ip=0; + if (wan_get_ip_address(sp->pp_if,WAN_LOCAL_IP)){ + wan_schedule_task(&sp->sppp_task); + } + } + + if (! sp->lcp.magic) + sp->lcp.magic = jiffies; + opt[0] = LCP_OPT_MAGIC; + opt[1] = sizeof (opt); + opt[2] = sp->lcp.magic >> 24; + opt[3] = sp->lcp.magic >> 16; + opt[4] = sp->lcp.magic >> 8; + opt[5] = sp->lcp.magic; + sp->lcp.confid = ++sp->pp_seq[IDX_LCP]; + sppp_cp_send (sp, PPP_LCP, LCP_CONF_REQ, sp->lcp.confid, + sizeof (opt), &opt); + sppp_set_timeout (sp, 2); +} + +static void sppp_ipcp_open (struct sppp *sp) +{ + if (sp->dynamic_ip){ + unsigned char data[]={3,6,0,0,0,0}; + sp->ipcp.confid = ++sp->pp_seq[IDX_LCP]; + sppp_cp_send (sp, PPP_IPCP, IPCP_CONF_REQ, sp->ipcp.confid, 6, data); + sppp_set_timeout (sp, 2); + }else{ + sp->ipcp.confid = ++sp->pp_seq[IDX_LCP]; + sppp_cp_send (sp, PPP_IPCP, IPCP_CONF_REQ, sp->ipcp.confid, 0,0); + sppp_set_timeout (sp, 2); + } +} + +/* + * Process PPP control protocol timeouts. + */ + +static void sppp_cp_timeout (unsigned long arg) +{ + struct sppp *sp = (struct sppp*) arg; + //unsigned long flags; + + //wan_spin_lock_irq(&spppq_lock, &flags); + + sp->pp_flags &= ~PP_TIMO; + if (! (sp->pp_if->flags & IFF_UP) || (sp->pp_flags & PP_CISCO)) { + //wan_spin_unlock_irq(&spppq_lock, &flags); + return; + } + switch (sp->lcp.state) { + case LCP_STATE_CLOSED: + /* No ACK for Configure-Request, retry. */ + sppp_lcp_open (sp); + break; + case LCP_STATE_ACK_RCVD: + /* ACK got, but no Configure-Request for peer, retry. */ + sppp_lcp_open (sp); + sp->lcp.state = LCP_STATE_CLOSED; + break; + case LCP_STATE_ACK_SENT: + /* ACK sent but no ACK for Configure-Request, retry. */ + sppp_lcp_open (sp); + break; + case LCP_STATE_OPENED: + /* LCP is already OK, try IPCP. */ + switch (sp->ipcp.state) { + case IPCP_STATE_CLOSED: + /* No ACK for Configure-Request, retry. */ + sppp_ipcp_open (sp); + break; + case IPCP_STATE_ACK_RCVD: + /* ACK got, but no Configure-Request for peer, retry. */ + sppp_ipcp_open (sp); + sp->ipcp.state = IPCP_STATE_CLOSED; + break; + case IPCP_STATE_ACK_SENT: + /* ACK sent but no ACK for Configure-Request, retry. */ + sppp_ipcp_open (sp); + break; + case IPCP_STATE_OPENED: + /* IPCP is OK. */ + break; + } + break; + } + //wan_spin_unlock_irq(&spppq_lock, &flags); +} + +static char *sppp_lcp_type_name (u8 type) +{ + static char buf [8]; + switch (type) { + case LCP_CONF_REQ: return ("conf-req"); + case LCP_CONF_ACK: return ("conf-ack"); + case LCP_CONF_NAK: return ("conf-nack"); + case LCP_CONF_REJ: return ("conf-rej"); + case LCP_TERM_REQ: return ("term-req"); + case LCP_TERM_ACK: return ("term-ack"); + case LCP_CODE_REJ: return ("code-rej"); + case LCP_PROTO_REJ: return ("proto-rej"); + case LCP_ECHO_REQ: return ("echo-req"); + case LCP_ECHO_REPLY: return ("echo-reply"); + case LCP_DISC_REQ: return ("discard-req"); + } + sprintf (buf, "%xh", type); + return (buf); +} + +static char *sppp_ipcp_type_name (u8 type) +{ + static char buf [8]; + switch (type) { + case IPCP_CONF_REQ: return ("conf-req"); + case IPCP_CONF_ACK: return ("conf-ack"); + case IPCP_CONF_NAK: return ("conf-nack"); + case IPCP_CONF_REJ: return ("conf-rej"); + case IPCP_TERM_REQ: return ("term-req"); + case IPCP_TERM_ACK: return ("term-ack"); + case IPCP_CODE_REJ: return ("code-rej"); + } + sprintf (buf, "%xh", type); + return (buf); +} + +static void sppp_print_bytes (u_char *p, u16 len) +{ + printk (" %x", *p++); + while (--len > 0) + printk ("-%x", *p++); +} + + +#if 0 + +/** + * sppp_rcv - receive and process a WAN PPP frame + * @skb: The buffer to process + * @dev: The device it arrived on + * @p: Unused + * + * Protocol glue. This drives the deferred processing mode the poorer + * cards use. This can be called directly by cards that do not have + * timing constraints but is normally called from the network layer + * after interrupt servicing to process frames queued via netif_rx. + */ + +static int sppp_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *p) +{ + wp_sppp_input(dev,skb); + return 0; +} + + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) +struct packet_type sppp_packet_type = { + type: __constant_htons(ETH_P_WAN_PPP), + func: sppp_rcv, +}; +#else +struct packet_type sppp_packet_type= +{ + 0, + NULL, + sppp_rcv, + NULL, + NULL +}; +#endif + +#endif + +static char fullname[] = "WANPIPE(tm) PPP/Cisco HDLC Protocol"; + +static int __init sync_ppp_init(void) +{ + if(debug) + debug=PP_DEBUG; + + if (WANPIPE_VERSION_BETA){ + DEBUG_EVENT("%s Beta%s-%s %s %s\n", + fullname, WANPIPE_SUB_VERSION, WANPIPE_VERSION, + WANPIPE_COPYRIGHT_DATES,WANPIPE_COMPANY); + }else{ + DEBUG_EVENT("%s Stable %s-%s %s %s\n", + fullname, WANPIPE_VERSION, WANPIPE_SUB_VERSION, + WANPIPE_COPYRIGHT_DATES,WANPIPE_COMPANY); + } + +#if 0 + dev_add_pack(&sppp_packet_type); +#endif + wan_spin_lock_init(&spppq_lock); + wan_spin_lock_init(&authenticate_lock); + + sppp_keepalive_interval=10; + sppp_max_keepalive_count=MAXALIVECNT; + +#if defined(CONFIG_PROC_FS) && LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) + sppp_proc_init(); +#endif + return 0; +} + +static void __exit sync_ppp_cleanup(void) +{ +#if defined(CONFIG_PROC_FS) && LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) + sppp_proc_cleanup(); +#endif +#if 0 + dev_remove_pack(&sppp_packet_type); +#endif +} + +module_init(sync_ppp_init); +module_exit(sync_ppp_cleanup); + +MODULE_AUTHOR ("Nenad Corbic "); +MODULE_DESCRIPTION ("Sangoma WANPIPE: WAN PPP Driver"); +MODULE_LICENSE("GPL"); + +/* PROC FILE SYSTEM ADDITION BY NENAD CORBIC */ + +#if defined(CONFIG_PROC_FS) && LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) + +#ifndef min +#define min(a,b) (((a)<(b))?(a):(b)) +#endif +#ifndef max +#define max(a,b) (((a)>(b))?(a):(b)) +#endif +#define PROC_BUFSZ 4000 +#define MAX_TOKENS 32 + +static ssize_t router_proc_read(struct file* file, char* buf, size_t count, + loff_t *ppos) +{ + struct inode *inode = file->f_dentry->d_inode; + struct proc_dir_entry* dent; + char* page; + int pos, offs, len; + + if (count <= 0) + return 0; + + dent = inode->u.generic_ip; + if ((dent == NULL) || (dent->get_info == NULL)){ + printk(KERN_INFO "NO DENT\n"); + return 0; + } + + page = kmalloc(PROC_BUFSZ, GFP_KERNEL); + if (page == NULL) + return -ENOBUFS; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) + pos = dent->get_info(page, dent->data, 0, 0); +#else + pos = dent->get_info(page, dent->data, 0, 0, 0); +#endif + offs = file->f_pos; + if (offs < pos) { + len = wp_min(pos - offs, count); + if(copy_to_user(buf, (page + offs), len)) + return -EFAULT; + file->f_pos += len; + }else{ + len = 0; + } + kfree(page); + return len; +} + +/*============================================================================ + * Strip leading and trailing spaces off the string str. + */ +char* strstrip (char* str, char* s) +{ + char* eos = str + strlen(str); /* -> end of string */ + + while (*str && strchr(s, *str)) + ++str; /* strip leading spaces */ + while ((eos > str) && strchr(s, *(eos - 1))) + --eos; /* strip trailing spaces */ + *eos = '\0'; + return str; +} + +/*============================================================================ + * Tokenize string. + * Parse a string of the following syntax: + * =,,... + * and fill array of tokens with pointers to string elements. + * + * Return number of tokens. + */ +int tokenize (char* str, char **tokens, char *arg1, char *arg2, char *arg3) +{ + int cnt = 0; + + tokens[0] = strsep(&str, arg1); + while (tokens[cnt] && (cnt < MAX_TOKENS - 1)) { + tokens[cnt] = strstrip(tokens[cnt], arg2); + tokens[++cnt] = strsep(&str, arg3); + } + return cnt; +} + +static ssize_t router_proc_write(struct file *file, const char *buf, size_t count, loff_t *ppos) +{ + struct inode *inode = file->f_dentry->d_inode; + struct proc_dir_entry* dent; + char* page; + int toknum; + char* token[MAX_TOKENS]; + struct sppp *sp; + struct net_device *dev; + unsigned long flags; + char msg[100]; + char print_msg=0; + + if (count <= 0 || count > PROC_BUFSZ) + return -EIO; + + dent = inode->u.generic_ip; + if ((dent == NULL) || (dent->get_info == NULL)) + return -EIO; + + page = kmalloc(count, GFP_KERNEL); + if (page == NULL) + return -ENOBUFS; + + if (copy_from_user(page,buf,count)){ + kfree(page); + return -EFAULT; + } + + toknum = tokenize(page, token, " ", " \t\n", " "); + if (toknum < 2){ + kfree(page); + return -EINVAL; + } + + wan_spin_lock_irq(&spppq_lock, &flags); + for (sp=spppq; sp; sp=sp->pp_next){ + dev = sp->pp_if; + if (!strcmp(dev->name,token[0]) && toknum == 3){ + if (!strcmp(token[1], "debug")){ + + if (!strcmp(token[2],"on")){ + sprintf(msg,"%s: SyncPPP debug: on\n",dev->name); + print_msg=1; + sp->pp_flags |= PP_DEBUG; + }else{ + sprintf(msg,"%s: SyncPPP debug: off\n",dev->name); + print_msg=1; + sp->pp_flags &= ~PP_DEBUG; + } + } + } + if (!strcmp(token[0], "keepalive_interval") && toknum == 2){ + unsigned int interval=sppp_keepalive_interval; + if ((interval=(unsigned)simple_strtoul(token[1],NULL,10)) && + interval > 0 && interval < 101){ + if (interval != sppp_keepalive_interval){ + sprintf(msg,"SyncPPP keepalive interval: %i\n",interval); + print_msg=1; + sppp_keepalive_interval=interval; + } + } + } + if (!strcmp(token[0], "max_keepalive_count") && toknum == 2){ + unsigned int kcount=sppp_max_keepalive_count; + if ((kcount=(unsigned)simple_strtoul(token[1],NULL,10)) && + kcount > 0 && kcount < 101){ + if (kcount != sppp_max_keepalive_count){ + print_msg=1; + sprintf(msg,"SyncPPP max keepalive count: %i\n",kcount); + sppp_max_keepalive_count=kcount; + } + } + } + } + wan_spin_unlock_irq(&spppq_lock, &flags); + + if (print_msg){ + printk(KERN_INFO "%s",msg); + } + + kfree(page); + return count; +} + + + +static int router_proc_perms (struct inode* inode, int op) +{ + int mode = inode->i_mode; + if (!current->euid){ + mode >>= 6; + }else if (in_egroup_p(0)){ + mode >>= 3; + } + + if ((mode & op & 0007) == op) + return 0; + + return -EACCES; +} + +static char proc_name[] = "syncppp"; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) +static struct file_operations router_fops = +{ + read: router_proc_read, + write: router_proc_write, +}; + +static struct inode_operations router_inode = +{ + permission: router_proc_perms +}; +#else +static struct file_operations router_fops = +{ + NULL, /* lseek */ + router_proc_read, /* read */ + router_proc_write, /* write */ + NULL, /* readdir */ + NULL, /* select */ + NULL, /* ioctl */ + NULL, /* mmap */ + NULL, /* no special open code */ + NULL, /* flush */ + NULL, /* no special release code */ + NULL /* can't fsync */ +}; + +static struct inode_operations router_inode = +{ + &router_fops, + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* follow link */ + NULL, /* readlink */ + NULL, /* readpage */ + NULL, /* writepage */ + NULL, /* bmap */ + NULL, /* truncate */ + router_proc_perms +}; +#endif + +extern struct proc_dir_entry *proc_router; + +int sppp_proc_init (void) +{ + struct proc_dir_entry *p; + + if (!proc_router){ + return -ENODEV; + } + + p = create_proc_entry(proc_name,0644,proc_router); + if (!p) + return -ENOMEM; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) + p->proc_fops = &router_fops; + p->proc_iops = &router_inode; +#else + p->ops = &router_inode; + p->nlink = 1; +#endif + p->get_info = status_get_info; + + return 0; +} +void sppp_proc_cleanup (void) +{ + remove_proc_entry(proc_name, proc_router); +} + + +static char stat_hdr[] = + "----------------------------------------------------------------------------\n" + "|Interface Name| Protocol | Debug | LCP State | ICMP State | Link State |\n" + "----------------------------------------------------------------------------\n"; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) +static int status_get_info(char* buf, char** start, off_t offs, int len) +#else +static int status_get_info(char* buf, char** start, off_t offs, int len,int dummy) +#endif +{ + int cnt = 0; + struct sppp *sp; + struct net_device *dev; + + strcpy(&buf[cnt], stat_hdr); + cnt += sizeof(stat_hdr) - 1; + + for (sp=spppq; sp; sp=sp->pp_next){ + dev = sp->pp_if; + cnt += sprintf(&buf[cnt], + "| %-13s| %-9s| %-6s| %-12s| %-12s| %-10s |\n", + dev->name, + (sp->pp_flags & PP_CISCO) ? "CHDLC" : "PPP", + (sp->pp_flags & PP_DEBUG) ? "on" : "off", + decode_lcp_state(sp->lcp.state), + decode_ipcp_state(sp->ipcp.state), + sp->pp_link_state ? "up" : "down"); + } + + cnt += sprintf(&buf[cnt], "----------------------------------------------------------------------------\n"); + cnt += sprintf(&buf[cnt], "\nPPP Config: keepalive_interval: %u | max_keepalive_count: %u |\n\n", + sppp_keepalive_interval,sppp_max_keepalive_count); + return cnt; +} + + +static char *decode_lcp_state(int state) +{ + switch (state){ + + case LCP_STATE_CLOSED: /* LCP state: closed (conf-req sent) */ + return "closed"; + case LCP_STATE_ACK_RCVD: /* LCP state: conf-ack received */ + return "conf-ack rx"; + case LCP_STATE_ACK_SENT: /* LCP state: conf-ack sent */ + return "conf-ack tx"; + case LCP_STATE_OPENED: /* LCP state: opened */ + return "opened"; + } + return "invalid"; +} + +static char *decode_ipcp_state(int state) +{ + switch (state){ + + case IPCP_STATE_CLOSED: /* IPCP state: closed (conf-req sent) */ + return "closed"; + case IPCP_STATE_ACK_RCVD: /* IPCP state: conf-ack received */ + return "conf-ack rx"; + case IPCP_STATE_ACK_SENT: /* IPCP state: conf-ack sent */ + return "conf-ack tx"; + case IPCP_STATE_OPENED: /* IPCP state: opened */ + return "opened"; + } + return "invalid"; +} + +#endif + + +static void sppp_bh (void *sp_ptr) +{ + struct sppp *sp=sp_ptr; + struct net_device *dev=sp->pp_if; + + if (!sp->dynamic_ip || !sp->pp_if) + return; + + if (test_and_set_bit(0,&sp->task_working)){ + DEBUG_EVENT("%s: Critical in sppp bh!\n",dev->name); + return; + } + + if (sp->ipcp.state == IPCP_STATE_OPENED){ + + int err=wan_set_ip_address(sp->pp_if,WAN_LOCAL_IP,sp->local_ip); + if (!err){ + DEBUG_EVENT("%s: Local IP Address %u.%u.%u.%u\n", + dev->name,NIPQUAD(sp->local_ip)); + }else{ + DEBUG_EVENT("%s: Failed to set Local IP Address %u.%u.%u.%u: Rc=%i\n", + dev->name,NIPQUAD(sp->local_ip),err); + } + err=wan_set_ip_address(sp->pp_if,WAN_POINTOPOINT_IP,sp->remote_ip); + if (!err){ + DEBUG_EVENT("%s: P-to-P IP Address %u.%u.%u.%u\n", + dev->name,NIPQUAD(sp->remote_ip)); + }else{ + DEBUG_EVENT("%s: Failed to set P-to-P IP Address %u.%u.%u.%u: Rc=%i\n", + dev->name,NIPQUAD(sp->remote_ip),err); + } + + if (sp->gateway){ + if (dev->flags & IFF_UP){ + wan_add_gateway(dev); + }else{ + DEBUG_EVENT("%s: Failed to add gateway dev not up!\n", + dev->name); + } + } + + wan_run_wanrouter(sp->hwdevname,dev->name,"script"); + + }else{ + sp->local_ip=0; + sp->remote_ip=0; + DEBUG_EVENT("%s: Local IP Address %u.%u.%u.%u\n", + dev->name,NIPQUAD(sp->local_ip)); + if (wan_get_ip_address(sp->pp_if,WAN_LOCAL_IP)){ + DEBUG_TX("%s: Local IP Address Exists Removing\n", + dev->name); + wan_set_ip_address(sp->pp_if,WAN_LOCAL_IP,sp->local_ip); + } + DEBUG_TX("%s: END Local IP Address %u.%u.%u.%u\n", + dev->name,NIPQUAD(sp->local_ip)); + } + + clear_bit(0,&sp->task_working); +} diff -Nur linux.org/drivers/net/wan/wanpipe_syncppp.mod.c linux-2.6.17/drivers/net/wan/wanpipe_syncppp.mod.c --- linux.org/drivers/net/wan/wanpipe_syncppp.mod.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/drivers/net/wan/wanpipe_syncppp.mod.c 2006-08-30 10:07:17.000000000 +0000 @@ -0,0 +1,30 @@ +#include +#include +#include + +MODULE_INFO(vermagic, VERMAGIC_STRING); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,6) || defined(WANPIPE_MOD_266_FORCE_UPDATE) +#undef unix +struct module __this_module +__attribute__((section(".gnu.linkonce.this_module"))) = { + .name = __stringify(KBUILD_MODNAME), + .init = init_module, +#ifdef CONFIG_MODULE_UNLOAD + .exit = cleanup_module, +#endif +}; +#endif + + +static const struct modversion_info ____versions[] +__attribute__((section("__versions"))) = { + +}; + + +static const char __module_depends[] +__attribute_used__ +__attribute__((section(".modinfo"))) = +"depends=wanrouter"; + diff -Nur linux.org/drivers/net/wan/wanpipe_tdm_api.c linux-2.6.17/drivers/net/wan/wanpipe_tdm_api.c --- linux.org/drivers/net/wan/wanpipe_tdm_api.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/drivers/net/wan/wanpipe_tdm_api.c 2006-08-30 10:07:17.000000000 +0000 @@ -0,0 +1,1598 @@ +/***************************************************************************** +* wanpipe_tdm_api.c +* +* WANPIPE(tm) AFT TE1 Hardware Support +* +* Authors: Nenad Corbic +* +* Copyright: (c) 2003-2005 Sangoma Technologies Inc. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version +* 2 of the License, or (at your option) any later version. +* ============================================================================ +* Oct 04, 2005 Nenad Corbic Initial version. +*****************************************************************************/ + +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) +# include +# include +# include +# include +# include +#elif defined(__LINUX__) +# include +# include +# include +# include +# include +#endif + +#include + +/*============================================================== + Defines + */ + +#define WP_TDMAPI_MAJOR 241 +#define WP_TDMAPI_MINOR_OFFSET 0 + + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15) +#define WP_CLASS_DEV_CREATE(class, devt, device, name) \ + class_device_create(class, NULL, devt, device, name) +#else +#define WP_CLASS_DEV_CREATE(class, devt, device, name) \ + class_device_create(class, devt, device, name) +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13) +static struct class *wp_tdmapi_class = NULL; +#else +static struct class_simple *wp_tdmapi_class = NULL; +#define class_create class_simple_create +#define class_destroy class_simple_destroy +#define class_device_create class_simple_device_add +#define class_device_destroy(a, b) class_simple_device_remove(b) +#endif + +#define UNIT(file) MINOR(file->f_dentry->d_inode->i_rdev) + +#define WP_TDMAPI_SPAN_MASK 0xFFFF +#define WP_TMDAPI_SPAN_SHIFT 5 //8 +#define WP_TDMAPI_CHAN_MASK 0x1F //0xFF + +#define WP_TDMAPI_SET_MINOR(span,chan) ((((span-1)&WP_TDMAPI_SPAN_MASK)<>WP_TMDAPI_SPAN_SHIFT)&WP_TDMAPI_SPAN_MASK)+1) + +#define WP_TDMAPI_GET_CHAN_FROM_MINOR(minor) ((minor)&WP_TDMAPI_CHAN_MASK) + +#define WP_TDM_API_MAX_PERIOD 50 /* 50ms */ + +#define WP_TDM_MAX_RX_Q_LEN 10 +#define WP_TDM_MAX_TX_Q_LEN 5 +#define WP_TDM_MAX_HDLC_TX_Q_LEN 17 +#define WP_TDM_MAX_EVENT_Q_LEN 5 +#define WP_TDM_MAX_RX_FREE_Q_LEN 10 + +#define WP_TDMAPI_MAX_SPANS 255 + + +#undef DEBUG_API_WAKEUP +#undef DEBUG_API_READ +#undef DEBUG_API_WRITE +#undef DEBUG_API_POLL + + +static void *wp_tdmapi_hash[WP_TDMAPI_HASH_SZ]; +static wan_spinlock_t wp_tdmapi_hash_lock; +static int wp_tdmapi_global_cnt=0; +/*============================================================== + Prototypes + */ + +static int wp_tdmapi_open(struct inode *inode, struct file *file); +static ssize_t wp_tdmapi_read(struct file *file, char *usrbuf, size_t count, loff_t *ppos); +static ssize_t wp_tdmapi_write(struct file *file, const char *usrbuf, size_t count, loff_t *ppos); +static int wp_tdmapi_release(struct inode *inode, struct file *file); +static int wp_tdmapi_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long data); +static unsigned int wp_tdmapi_poll(struct file *file, struct poll_table_struct *wait_table); +static int wanpipe_tdm_api_ioctl(wanpipe_tdm_api_dev_t *tdm_api, struct ifreq *ifr); +static void wanpipe_tdm_api_rbs_poll(wanpipe_tdm_api_dev_t *tdm_api); + +static void wp_tdmapi_rbsbits(void* card_id, int channel, unsigned char rbsbits); +static void wp_tdmapi_alarms(void* card_id, unsigned long alarams); +static void wp_tdmapi_dtmf(void* card_id, wan_event_t*); +static void wp_tdmapi_hook(void* card_id, wan_event_t*); +static void wp_tdmapi_ringtrip(void* card_id, wan_event_t*); + +/*============================================================== + Global Variables + */ + +static struct file_operations wp_tdmapi_fops = { + owner: THIS_MODULE, + llseek: NULL, + open: wp_tdmapi_open, + release: wp_tdmapi_release, + ioctl: wp_tdmapi_ioctl, + read: wp_tdmapi_read, + write: wp_tdmapi_write, + poll: wp_tdmapi_poll, + mmap: NULL, + flush: NULL, + fsync: NULL, + fasync: NULL, +}; + +static void wp_tdmapi_init_buffs(wanpipe_tdm_api_dev_t *tdm_api) +{ + wan_skb_queue_purge(&tdm_api->wp_rx_list); + wan_skb_queue_purge(&tdm_api->wp_rx_free_list); + wan_skb_queue_purge(&tdm_api->wp_tx_free_list); + wan_skb_queue_purge(&tdm_api->wp_tx_list); + wan_skb_queue_purge(&tdm_api->wp_event_list); + + if (tdm_api->rx_skb){ + wan_skb_free(tdm_api->rx_skb); + tdm_api->rx_skb=NULL; + } + if (tdm_api->tx_skb){ + wan_skb_free(tdm_api->tx_skb); + tdm_api->tx_skb=NULL; + } + +} + + +#ifdef DEBUG_API_WAKEUP +static int gwake_cnt=0; +#endif +static void wp_wakeup_tdmapi(wanpipe_tdm_api_dev_t *tdm_api) +{ +#ifdef DEBUG_API_WAKEUP + if (tdm_api->tdm_span == 1 && tdm_api->tdm_chan == 1) { + gwake_cnt++; + if (gwake_cnt % 1000 == 0) { + DEBUG_EVENT("%s: TDMAPI WAKING DEV \n",tdm_api->name); + } + } +#endif + if (waitqueue_active(&tdm_api->poll_wait)){ + wake_up_interruptible(&tdm_api->poll_wait); + } +} + +static int wp_tdmapi_reg_globals(void) +{ + int err; + + wan_spin_lock_init(&wp_tdmapi_hash_lock); + DEBUG_EVENT("%s: Registering Wanpipe TDM Device!\n",__FUNCTION__); + wp_tdmapi_class = class_create(THIS_MODULE, "wptdm"); + if ((err = register_chrdev(WP_TDMAPI_MAJOR, "wptdm", &wp_tdmapi_fops))) { + DEBUG_EVENT("Unable to register tor device on %d\n", WP_TDMAPI_MAJOR); + } + return err; +} + +static int wp_tdmapi_unreg_globals(void) +{ + DEBUG_EVENT("%s: Unregistering Wanpipe TDM Device!\n",__FUNCTION__); + class_destroy(wp_tdmapi_class); + unregister_chrdev(WP_TDMAPI_MAJOR, "wptdm"); + return 0; +} + +int wanpipe_tdm_api_reg(wanpipe_tdm_api_dev_t *tdm_api) +{ + sdla_t *card = NULL; + u8 tmp_name[50]; + int err; + + if (wp_tdmapi_global_cnt == 0){ + wp_tdmapi_reg_globals(); + } + wp_tdmapi_global_cnt++; + + WAN_ASSERT(tdm_api == NULL); + card = (sdla_t*)tdm_api->card; + + wan_skb_queue_init(&tdm_api->wp_rx_list); + wan_skb_queue_init(&tdm_api->wp_rx_free_list); + wan_skb_queue_init(&tdm_api->wp_tx_free_list); + wan_skb_queue_init(&tdm_api->wp_tx_list); + wan_skb_queue_init(&tdm_api->wp_event_list); + + tdm_api->cfg.rbs_poll=0; + + if (tdm_api->hdlc_framing) { + + tdm_api->cfg.hw_mtu_mru =1500; + tdm_api->cfg.usr_period =0; + tdm_api->cfg.tdm_codec =WP_NONE; + tdm_api->cfg.power_level =0; + tdm_api->cfg.rx_disable =0; + tdm_api->cfg.tx_disable =0; + tdm_api->cfg.usr_mtu_mru =1500; + tdm_api->cfg.ec_tap =0; + tdm_api->cfg.rbs_rx_bits =-1; + tdm_api->cfg.hdlc =1; + tdm_api->tx_q_len = WP_TDM_MAX_HDLC_TX_Q_LEN; + + } else { + tdm_api->cfg.hw_mtu_mru =8; + tdm_api->cfg.usr_period =10; + tdm_api->cfg.tdm_codec =WP_NONE; + tdm_api->cfg.power_level =0; + tdm_api->cfg.rx_disable =0; + tdm_api->cfg.tx_disable =0; + tdm_api->cfg.usr_mtu_mru =tdm_api->cfg.usr_period*tdm_api->cfg.hw_mtu_mru; + tdm_api->cfg.ec_tap =0; + tdm_api->cfg.rbs_rx_bits =-1; + tdm_api->cfg.hdlc =0; + tdm_api->tx_q_len = WP_TDM_MAX_TX_Q_LEN; + + } + + tdm_api->critical=0; + wan_clear_bit(0,&tdm_api->used); + + init_waitqueue_head(&tdm_api->poll_wait); + + err=wphash_tdm_api_dev(wp_tdmapi_hash,tdm_api, + WP_TDMAPI_SET_MINOR(tdm_api->tdm_span,tdm_api->tdm_chan)); + if (err){ + wp_tdmapi_global_cnt--; + if (wp_tdmapi_global_cnt == 0){ + wp_tdmapi_unreg_globals(); + } + return err; + } + wan_spin_lock_init(&tdm_api->lock); + sprintf(tmp_name,"wptdm_s%dc%d",tdm_api->tdm_span,tdm_api->tdm_chan); + + /* Initialize Event Callback functions */ + card->wandev.event_callback.rbsbits = wp_tdmapi_rbsbits; + card->wandev.event_callback.dtmf = wp_tdmapi_dtmf; + card->wandev.event_callback.alarms = wp_tdmapi_alarms; + card->wandev.event_callback.hook = wp_tdmapi_hook; + + if (tdm_api->cfg.rbs_tx_bits) { + DEBUG_EVENT("%s: Setting Tx RBS/CAS Idle Bits = 0x%02X\n", + tmp_name, + tdm_api->cfg.rbs_tx_bits); + tdm_api->write_rbs_bits(tdm_api->chan, + tdm_api->tdm_chan, + tdm_api->cfg.rbs_tx_bits); + } + + WP_CLASS_DEV_CREATE(wp_tdmapi_class, + MKDEV(WP_TDMAPI_MAJOR, + WP_TDMAPI_SET_MINOR(tdm_api->tdm_span,tdm_api->tdm_chan)), + NULL, tmp_name); + return err; +} + +int wanpipe_tdm_api_unreg(wanpipe_tdm_api_dev_t *tdm_api) +{ + wan_smp_flag_t flags; + + wan_set_bit(WP_TDM_DOWN,&tdm_api->critical); + + if (wan_test_bit(0,&tdm_api->used)) { + DEBUG_EVENT("%s Failed to unreg Span=%i Chan=%i: BUSY!\n", + tdm_api->name,tdm_api->tdm_span,tdm_api->tdm_chan); + return -EBUSY; + } + + wan_spin_lock_irq(&wp_tdmapi_hash_lock,&flags); + wpunhash_tdm_api_dev(tdm_api); + + wp_tdmapi_init_buffs(tdm_api); + + wan_spin_unlock_irq(&wp_tdmapi_hash_lock,&flags); + + class_device_destroy(wp_tdmapi_class, + MKDEV(WP_TDMAPI_MAJOR, + WP_TDMAPI_SET_MINOR(tdm_api->tdm_span,tdm_api->tdm_chan))); + + wp_tdmapi_global_cnt--; + if (wp_tdmapi_global_cnt == 0) { + wp_tdmapi_unreg_globals(); + } + + return 0; +} + +int wanpipe_tdm_api_update_state(wanpipe_tdm_api_dev_t *tdm_api, int state) +{ + if (tdm_api == NULL || !wan_test_bit(0,&tdm_api->init)){ + return -ENODEV; + } + + if (tdm_api->state != state) { + tdm_api->state = state; + + if (wan_test_bit(0,&tdm_api->used)) { + DEBUG_EVENT("%s: UPDATE STATE API\n",tdm_api->name); + wp_wakeup_tdmapi(tdm_api); + } + } + + return 0; +} + +int wanpipe_tdm_api_kick(wanpipe_tdm_api_dev_t *tdm_api) +{ + if (tdm_api == NULL || !wan_test_bit(0,&tdm_api->init)){ + return -ENODEV; + } + + if (is_tdm_api_stopped(tdm_api)){ + wp_tdm_api_start(tdm_api); + + if (wan_test_bit(0,&tdm_api->used)) { + DEBUG_EVENT("%s: KICK API\n",tdm_api->name); + wp_wakeup_tdmapi(tdm_api); + } + } + + return 0; +} + + + +static int wp_tdmapi_open(struct inode *inode, struct file *file) +{ + wanpipe_tdm_api_dev_t *tdm_api; + wan_smp_flag_t flags; + + u32 tdm_span = WP_TDMAPI_GET_SPAN_FROM_MINOR(UNIT(file)); + u32 tdm_chan = WP_TDMAPI_GET_CHAN_FROM_MINOR(UNIT(file)); + + + + wan_spin_lock_irq(&wp_tdmapi_hash_lock,&flags); + tdm_api = wp_find_tdm_api_dev(wp_tdmapi_hash,UNIT(file),tdm_span,tdm_chan); + if (!tdm_api){ + wan_spin_unlock_irq(&wp_tdmapi_hash_lock,&flags); + return -ENODEV; + } + + if (wan_test_bit(WP_TDM_DOWN,&tdm_api->critical)) { + wan_spin_unlock_irq(&wp_tdmapi_hash_lock,&flags); + return -ENODEV; + } + + wp_tdmapi_init_buffs(tdm_api); + + wan_spin_lock(&tdm_api->lock); + if (wan_test_and_set_bit(0,&tdm_api->used)){ + wan_spin_unlock(&tdm_api->lock); + wan_spin_unlock_irq(&wp_tdmapi_hash_lock,&flags); + + DEBUG_EVENT ("%s: Device S/C(%i/%i) is already open!\n", + tdm_api->name, tdm_span,tdm_span); + /* This device is already busy */ + return -EBUSY; + } + + file->private_data = tdm_api; + + wan_spin_unlock(&tdm_api->lock); + wan_spin_unlock_irq(&wp_tdmapi_hash_lock,&flags); + + + DEBUG_TEST ("%s: DRIVER OPEN S/C(%i/%i) API Ptr=%p\n", + __FUNCTION__, tdm_span, tdm_chan, tdm_api); + + return 0; +} + +#ifdef DEBUG_API_READ +static int gread_cnt=0; +#endif + +static ssize_t wp_tdmapi_read_msg(struct file *file, struct msghdr *msg, size_t count) +{ + wanpipe_tdm_api_dev_t *tdm_api; + netskb_t *skb; + int err=0, len; + + WAN_ASSERT((file==NULL)); + + tdm_api=file->private_data; + if (tdm_api == NULL || !wan_test_bit(0,&tdm_api->init) || !wan_test_bit(0,&tdm_api->used)) { + return -ENODEV; + } + + if (wan_test_bit(WP_TDM_DOWN,&tdm_api->critical)) { + return -ENODEV; + } + + + skb=wan_skb_dequeue(&tdm_api->wp_rx_list); + if (!skb){ + return -ENOBUFS; + } + +#ifdef DEBUG_API_READ + if (tdm_api->tdm_span == 1 && + tdm_api->tdm_chan == 1) { + gread_cnt++; + if (gread_cnt && + gread_cnt % 1000 == 0) { + DEBUG_EVENT("%s: WP_TDM API READ %i Len=%i\n", + tdm_api->name, gread_cnt, + wan_skb_len(skb)-sizeof(wp_tdm_api_rx_hdr_t)); + } + } +#endif + + if (count < wan_skb_len(skb) || + wan_skb_len(skb) < sizeof(wp_tdm_api_rx_hdr_t)){ + wan_skb_free(skb); + DEBUG_EVENT("%s:%d TDMAPI READ: Critical Error\n", + __FUNCTION__,__LINE__); + return -EFAULT; + } + + len=wan_skb_len(skb); + + if (tdm_api->cfg.tdm_codec == WP_NONE) { + err = wan_memcpy_toiovec(msg->msg_iov, + wan_skb_data(skb), + wan_skb_len(skb)); + if (err){ + wan_skb_free(skb); + return err; + } + + } else { + u8 *data_ptr; + wanpipe_codec_ops_t *wp_codec_ops; + u32 power; + + + wp_codec_ops=WANPIPE_CODEC_OPS[tdm_api->cfg.hw_tdm_coding][tdm_api->cfg.tdm_codec]; + if (!wp_codec_ops || !wp_codec_ops->init){ + return -EINVAL; + } + + data_ptr=(u8*)wan_skb_data(skb); + +#if 0 + /* OPTIMIZATION: Dont copy the header. + * Not used now */ + err = wan_memcpy_toiovec(msg->msg_iov, + wan_skb_data(skb), + sizeof(wp_tdm_api_rx_hdr_t)); + if (err){ + wan_skb_free(skb); + return err; + } +#endif + len = wp_codec_ops->encode(&data_ptr[sizeof(wp_tdm_api_rx_hdr_t)], + wan_skb_len(skb)-sizeof(wp_tdm_api_rx_hdr_t), + (u16*)msg->msg_iov[1].iov_base, + &power, 1); + + +#ifdef DEBUG_API_READ + if (tdm_api->tdm_span == 1 && + tdm_api->tdm_chan == 1) { + if (gread_cnt && + gread_cnt % 1000 == 0) { + DEBUG_EVENT("%s: WP_TDM API READ CODEC %i Len=%i\n", + tdm_api->name, gread_cnt, + len); + } + } +#endif + + if (len <= 0){ + wan_skb_free(skb); + return -EINVAL; + } + + len+=sizeof(wp_tdm_api_rx_hdr_t); + } + + if (tdm_api->hdlc_framing || + wan_skb_queue_len(&tdm_api->wp_rx_free_list) > WP_TDM_MAX_RX_FREE_Q_LEN) { + wan_skb_free(skb); + } else { + wan_skb_init(skb,16); + wan_skb_trim(skb,0); + wan_skb_queue_tail(&tdm_api->wp_rx_free_list,skb); + } + + return len; +} + +#define WP_UIO_MAX_SZ 5 + +static ssize_t wp_tdmapi_read(struct file *file, char *usrbuf, size_t count, loff_t *ppos) +{ + struct iovec iovstack[WP_UIO_MAX_SZ]; + struct iovec *iov=iovstack; + struct msghdr msg_sys; + struct msghdr *msg = (struct msghdr*)usrbuf; + int err; + + WAN_ASSERT((file==NULL)); + WAN_ASSERT((usrbuf==NULL)); + + if (copy_from_user(&msg_sys,msg,sizeof(struct msghdr))) + return -EFAULT; + + if (msg_sys.msg_iovlen > WP_UIO_MAX_SZ) + return -EFAULT; + + msg_sys.msg_namelen=0; + + err=wan_verify_iovec(&msg_sys, iov, NULL, 0); + if (err < 0) { + return err; + } + + return wp_tdmapi_read_msg(file, &msg_sys, count); +} + + +static int wp_tdmapi_tx(wanpipe_tdm_api_dev_t *tdm_api) +{ + netskb_t *skb; + int err; + + if (wan_test_and_set_bit(WP_TDM_HDLC_TX,&tdm_api->critical)){ + return 0; + } + + while ((skb=wan_skb_dequeue(&tdm_api->wp_tx_list)) != NULL) { + err=tdm_api->write_hdlc_frame(tdm_api->chan,skb); + if (err) { + wan_skb_queue_head(&tdm_api->wp_tx_list, skb); + break; + } + tdm_api->cfg.stats.tx_packets++; + skb=NULL; + } + + wan_clear_bit(WP_TDM_HDLC_TX,&tdm_api->critical); + return 0; +} + +#ifdef DEBUG_API_WRITE +static int gwrite_cnt=0; +#endif +static ssize_t wp_tdmapi_write_msg(struct file *file, struct msghdr *msg, size_t count) +{ + wanpipe_tdm_api_dev_t *tdm_api; + netskb_t *skb; + int err; + int skb_len = WP_TDM_API_MAX_LEN; + u8 *buf; + + WAN_ASSERT((file==NULL)); + + tdm_api = file->private_data; + if (tdm_api == NULL || !wan_test_bit(0,&tdm_api->init) || !wan_test_bit(0,&tdm_api->used)){ + return -ENODEV; + } + if (wan_test_bit(WP_TDM_DOWN,&tdm_api->critical)) { + return -ENODEV; + } + + if (tdm_api->hdlc_framing) { + skb_len=count+100; + if (count > (tdm_api->cfg.usr_mtu_mru + sizeof(wp_tdm_api_tx_hdr_t))) { + return -EFBIG; + } + if (count <= sizeof(wp_tdm_api_tx_hdr_t)) { + return -EINVAL; + } + } else { + /* FIXME: Should have some sort of a check invalid len + * In reality not needed */ +#if 0 + if ((count-sizeof(wp_tdm_api_tx_hdr_t)) % 8){ + DEBUG_EVENT("%s: Error: Tx packet not divisible by 8\n"); + return -EINVAL; + } +#endif + skb_len=WP_TDM_API_MAX_LEN; + } + + if (wan_skb_queue_len(&tdm_api->wp_tx_list) > tdm_api->tx_q_len){ + wp_tdm_api_stop(tdm_api); + return -EBUSY; + } + + skb=wan_skb_dequeue(&tdm_api->wp_tx_free_list); + if (!skb) { + skb=wan_skb_alloc(skb_len); + if (!skb){ + return -ENOMEM; + } + } + + if (tdm_api->hdlc_framing) { + + buf = skb_put(skb,count); + err = memcpy_fromiovec(buf, msg->msg_iov, count); + if (err){ + wan_skb_free(skb); + return -ENOMEM; + } + + if (wan_skb_len(skb) <= sizeof(wp_tdm_api_tx_hdr_t)) { + wan_skb_free(skb); + return -EINVAL; + } + + wan_skb_pull(skb,sizeof(wp_tdm_api_tx_hdr_t)); + wan_skb_queue_tail(&tdm_api->wp_tx_list, skb); + + wp_tdmapi_tx(tdm_api); + + return count; + } + + if (tdm_api->cfg.tdm_codec == WP_NONE) { + + buf = skb_put(skb,count); + err = memcpy_fromiovec(buf, msg->msg_iov, count); + if (err){ + wan_skb_free(skb); + return -ENOMEM; + } + + } else { + + int len; + u8 *buf; + wanpipe_codec_ops_t *wp_codec_ops; + + buf = skb_put(skb,sizeof(wp_tdm_api_tx_hdr_t)); + +#if 0 + /* OPTIMIZATION: Do not copy the Write Header + * Not needed at this time */ + err = memcpy_fromiovec(buf, msg->msg_iov, sizeof(wp_tdm_api_tx_hdr_t)); + if (err){ + wan_skb_free(skb); + return -ENOMEM; + } +#endif + + wp_codec_ops=WANPIPE_CODEC_OPS[tdm_api->cfg.hw_tdm_coding][tdm_api->cfg.tdm_codec]; + if (!wp_codec_ops || !wp_codec_ops->init){ + wan_skb_free(skb); + return -EINVAL; + } + + len = wp_codec_ops->decode((u16*)msg->msg_iov[1].iov_base, + count-sizeof(wp_tdm_api_tx_hdr_t), + wan_skb_tail(skb), 1); + if (len <= 0) { + wan_skb_free(skb); + return -EFAULT; + } + + if (len > wan_skb_tailroom(skb)){ + DEBUG_EVENT("%s:%d TDM WRITE Critical Error: Len=%i TailRoom=%i\n", + __FUNCTION__,__LINE__, len, wan_skb_tailroom(skb)); + wan_skb_free(skb); + tdm_api->cfg.stats.tx_errors++; + return -EIO; + } + + buf=wan_skb_put(skb,len); + } + +#ifdef DEBUG_API_WRITE + if (tdm_api->tdm_span == 1 && + tdm_api->tdm_chan == 1) { + gwrite_cnt++; + if (gwrite_cnt && + gwrite_cnt % 1000 == 0) { + DEBUG_EVENT("%s: WP_TDM API WRITE CODEC %i Len=%i\n", + tdm_api->name, gwrite_cnt, + wan_skb_len(skb)-sizeof(wp_tdm_api_tx_hdr_t)); + } + } +#endif + + wan_skb_queue_tail(&tdm_api->wp_tx_list, skb); + + return count; +} + + +static ssize_t wp_tdmapi_write(struct file *file, const char *usrbuf, size_t count, loff_t *ppos) +{ + struct iovec iovstack[WP_UIO_MAX_SZ]; + struct iovec *iov=iovstack; + struct msghdr msg_sys; + struct msghdr *msg = (struct msghdr*)usrbuf; + int err; + + WAN_ASSERT((file==NULL)); + WAN_ASSERT((usrbuf==NULL)); + + if (copy_from_user(&msg_sys,msg,sizeof(struct msghdr))) + return -EFAULT; + + if (msg_sys.msg_iovlen > WP_UIO_MAX_SZ) + return -EFAULT; + + msg_sys.msg_namelen=0; + + err=wan_verify_iovec(&msg_sys, iov, NULL, 0); + if (err < 0) { + return err; + } + + return wp_tdmapi_write_msg(file, &msg_sys, count); +} + + + +static int wp_tdmapi_release(struct inode *inode, struct file *file) +{ + wan_smp_flag_t flags; + wanpipe_tdm_api_dev_t *tdm_api = file->private_data; + + if (tdm_api == NULL || !wan_test_bit(0,&tdm_api->init)){ + return -ENODEV; + } + + wan_clear_bit(0,&tdm_api->used); + wp_wakeup_tdmapi(tdm_api); + + wan_spin_lock_irq(&tdm_api->lock,&flags); + + tdm_api->cfg.rbs_rx_bits=-1; + tdm_api->cfg.rbs_tx_bits=-1; + + tdm_api->cfg.rbs_poll=0; + + file->private_data=NULL; + + wan_spin_unlock_irq(&tdm_api->lock,&flags); + + + return 0; +} + +static int wp_tdmapi_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long data) +{ + struct ifreq ifr; + wanpipe_tdm_api_dev_t *tdm_api; + + WAN_ASSERT((file==NULL)); + + tdm_api = file->private_data; + if (tdm_api == NULL || !wan_test_bit(0,&tdm_api->init) || !wan_test_bit(0,&tdm_api->used)){ + return -ENODEV; + } + if (wan_test_bit(WP_TDM_DOWN,&tdm_api->critical)) { + return -ENODEV; + } + + if (data == 0){ + return -EINVAL; + } + + ifr.ifr_data=(void*)data; + + return wanpipe_tdm_api_ioctl(tdm_api, &ifr); + +} + +#ifdef DEBUG_API_POLL +#warning "POLL Debugging Enabled" +static int gpoll_cnt=0; +#endif +static unsigned int wp_tdmapi_poll(struct file *file, struct poll_table_struct *wait_table) +{ + int ret; + wanpipe_tdm_api_dev_t *tdm_api = file->private_data; + + if (tdm_api == NULL || !wan_test_bit(0,&tdm_api->init) || !wan_test_bit(0,&tdm_api->used)){ + return -ENODEV; + } + + if (wan_test_bit(WP_TDM_DOWN,&tdm_api->critical)) { + return -ENODEV; + } + + poll_wait(file, &tdm_api->poll_wait, wait_table); + ret = 0; + +#ifdef DEBUG_API_POLL + if (tdm_api->tdm_span == 1 && tdm_api->tdm_chan == 1) { + gpoll_cnt++; + if (gpoll_cnt && gpoll_cnt % 1000 == 0) { + DEBUG_EVENT("%s: WP_TDM POLL WAKEUP %i RxF=%i TxF=%i TxCE=%i TxE=%i TxP=%i\n", + tdm_api->name, gpoll_cnt, + wan_skb_queue_len(&tdm_api->wp_tx_free_list), + wan_skb_queue_len(&tdm_api->wp_rx_free_list), + tdm_api->cfg.stats.tx_carrier_errors, + tdm_api->cfg.stats.tx_errors, + tdm_api->cfg.stats.tx_packets); + } + } +#endif + + /* Tx Poll */ + if (!wan_test_bit(0,&tdm_api->cfg.tx_disable)){ + + if (tdm_api->hdlc_framing && + wan_skb_queue_len(&tdm_api->wp_tx_list) > tdm_api->tx_q_len && + !is_tdm_api_stopped(tdm_api)) { + wp_tdmapi_tx(tdm_api); + } + + if (wan_skb_queue_len(&tdm_api->wp_tx_list) <= tdm_api->tx_q_len) { + ret |= POLLOUT | POLLWRNORM; + } + } + + /* Rx Poll */ + if (!wan_test_bit(0,&tdm_api->cfg.rx_disable) && + wan_skb_queue_len(&tdm_api->wp_rx_list)) { + ret |= POLLIN | POLLRDNORM; + } + + if (tdm_api->cfg.rbs_poll){ + wanpipe_tdm_api_rbs_poll(tdm_api); + } + + if (wan_skb_queue_len(&tdm_api->wp_event_list)) { + /* Indicate an exception */ + ret |= POLLPRI; + } + + return(ret); +} + +static void wanpipe_tdm_api_rbs_poll(wanpipe_tdm_api_dev_t *tdm_api) +{ + + if (!tdm_api->cfg.rbs_poll) { + return; + } + + if (SYSTEM_TICKS-tdm_api->rbs_poll_cnt > tdm_api->cfg.rbs_poll) { + tdm_api->rbs_poll_cnt=SYSTEM_TICKS; + if (tdm_api->read_rbs_bits) { + u8 rbs_bits; +#if 0 + DEBUG_EVENT("%s: READING RBS 0x%lX %i\n", + tdm_api->name,SYSTEM_TICKS,tdm_api->cfg.stats.rx_errors); + tdm_api->cfg.stats.rx_errors=0; +#endif + tdm_api->read_rbs_bits(tdm_api->chan, tdm_api->tdm_chan, &rbs_bits); + if (tdm_api->cfg.rbs_rx_bits != rbs_bits) { + netskb_t *skb; + wp_tdm_api_rx_hdr_t *rx_hdr; + DEBUG_TEST("%s: RBS BITS CHANGED O=0x%X N=0x%X\n", + tdm_api->name, tdm_api->cfg.rbs_rx_bits, rbs_bits); + tdm_api->cfg.rbs_rx_bits = rbs_bits; + + if (wan_skb_queue_len(&tdm_api->wp_event_list) > + WP_TDM_MAX_EVENT_Q_LEN) { + return; + } + + skb=wan_skb_alloc(sizeof(wp_tdm_api_rx_hdr_t)); + if (skb) { + rx_hdr=(wp_tdm_api_rx_hdr_t*) + wan_skb_put(skb,sizeof(wp_tdm_api_rx_hdr_t)); + + memset(rx_hdr,0,sizeof(wp_tdm_api_rx_hdr_t)); + + rx_hdr->wp_api_event_rbs_rx_bits = tdm_api->cfg.rbs_rx_bits; + rx_hdr->wp_api_event_type = WP_TDM_EVENT_RBS; +#if 0 + /* FIXME: NENAD TO ADD Timestamp */ + rx_hdr->event_time_stamp = gettimeofday(); +#endif + wan_skb_queue_tail(&tdm_api->wp_event_list,skb); + } + } + } + } +} + +static int wanpipe_tdm_api_ioctl(wanpipe_tdm_api_dev_t *tdm_api, struct ifreq *ifr) +{ + wanpipe_tdm_api_cmd_t usr_tdm_api; + int err=0; + u32 cmd; + wanpipe_codec_ops_t *wp_codec_ops; + wan_smp_flag_t smp_flags; + netskb_t *skb; + wan_event_ctrl_t event_ctrl; + + if (!tdm_api->chan){ + DEBUG_EVENT("%s:%d Error: TDM API Not initialized! chan=NULL!\n", + __FUNCTION__,__LINE__); + return -EFAULT; + } + + if (!ifr){ + return -EINVAL; + } + + if (WAN_COPY_FROM_USER(&usr_tdm_api, + ifr->ifr_data, + sizeof(wanpipe_tdm_api_cmd_t))){ + return -EFAULT; + } + + cmd=usr_tdm_api.cmd; + + DEBUG_TEST("%s: TDM API CMD: %i\n",tdm_api->name,cmd); + + wan_spin_lock_irq(&tdm_api->lock,&smp_flags); + + if (tdm_api->hdlc_framing) { + switch (cmd) { + case SIOC_WP_TDM_GET_USR_MTU_MRU: + case SIOC_WP_TDM_GET_STATS: + case SIOC_WP_TDM_GET_FULL_CFG: + break; + default: + DEBUG_EVENT("%s: Invalid TDM API HDLC CMD %i\n", tdm_api->name,cmd); + err=-EOPNOTSUPP; + goto tdm_api_exit; + } + } + + switch (cmd) { + + case SIOC_WP_TDM_SET_HW_MTU_MRU: + err=-EOPNOTSUPP; + break; + + case SIOC_WP_TDM_GET_HW_MTU_MRU: + usr_tdm_api.hw_mtu_mru = tdm_api->cfg.hw_mtu_mru; + break; + + case SIOC_WP_TDM_SET_USR_PERIOD: + + if (usr_tdm_api.usr_period >= 10 && + (usr_tdm_api.usr_period % 10) == 0 && + usr_tdm_api.usr_period <= 1000) { + + usr_tdm_api.usr_mtu_mru = usr_tdm_api.usr_period*tdm_api->cfg.hw_mtu_mru; + + } else { + err = -EINVAL; + DEBUG_EVENT("%s: TDM API: Invalid HW Period %i!\n", + tdm_api->name,usr_tdm_api.usr_period); + goto tdm_api_exit; + } + + usr_tdm_api.usr_mtu_mru = wanpipe_codec_calc_new_mtu(tdm_api->cfg.tdm_codec, + usr_tdm_api.usr_mtu_mru); + tdm_api->cfg.usr_period = usr_tdm_api.usr_period; + tdm_api->cfg.usr_mtu_mru = usr_tdm_api.usr_mtu_mru; + break; + + case SIOC_WP_TDM_GET_USR_PERIOD: + + usr_tdm_api.usr_period = tdm_api->cfg.usr_period; + break; + + case SIOC_WP_TDM_GET_USR_MTU_MRU: + + usr_tdm_api.usr_mtu_mru = tdm_api->cfg.usr_mtu_mru; + break; + + case SIOC_WP_TDM_SET_CODEC: + + if (usr_tdm_api.tdm_codec == tdm_api->cfg.tdm_codec){ + err = 0; + goto tdm_api_exit; + } + + if (usr_tdm_api.tdm_codec < 0 || usr_tdm_api.tdm_codec >= WP_TDM_CODEC_MAX){ + err = -EINVAL; + goto tdm_api_exit; + } + + if (usr_tdm_api.tdm_codec == WP_NONE) { + + usr_tdm_api.usr_mtu_mru = tdm_api->cfg.hw_mtu_mru * tdm_api->cfg.usr_period; + + } else { + wp_codec_ops = WANPIPE_CODEC_OPS[tdm_api->cfg.hw_tdm_coding][usr_tdm_api.tdm_codec]; + if (!wp_codec_ops || !wp_codec_ops->init){ + + err = -EINVAL; + DEBUG_EVENT("%s: TDM API: Codec %i is unsupported!\n", + tdm_api->name,usr_tdm_api.tdm_codec); + goto tdm_api_exit; + } + usr_tdm_api.usr_mtu_mru = wanpipe_codec_calc_new_mtu(usr_tdm_api.tdm_codec, + tdm_api->cfg.usr_mtu_mru); + } + + tdm_api->cfg.usr_mtu_mru=usr_tdm_api.usr_mtu_mru; + tdm_api->cfg.tdm_codec = usr_tdm_api.tdm_codec; + break; + + case SIOC_WP_TDM_GET_CODEC: + usr_tdm_api.tdm_codec = tdm_api->cfg.tdm_codec; + break; + + case SIOC_WP_TDM_SET_POWER_LEVEL: + tdm_api->cfg.power_level = usr_tdm_api.power_level; + break; + + case SIOC_WP_TDM_GET_POWER_LEVEL: + usr_tdm_api.power_level = tdm_api->cfg.power_level; + break; + + case SIOC_WP_TDM_TOGGLE_RX: + if (tdm_api->cfg.tx_disable){ + wan_clear_bit(0,&tdm_api->cfg.rx_disable); + }else{ + wan_set_bit(0,&tdm_api->cfg.rx_disable); + } + break; + + case SIOC_WP_TDM_TOGGLE_TX: + if (tdm_api->cfg.tx_disable){ + wan_clear_bit(0,&tdm_api->cfg.tx_disable); + }else{ + wan_set_bit(0,&tdm_api->cfg.tx_disable); + } + break; + + case SIOC_WP_TDM_SET_EC_TAP: + + switch (usr_tdm_api.ec_tap){ + case 0: + case 32: + case 64: + case 128: + tdm_api->cfg.ec_tap = usr_tdm_api.ec_tap; + break; + + default: + DEBUG_EVENT("%s: Illegal Echo Cancellation Tap \n", + tdm_api->name); + err = -EINVAL; + goto tdm_api_exit; + } + break; + + case SIOC_WP_TDM_GET_EC_TAP: + usr_tdm_api.ec_tap = tdm_api->cfg.ec_tap; + break; + + case SIOC_WP_TDM_GET_STATS: + memcpy(&usr_tdm_api.stats,&tdm_api->cfg.stats,sizeof(tdm_api->cfg.stats)); + break; + + case SIOC_WP_TDM_GET_FULL_CFG: + memcpy(&usr_tdm_api,&tdm_api->cfg,sizeof(wanpipe_tdm_api_cmd_t)); + break; + + case SIOC_WP_TDM_ENABLE_RBS_EVENTS: + if (usr_tdm_api.rbs_poll < 20 || usr_tdm_api.rbs_poll > 100) { + DEBUG_EVENT("%s: Error: Invalid RBS Poll Count Min=20 Max=100\n", + tdm_api->name); + usr_tdm_api.rbs_poll=20; + } + usr_tdm_api.rbs_poll=HZ/usr_tdm_api.rbs_poll; + + tdm_api->cfg.rbs_poll = usr_tdm_api.rbs_poll; + break; + + case SIOC_WP_TDM_DISABLE_RBS_EVENTS: + tdm_api->cfg.rbs_poll=0; + break; + + case SIOC_WP_TDM_ENABLE_DTMF_EVENTS: + // Octasic DTMF event + DEBUG_TDMAPI("%s: Enable HW EC DTMF event %X!\n", + tdm_api->name, tdm_api->active_ch); + memset(&event_ctrl, 0, sizeof(wan_event_ctrl_t)); + event_ctrl.type = WAN_EVENT_ENABLE|WAN_EVENT_EC_DTMF; + event_ctrl.ts_map = tdm_api->active_ch; + if (tdm_api->event_ctrl){ + tdm_api->event_ctrl(tdm_api->chan, &event_ctrl); + } + break; + + case SIOC_WP_TDM_DISABLE_DTMF_EVENTS: + // Octasic DTMF event + DEBUG_TDMAPI("%s: Disable HW EC DTMF event!\n", + tdm_api->name); + memset(&event_ctrl, 0, sizeof(wan_event_ctrl_t)); + event_ctrl.type = WAN_EVENT_DISABLE|WAN_EVENT_EC_DTMF; + event_ctrl.ts_map = tdm_api->active_ch; + if (tdm_api->event_ctrl){ + tdm_api->event_ctrl(tdm_api->chan, &event_ctrl); + } + break; + + case SIOC_WP_TDM_ENABLE_RM_DTMF_EVENTS: + // A200-Remora DTMF event + DEBUG_TDMAPI("%s: Enable A200-Remora DTMF event!\n", + tdm_api->name); + memset(&event_ctrl, 0, sizeof(wan_event_ctrl_t)); + event_ctrl.type = WAN_EVENT_ENABLE|WAN_EVENT_RM_DTMF; + event_ctrl.mod_no = tdm_api->tdm_chan; + if (tdm_api->event_ctrl){ + tdm_api->event_ctrl(tdm_api->chan, &event_ctrl); + } + break; + case SIOC_WP_TDM_DISABLE_RM_DTMF_EVENTS: + // A200-Remora DTMF event + DEBUG_TDMAPI("%s: Disable A200-Remora DTMF event!\n", + tdm_api->name); + memset(&event_ctrl, 0, sizeof(wan_event_ctrl_t)); + event_ctrl.type = WAN_EVENT_DISABLE|WAN_EVENT_RM_DTMF; + event_ctrl.mod_no = tdm_api->tdm_chan; + if (tdm_api->event_ctrl){ + tdm_api->event_ctrl(tdm_api->chan, &event_ctrl); + } + break; + + + case SIOC_WP_TDM_ENABLE_RXHOOK_EVENTS: + DEBUG_TDMAPI("%s: Enable A200-Remora Loop Closure event!\n", + tdm_api->name); + memset(&event_ctrl, 0, sizeof(wan_event_ctrl_t)); + event_ctrl.type = WAN_EVENT_ENABLE|WAN_EVENT_RM_LC; + event_ctrl.mod_no = tdm_api->tdm_chan; + if (tdm_api->event_ctrl){ + tdm_api->event_ctrl(tdm_api->chan, &event_ctrl); + } + break; + + case SIOC_WP_TDM_DISABLE_RXHOOK_EVENTS: + DEBUG_TDMAPI("%s: Disable A200-Remora Loop Closure event!\n", + tdm_api->name); + memset(&event_ctrl, 0, sizeof(wan_event_ctrl_t)); + event_ctrl.type = WAN_EVENT_DISABLE|WAN_EVENT_RM_LC; + event_ctrl.mod_no = tdm_api->tdm_chan; + if (tdm_api->event_ctrl){ + tdm_api->event_ctrl(tdm_api->chan, &event_ctrl); + } + break; + + + case SIOC_WP_TDM_WRITE_RBS_BITS: + wan_spin_unlock_irq(&tdm_api->lock,&smp_flags); + + err=tdm_api->write_rbs_bits(tdm_api->chan, + tdm_api->tdm_chan, + usr_tdm_api.rbs_tx_bits); + if (err) { + DEBUG_EVENT("%s: WRITE RBS Error (%i)\n",tdm_api->name,err); + } + goto tdm_api_unlocked_exit; + break; + + case SIOC_WP_TDM_READ_EVENT: + skb=wan_skb_dequeue(&tdm_api->wp_event_list); + if (!skb){ + err=-ENOBUFS; + break; + } + memcpy(&usr_tdm_api.event,wan_skb_data(skb),sizeof(wp_tdm_api_rx_hdr_t)); + wan_skb_free(skb); + break; + + default: + DEBUG_EVENT("%s: Invalid TDM API CMD %i\n", tdm_api->name,cmd); + err=-EOPNOTSUPP; + break; + } + + +tdm_api_exit: + wan_spin_unlock_irq(&tdm_api->lock,&smp_flags); + +tdm_api_unlocked_exit: + if (WAN_COPY_TO_USER(ifr->ifr_data, + &usr_tdm_api, + sizeof(wanpipe_tdm_api_cmd_t))){ + return -EFAULT; + } + + + return err; +} + + + +static int wanpipe_tdm_api_tx (wanpipe_tdm_api_dev_t *tdm_api, u8 *tx_data, int len) +{ + u8 *buf; + wp_tdm_api_tx_hdr_t *tx_hdr; + + if (wan_test_bit(0,&tdm_api->cfg.tx_disable)){ + return 0; + } + + if (!tdm_api->tx_skb) { + tdm_api->tx_skb=wan_skb_dequeue(&tdm_api->wp_tx_list); + if (!tdm_api->tx_skb){ + memset(tx_data,tdm_api->cfg.idle_flag,len); + tdm_api->cfg.stats.tx_carrier_errors++; + return -ENOBUFS; + } + + buf=wan_skb_pull(tdm_api->tx_skb,sizeof(wp_tdm_api_tx_hdr_t)); + memcpy(&tdm_api->tx_hdr, buf, sizeof(wp_tdm_api_tx_hdr_t)); + + if (wan_skb_len(tdm_api->tx_skb) % len) { + wan_skb_free(tdm_api->tx_skb); + tdm_api->tx_skb=NULL; + tdm_api->cfg.stats.tx_errors++; + return -EINVAL; + } + } + + tx_hdr=&tdm_api->tx_hdr; + + buf=(u8*)wan_skb_data(tdm_api->tx_skb); + memcpy(tx_data,buf,len); + wan_skb_pull(tdm_api->tx_skb,len); + + if (wan_skb_len(tdm_api->tx_skb) <= 0) { + + /* Recycle the buffer so we dont have to realloc */ + wan_skb_push(tdm_api->tx_skb,sizeof(wp_tdm_api_tx_hdr_t)); + wan_skb_init(tdm_api->tx_skb,16); + wan_skb_trim(tdm_api->tx_skb,0); + wan_skb_queue_tail(&tdm_api->wp_tx_free_list,tdm_api->tx_skb); + + tdm_api->tx_skb=NULL; + tdm_api->cfg.stats.tx_packets++; + } + + return 0; +} + +static int wanpipe_tdm_api_rx (wanpipe_tdm_api_dev_t *tdm_api, u8 *rx_data, u8 *tx_data, int len) +{ + u8 *data_ptr; + wp_tdm_api_rx_hdr_t *rx_hdr; + int err=-EINVAL; + + if (wan_test_bit(0,&tdm_api->cfg.rx_disable)) { + err=0; + goto wanpipe_tdm_api_rx_error; + } + + if (wan_skb_queue_len(&tdm_api->wp_rx_list) > WP_TDM_MAX_RX_Q_LEN) { + tdm_api->cfg.stats.rx_fifo_errors++; + err=0; + goto wanpipe_tdm_api_rx_error; + } + + if (!tdm_api->rx_skb) { + tdm_api->rx_skb=wan_skb_dequeue(&tdm_api->wp_rx_free_list); + if (!tdm_api->rx_skb) { + tdm_api->rx_skb=wan_skb_alloc(WP_TDM_API_MAX_LEN); + if (!tdm_api->rx_skb){ + err=-ENOMEM; + tdm_api->cfg.stats.rx_errors++; + goto wanpipe_tdm_api_rx_error; + } + } + data_ptr=wan_skb_put(tdm_api->rx_skb,sizeof(wp_tdm_api_rx_hdr_t)); + } + + if (wan_skb_len(tdm_api->rx_skb)+len >= WP_TDM_API_MAX_LEN) { + err=-EINVAL; + tdm_api->cfg.stats.rx_errors++; + goto wanpipe_tdm_api_rx_error; + } + + rx_hdr=(wp_tdm_api_rx_hdr_t*)wan_skb_data(tdm_api->rx_skb); + + data_ptr=wan_skb_put(tdm_api->rx_skb,len); + memcpy((u8*)data_ptr,rx_data,len); + +#if 0 + if (tdm_api->cfg.tdm_codec == WP_NONE) { + + data_ptr=wan_skb_put(tdm_api->rx_skb,len); + memcpy((u8*)data_ptr,rx_data,len); + + } else { + wanpipe_codec_ops_t *wp_codec_ops; + wan_smp_flag_t smp_flags; + u32 power; + + wan_spin_lock_irq(&tdm_api->lock,&smp_flags); + + wp_codec_ops=WANPIPE_CODEC_OPS[tdm_api->cfg.hw_tdm_coding][tdm_api->cfg.tdm_codec]; + if (!wp_codec_ops || !wp_codec_ops->init){ + wan_spin_unlock_irq(&tdm_api->lock,&smp_flags); + err=-EINVAL; + tdm_api->cfg.stats.rx_errors++; + goto wanpipe_tdm_api_rx_error; + } + + wan_spin_unlock_irq(&tdm_api->lock,&smp_flags); + + data_ptr=(u8*)wan_skb_data(tdm_api->rx_skb); + + len = wp_codec_ops->encode(rx_data, + len, + (u16*)&data_ptr[wan_skb_len(tdm_api->rx_skb)], + &power, 0); + + if (len < 0){ + err=len; + tdm_api->cfg.stats.rx_errors++; + goto wanpipe_tdm_api_rx_error; + } + + wan_skb_put(tdm_api->rx_skb,len); + } +#endif + + if (wan_skb_len(tdm_api->rx_skb) >= + (tdm_api->cfg.usr_period*tdm_api->cfg.hw_mtu_mru + sizeof(wp_tdm_api_rx_hdr_t))) { + wan_skb_queue_tail(&tdm_api->wp_rx_list,tdm_api->rx_skb); + tdm_api->rx_skb=NULL; + wp_wakeup_tdmapi(tdm_api); + tdm_api->cfg.stats.rx_packets++; + } + + + return 0; + +wanpipe_tdm_api_rx_error: + + if (tdm_api->rx_skb) { + wan_skb_free(tdm_api->rx_skb); + } + + tdm_api->rx_skb=NULL; + return err; +} + + +int wanpipe_tdm_api_rx_tx (wanpipe_tdm_api_dev_t *tdm_api, u8 *rx_data, u8 *tx_data, int len) +{ + if (!tdm_api->chan || !wan_test_bit(0,&tdm_api->init)){ + return 0; + } + + if (!wan_test_bit(0,&tdm_api->used)) { + if (tx_data[0] != tdm_api->cfg.idle_flag) { + memset(tx_data,tdm_api->cfg.idle_flag,len); + } + return 0; + } + + wanpipe_tdm_api_rx (tdm_api, rx_data, tx_data, len); + wanpipe_tdm_api_tx (tdm_api, tx_data, len); + + + return 0; +} + +int wanpipe_tdm_api_rx_hdlc (wanpipe_tdm_api_dev_t *tdm_api, netskb_t *skb) +{ + if (wan_skb_queue_len(&tdm_api->wp_rx_list) > WP_TDM_MAX_RX_Q_LEN) { + tdm_api->cfg.stats.rx_fifo_errors++; + return -EBUSY; + } + + wan_skb_queue_tail(&tdm_api->wp_rx_list,skb); + wp_wakeup_tdmapi(tdm_api); + tdm_api->cfg.stats.rx_packets++; + return 0; +} + +static wanpipe_tdm_api_dev_t *wp_tdmapi_search(sdla_t *card, int fe_chan) +{ + wanpipe_tdm_api_dev_t *tdm_api; + int i = 0; + + for(i = 0; i < WP_TDMAPI_HASH_SZ; i++){ + tdm_api = wp_tdmapi_hash[i]; + + if (tdm_api->card != card) continue; + if (wan_test_bit(fe_chan, &tdm_api->active_ch)){ + return tdm_api; + } + } + return NULL; +} + +static void wp_tdmapi_rbsbits(void* card_id, int channel, unsigned char rbsbits) +{ + sdla_t *card = (sdla_t*)card_id; + + DEBUG_EVENT("ADBG> %s: Received RBS Event at TDM_API!\n", + card->devname); + return; +} + +static void wp_tdmapi_alarms(void* card_id, unsigned long alarams) +{ + sdla_t *card = (sdla_t*)card_id; + + DEBUG_EVENT("ADBG> %s: Received RBS Event at TDM_API!\n", + card->devname); + return; +} + +static void wp_tdmapi_dtmf (void* card_id, wan_event_t *event) +{ + netskb_t *skb = NULL; + wanpipe_tdm_api_dev_t *tdm_api = NULL; + sdla_t *card = (sdla_t*)card_id; + wp_tdm_api_rx_hdr_t *rx_hdr = NULL; + + if (event->type & WAN_EVENT_EC_DTMF){ + DEBUG_TDMAPI("%s: Received DTMF Event at TDM_API (%d:%c:%s:%s)!\n", + card->devname, + event->channel, + event->digit, + (event->ec_dtmf_port==WAN_EC_CHANNEL_PORT_ROUT)?"ROUT":"SOUT", + (event->ec_dtmf_type==WAN_EC_TONE_PRESENT)?"PRESENT":"STOP"); + }else if (event->type & WAN_EVENT_RM_DTMF){ + DEBUG_TDMAPI("%s: Received DTMF Event at TDM_API (%d:%c)!\n", + card->devname, + event->channel, + event->digit); + } + + tdm_api = wp_tdmapi_search(card, event->channel); + if (tdm_api == NULL){ + return; + } + + if (wan_skb_queue_len(&tdm_api->wp_event_list) > WP_TDM_MAX_EVENT_Q_LEN) { + return; + } + + skb=wan_skb_alloc(sizeof(wp_tdm_api_rx_hdr_t)); + if (skb == NULL) return; + + rx_hdr=(wp_tdm_api_rx_hdr_t*)wan_skb_put(skb,sizeof(wp_tdm_api_rx_hdr_t)); + memset(rx_hdr,0,sizeof(wp_tdm_api_rx_hdr_t)); + rx_hdr->wp_api_event_type = WP_TDM_EVENT_DTMF; + rx_hdr->wp_api_event_dtmf_digit = event->digit; + rx_hdr->wp_api_event_dtmf_type = event->dtmf_type; + rx_hdr->wp_api_event_dtmf_port = event->dtmf_port; +#if 0 + rx_hdr->event_time_stamp = gettimeofday(); +#endif + wan_skb_queue_tail(&tdm_api->wp_event_list,skb); + return; +} + +static void wp_tdmapi_hook (void* card_id, wan_event_t *event) +{ + netskb_t *skb; + wanpipe_tdm_api_dev_t *tdm_api = NULL; + sdla_t *card = (sdla_t*)card_id; + wp_tdm_api_rx_hdr_t *rx_hdr = NULL; + + DEBUG_TDMAPI("%s: Received RM LC Event at TDM_API (%d:%s)!\n", + card->devname, + event->channel, + (event->rxhook==WAN_EVENT_RXHOOK_OFF)?"OFF-HOOK":"ON-HOOK"); + + + tdm_api = wp_tdmapi_search(card, event->channel); + if (tdm_api == NULL){ + return; + } + + if (wan_skb_queue_len(&tdm_api->wp_event_list) > WP_TDM_MAX_EVENT_Q_LEN) { + return; + } + + skb=wan_skb_alloc(sizeof(wp_tdm_api_rx_hdr_t)); + if (skb == NULL) return; + rx_hdr=(wp_tdm_api_rx_hdr_t*)wan_skb_put(skb,sizeof(wp_tdm_api_rx_hdr_t)); + memset(rx_hdr,0,sizeof(wp_tdm_api_rx_hdr_t)); + rx_hdr->wp_api_event_type = WP_TDM_EVENT_RXHOOK; + rx_hdr->wp_api_event_rxhook_state = event->rxhook; + +#if 0 + rx_hdr->event_time_stamp = gettimeofday(); +#endif + wan_skb_queue_tail(&tdm_api->wp_event_list,skb); + wp_wakeup_tdmapi(tdm_api); + return; +} + +static void wp_tdmapi_ringtrip (void* card_id, wan_event_t *event) +{ + netskb_t *skb; + wanpipe_tdm_api_dev_t *tdm_api = NULL; + sdla_t *card = (sdla_t*)card_id; + wp_tdm_api_rx_hdr_t *rx_hdr = NULL; + + DEBUG_TDMAPI("%s: Received RM RING TRIP Event at TDM_API (%d:%s)!\n", + card->devname, + event->channel, + (event->rxhook==WAN_EVENT_RM_RING_PRESENT)?"PRESETN":"STOP"); + + tdm_api = wp_tdmapi_search(card, event->channel); + if (tdm_api == NULL){ + return; + } + + if (wan_skb_queue_len(&tdm_api->wp_event_list) > WP_TDM_MAX_EVENT_Q_LEN) { + return; + } + + skb=wan_skb_alloc(sizeof(wp_tdm_api_rx_hdr_t)); + if (skb == NULL) { + return; + } + + rx_hdr=(wp_tdm_api_rx_hdr_t*)wan_skb_put(skb,sizeof(wp_tdm_api_rx_hdr_t)); + memset(rx_hdr,0,sizeof(wp_tdm_api_rx_hdr_t)); + rx_hdr->wp_api_event_type = WP_TDM_EVENT_RING; + rx_hdr->wp_api_event_ring_state = event->rxhook; + +#if 0 + rx_hdr->event_time_stamp = gettimeofday(); +#endif + wan_skb_queue_tail(&tdm_api->wp_event_list,skb); + wp_wakeup_tdmapi(tdm_api); + return; +} + +#else + +int wanpipe_tdm_api_reg(wanpipe_tdm_api_dev_t *tdm_api) +{ + return -EINVAL; +} + +int wanpipe_tdm_api_unreg(wanpipe_tdm_api_dev_t *tdm_api) +{ + return -EINVAL; +} + +int wanpipe_tdm_api_update_state(wanpipe_tdm_api_dev_t *tdm_api, int state) +{ + return -ENODEV; +} + +int wanpipe_tdm_api_kick(wanpipe_tdm_api_dev_t *tdm_api) +{ + return -EINVAL; +} + +int wanpipe_tdm_api_rx_hdlc (wanpipe_tdm_api_dev_t *tdm_api, netskb_t *skb) +{ + return -EINVAL; +} + +int wanpipe_tdm_api_rx_tx (wanpipe_tdm_api_dev_t *tdm_api, u8 *rx_data, u8 *tx_data, int len) +{ + return -EINVAL; +} + +#endif diff -Nur linux.org/drivers/net/wan/wanpipe_utils.c linux-2.6.17/drivers/net/wan/wanpipe_utils.c --- linux.org/drivers/net/wan/wanpipe_utils.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/drivers/net/wan/wanpipe_utils.c 2006-08-30 10:07:17.000000000 +0000 @@ -0,0 +1,1434 @@ +/* + * Copyright (c) 1997, 1998, 1999 + * Alex Feldman . All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Alex Feldman. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Alex Feldman AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Alex Feldman OR THE VOICES IN HIS HEAD + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + * $Id$ + */ + +/* + **************************************************************************** + * wan_utils.c WANPIPE(tm) Multiprotocol WAN Utilities. + * + * Author: Alex Feldman + * + * =========================================================================== + * July 29, 2002 Alex Feldman Initial version. + **************************************************************************** +*/ + +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) +# include +# if !defined(CONFIG_PRODUCT_WANPIPE_GENERIC) +# include +# endif +# include +# include /* WANPIPE common user API definitions */ +#elif (defined __WINDOWS__) +# include +#elif (defined __KERNEL__) +# include +# include +# include +# include +# if !defined(CONFIG_PRODUCT_WANPIPE_GENERIC) +# include +# include +# include +# endif +#else +# error "Unsupported Operating System!" +#endif + + +#ifdef __OpenBSD__ +# define read_eflags() ({ register u_long ef; \ + __asm("pushfl; popl %0" : "=r" (ef)); \ + ef;}) +# define write_eflags(x)({register u_long ef = (x); \ + __asm("pushl %0; popfl" : : "r" (ef));}) +#endif + +/* +** Function prototypes. +*/ +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) +static void wanpipe_debug_timer(void* arg); +#else +static void wanpipe_debug_timer(unsigned long arg); +#endif + +extern sdla_t* wanpipe_debug; +int wan_get_dbg_msg(wan_device_t* wandev, void* u_dbg_msg); + + +unsigned char wp_brt[256]; + +static void wan_generate_bit_rev_table(void) +{ + unsigned char util_char; + unsigned char misc_status_byte; + int i; + + /* generate the bit-reversing table for all unsigned characters */ + for(util_char = 0;; util_char ++) { + misc_status_byte = 0; /* zero the character to be 'built' */ + /* process all 8 bits of the source byte and generate the */ + for(i = 0; i <= 7; i ++) { + /* corresponding 'bit-flipped' character */ + if(util_char & (1 << i)) { + misc_status_byte |= (1 << (7 - i)); + } + } + /* insert the 'bit-flipped' character into the table + * at the appropriate location */ + wp_brt[util_char] = misc_status_byte; + + /* exit when all unsigned characters have been processed */ + if(util_char == 0xFF) { + break; + } + } +} + + + +/*============================================================================ + * Convert decimal string to unsigned integer. + * If len != 0 then only 'len' characters of the string are converted. + */ +unsigned int wan_dec2uint (unsigned char* str, int len) +{ + unsigned val; + + if (!len) + len = strlen(str); + + for (val = 0; len && is_digit(*str); ++str, --len) + val = (val * 10) + (*str - (unsigned)'0'); + + return val; +} + +/* + * ============================================================================ + * Get WAN device state. + */ +char* wanpipe_get_state_string (void* card_id) +{ + sdla_t* card = (sdla_t*)card_id; + + switch(card->wandev.state){ + case WAN_UNCONFIGURED: + return "Unconfigured"; + case WAN_DISCONNECTED: + return "Disconnected"; + case WAN_CONNECTING: + return "Connecting"; + case WAN_CONNECTED: + return "Connected"; + case WAN_DISCONNECTING: + return "disconnecting"; + case WAN_FT1_READY: + return "FT1 Ready"; + } + return "Unknown"; +} + +/* + * ============================================================================ + * Get WAN device state. + */ +char wanpipe_get_state (void* card_id) +{ + sdla_t* card = (sdla_t*)card_id; + + return card->wandev.state; +} + +/* + * ============================================================================ + * Get WAN device state. + */ +void wanpipe_set_baud (void* card_id, unsigned int baud) +{ + sdla_t* card = (sdla_t*)card_id; + + /* Setup for bps */ + card->wandev.bps=baud*1000; +} + + +/* + * ============================================================================ + * Set WAN device state. + */ +void wanpipe_set_state (void* card_id, int state) +{ + sdla_t* card = (sdla_t*)card_id; + if (card->wandev.state != state){ + switch (state){ + case WAN_CONNECTED: + DEBUG_EVENT("%s: Link connected!\n", card->devname); + card->wan_debugging_state = WAN_DEBUGGING_NONE; + break; + + case WAN_CONNECTING: + DEBUG_EVENT("%s: Link connecting...\n", card->devname); + break; + + case WAN_DISCONNECTED: + DEBUG_EVENT("%s: Link disconnected!\n", card->devname); + break; + } + card->wandev.state = state; + } + card->state_tick = SYSTEM_TICKS; +} + +/* + * ============================================================================ + * Check if packet is UDP packet or not. + */ +int wan_udp_pkt_type(void* card_id, caddr_t ptr) +{ + sdla_t* card = (sdla_t*)card_id; + wan_udp_pkt_t* wan_udp_pkt = (wan_udp_pkt_t*)ptr; + unsigned int udp_port = card->wandev.udp_port; + + DEBUG_UDP("%s: Ver 0x%x Prot 0x%x UDP type %d Req 0x%x\n", + card->devname, + wan_udp_pkt->wan_ip_v, + wan_udp_pkt->wan_ip_p, + wan_udp_pkt->wan_udp_dport, + wan_udp_pkt->wan_udp_request_reply); + + if (wan_udp_pkt->wan_ip_v == 0x04 && + wan_udp_pkt->wan_ip_p == UDPMGMT_UDP_PROTOCOL && + wan_udp_pkt->wan_udp_dport == ntohs(udp_port) && + wan_udp_pkt->wan_udp_request_reply == UDPMGMT_REQUEST){ + + if (!strncmp(wan_udp_pkt->wan_udp_signature, + GLOBAL_UDP_SIGNATURE, + GLOBAL_UDP_SIGNATURE_LEN)){ + return 0; + } + } + return UDP_INVALID_TYPE; +} + +/* + * ============================================================================ + * Calculate packet checksum. + */ +unsigned short wan_calc_checksum(char *data, int len) +{ + unsigned short temp; + u_int32_t sum = 0; + int i; + + for(i=0; i < len; i += 2){ + memcpy(&temp, &data[i], 2); + sum += (u_int32_t)temp; + } + + while(sum >> 16){ + sum = (sum & 0xffffUL) + (sum >> 16); + } + + temp = (unsigned short)sum; + temp = ~temp; + + if (temp == 0){ + temp = 0xFFFF; + } + + return temp; +} + +/* + * =========================================================================== + * Reply to UDP Management system. + * Agruments: + * mbox_len - includes data length and trace_info_t (chdlc and dsl). + * Return length of reply. + */ +int wan_reply_udp(void* card_id, unsigned char *data, unsigned int mbox_len) +{ + sdla_t* card = (sdla_t*)card_id; + wan_udp_pkt_t* udp_pkt = (wan_udp_pkt_t*)data; + u_int32_t ip_temp; + unsigned short len, + udp_length, + temp, + ip_length; + int even_bound = 0; + + + /* fill in UDP reply */ + udp_pkt->wan_udp_request_reply = UDPMGMT_REPLY; + + /* fill in UDP length */ + udp_length = + sizeof(struct udphdr) + + sizeof(wan_mgmt_t) + + sizeof(wan_cmd_t) + + mbox_len; + + if (card->wandev.config_id == WANCONFIG_CHDLC || + card->wandev.config_id == WANCONFIG_SDLC){ + udp_length += sizeof(wan_trace_info_t); + } + + /* Set length of packet */ +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) + len = sizeof(struct ip) + udp_length; +#else + len = sizeof(struct iphdr) + udp_length; +#endif + + /* put it on an even boundary */ + if (udp_length & 0x0001){ + udp_length += 1; + len += 1; + even_bound = 1; + } + + temp = (udp_length<<8)|(udp_length>>8); + udp_pkt->wan_udp_len = temp; + + /* swap UDP ports */ + temp = udp_pkt->wan_udp_sport; + udp_pkt->wan_udp_sport = udp_pkt->wan_udp_dport; + udp_pkt->wan_udp_dport = temp; + + /* add UDP pseudo header */ + temp = 0x1100; + *((unsigned short*)(udp_pkt->wan_udp_data + mbox_len + even_bound)) = temp; + temp = (udp_length<<8)|(udp_length>>8); + *((unsigned short*)(udp_pkt->wan_udp_data + mbox_len + even_bound + 2)) = temp; + + /* calculate UDP checksum */ + udp_pkt->wan_udp_sum = 0; + udp_pkt->wan_udp_sum = + wan_calc_checksum(&data[UDP_OFFSET], + udp_length + UDP_OFFSET); + + /* fill in IP length */ + ip_length = len; + temp = (ip_length<<8)|(ip_length>>8); + udp_pkt->wan_ip_len = temp; + + /* swap IP addresses */ + ip_temp = udp_pkt->wan_ip_src; + udp_pkt->wan_ip_src = udp_pkt->wan_ip_dst; + udp_pkt->wan_ip_dst = ip_temp; + + /* fill in IP checksum */ + udp_pkt->wan_ip_sum = 0; +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) + udp_pkt->wan_ip_sum = wan_calc_checksum(data, sizeof(struct ip)); +#else + udp_pkt->wan_ip_sum = wan_calc_checksum(data, sizeof(struct iphdr)); +#endif + + return len; +} /* wan_reply_udp */ + +/* +***************************************************************************** +** +** +*/ + +/* +** Initialize WANPIPE debug timer +*/ +void wanpipe_debug_timer_init(void* card_id) +{ + sdla_t* card = (sdla_t*)card_id; + wan_init_timer(&card->debug_timer, + wanpipe_debug_timer, + (wan_timer_arg_t)card); + return; +} + + +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) +static void wanpipe_debug_timer(void* arg) +#else +static void wanpipe_debug_timer(unsigned long arg) +#endif +{ + sdla_t* card = (sdla_t*)arg; + wan_tasklet_t* debug_task = NULL; + /* + ** I should set running flag to zero in order to + ** schedule this task. I don't care if after setting + ** this flag to zero, the same task can be scheduled from + ** another place before I'll try to do this here, only + ** one task will go through and the result will be same. + */ + WAN_ASSERT1(card == NULL); + debug_task = &card->debug_task; + if (card->wandev.state == WAN_UNCONFIGURED){ + return; + } + WAN_TASKLET_END(debug_task); + WAN_TASKLET_SCHEDULE(debug_task); +} + +/* +***************************************************************************** +** +** +*/ +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) +void wanpipe_debugging (void* data, int pending) +#else +void wanpipe_debugging (unsigned long data) +#endif +{ + sdla_t* card = (sdla_t*)data; + wan_tasklet_t* debug_task = NULL; + static u_int32_t CRC_frames = 0, abort_frames = 0; + static u_int32_t tx_underun_frames = 0; + int delay = 0; + + WAN_ASSERT1(card == NULL); + if (card->wandev.state == WAN_UNCONFIGURED){ + goto wanpipe_debugging_end; + } + if (card->wandev.state == WAN_CONNECTED){ + /* + ** Terminate sequence because link comes UP. + */ + DEBUG_DBG("%s: WAN_DBG: Link came UP before the end of the DEBUG sequence!\n", + card->devname); + goto wanpipe_debugging_end; + } + if (card->wan_debugging_state == WAN_DEBUGGING_NONE || + card->wan_debugging_state == WAN_DEBUGGING_AGAIN){ + DEBUG_DBG("%s: WAN_DBG: Debugging state is %s!\n", + card->devname, + (card->wan_debugging_state == WAN_DEBUGGING_NONE) ? "Start":"Again"); + card->wan_debugging_state = WAN_DEBUGGING_START; + } + if (IS_TE1_CARD(card) || IS_56K_CARD(card)){ + u_int32_t status; + /* Sangoma T1/E1/56K cards */ + /* Check Tv attributes */ + if (card->wandev.fe_iface.read_alarm){ + card->wandev.fe_iface.read_alarm(&card->fe, 0); + } + if (card->wandev.fe_iface.read_alarm && + (status = card->wandev.fe_iface.read_alarm(&card->fe, 0))){ + DEBUG_DBG("%s: WAN_DBG: T1/E1/56K is not in Service, print Alarms!\n", + card->devname); + /* Not in service, Alarms */ + if (card->wan_debug_last_msg != WAN_DEBUG_ALARM_MSG){ + card->wandev.fe_iface.print_fe_alarm(&card->fe, status); + DEBUG_EVENT("%s: Line for WANPIPEn is down.\n", + card->devname); + DEBUG_EVENT("%s: All WANPIPEn interfaces down.\n", + card->devname); + DEBUG_EVENT("%s: Tell your Telco about your\n", + card->devname); + DEBUG_EVENT("%s: ALARM condition.\n", + card->devname); + } + card->wan_debug_last_msg = WAN_DEBUG_ALARM_MSG; + }else{ + /* In service, no Alarms */ + switch(card->wan_debugging_state){ + case WAN_DEBUGGING_START: + DEBUG_DBG("%s: WAN_DBG: T1/E1/56K in Service, reading statistics...\n", + card->devname); + /* Read number of CRC, abort and tx frames */ + CRC_frames = card->get_crc_frames(card); + abort_frames = card->get_abort_frames(card); + tx_underun_frames = card->get_tx_underun_frames(card); + card->wan_debugging_state = WAN_DEBUGGING_CONT; + wan_add_timer(&card->debug_timer, 15*HZ); + return; + break; + + case WAN_DEBUGGING_CONT: + if (IS_TE1_CARD(card) && + ((card->get_crc_frames(card) != CRC_frames) || + (card->get_abort_frames(card) != abort_frames))){ + DEBUG_DBG("%s: WAN_DBG: T1/E1/56K in Service, RX CRC/Abort frames!\n", + card->devname); + /* CRC/Abort frames, Probably incorrect channel config */ + if (card->wan_debug_last_msg != WAN_DEBUG_TE1_MSG){ + DEBUG_EVENT("%s: T1/E1 channel set-up is wrong!\n", + card->devname); + DEBUG_EVENT("%s: Your current channel configuration is %s!\n", + card->devname, + card->wandev.fe_iface.print_fe_act_channels(&card->fe)); + DEBUG_EVENT("%s: Have your Telco check the \n", + card->devname); + DEBUG_EVENT("%s: active DS0 channels on your line.\n", + card->devname); + } + card->wan_debug_last_msg = WAN_DEBUG_TE1_MSG; + }else{ + /* no CRC/Abort frames */ + goto line_down_without_DSU_CSU_error; + } + break; + + case WAN_DEBUGGING_PROTOCOL: + DEBUG_DBG("%s: WAN_DBG: Debugging protocol level...\n", + card->devname); + if (card->wan_debugging){ + delay = card->wan_debugging(card); + } + break; + } + } + }else{ + /* Sangoma Serial cards */ + switch(card->wan_debugging_state){ + case WAN_DEBUGGING_START: + DEBUG_DBG("%s: WAN_DBG: Serial card, reading statistics...\n", + card->devname); + /* Check CRC and abort stats for 15 second */ + CRC_frames = card->get_crc_frames(card); + abort_frames = card->get_abort_frames(card); + tx_underun_frames = card->get_tx_underun_frames(card); + card->wan_debugging_state = WAN_DEBUGGING_CONT; + wan_add_timer(&card->debug_timer, 15*HZ); + return; + break; + + case WAN_DEBUGGING_CONT: + if ((card->get_crc_frames(card) != CRC_frames) || + (card->get_abort_frames(card) != abort_frames)){ + DEBUG_DBG("%s: WAN_DBG: Serial card, RX CRC/Abort frames!\n", + card->devname); + /* CRC/Abort frames, Probably incorrect channel config */ + if (card->wandev.clocking == WANOPT_EXTERNAL){ + if (card->wan_debug_last_msg != WAN_DEBUG_LINERROR_MSG){ + /* External clocking */ + DEBUG_EVENT("%s: Your line is experiencing errors!\n", + card->devname); + DEBUG_EVENT("%s: Check your DSU/CSU and line configuration\n", + card->devname); + DEBUG_EVENT("%s: with your Telco.\n", + card->devname); + } + card->wan_debug_last_msg = WAN_DEBUG_LINERROR_MSG; + }else{ + /* Internal clocking */ + if (card->wan_debug_last_msg != WAN_DEBUG_CLK_MSG){ + DEBUG_EVENT("%s: You are set for Internal clocking, \n", + card->devname); + DEBUG_EVENT("%s: causing line errors!\n", + card->devname); + DEBUG_EVENT("%s: Set to External clocking except for\n", + card->devname); + DEBUG_EVENT("%s: back-to-back testing!\n", + card->devname); + } + card->wan_debug_last_msg = WAN_DEBUG_CLK_MSG; + } + }else{ + /* no CRC/Abort frames */ + goto line_down_without_DSU_CSU_error; + } + break; + + case WAN_DEBUGGING_PROTOCOL: + DEBUG_DBG("%s: WAN_DBG: Debugging protocol level...\n", + card->devname); + if (card->wan_debugging){ + delay = card->wan_debugging(card); + } + break; + } + } + /* Link is down because DSU/CSU errors */ + goto wanpipe_debugging_end; + +line_down_without_DSU_CSU_error: + /* Link is down (no DSU/CSU errors) - may be protocol problem */ + if (card->get_tx_underun_frames(card) != tx_underun_frames){ + DEBUG_DBG("%s: WAN_DBG: No TX frames!\n", + card->devname); + if (card->wan_debug_last_msg != WAN_DEBUG_TX_MSG){ + DEBUG_EVENT("%s: WAN port is not transmitting!\n", + card->devname); + DEBUG_EVENT("%s: No TX clock from DSU/CSU.\n", + card->devname); + DEBUG_EVENT("%s: Check your cable with your DSU/CSU supplier.\n", + card->devname); + } + card->wan_debug_last_msg = WAN_DEBUG_TX_MSG; + }else{ + if (card->wan_debugging){ + delay = card->wan_debugging(card); + } + if (card->wan_debugging_state == WAN_DEBUGGING_PROTOCOL){ + wan_add_timer(&card->debug_timer, delay*HZ); + return; + } + } + goto wanpipe_debugging_end; + +wanpipe_debugging_end: + /* + ** WANPIPE debugging task is finished. Clear debugging flag! + */ + card->wan_debugging_state = WAN_DEBUGGING_NONE; + debug_task = &card->debug_task; + WAN_TASKLET_END(debug_task); + if (card->wandev.state != WAN_CONNECTED && card->wandev.state != WAN_UNCONFIGURED){ + /* + ** Repeat the WANPIPE debugging task in next 60 seconds. + */ + card->wan_debugging_state = WAN_DEBUGGING_AGAIN; + wan_add_timer(&card->debug_timer, WAN_DEBUGGING_DELAY*HZ); + }else{ + /* + ** Link is connected, We don't need to remember the last message + */ + card->wan_debug_last_msg = WAN_DEBUG_NONE_MSG; + WAN_DEBUG_STOP(card); + } + return; +} + +/* ALEX_DEBUG */ +void wan_debug_trigger(int flag) +{ + if (wanpipe_debug == NULL){ + return; + } + switch(flag){ + case WAN_DEBUG_SET_TRIGGER: + wan_set_bit(WAN_DEBUG_TRIGGER, &wanpipe_debug->u.debug.status); + break; + + case WAN_DEBUG_CLEAR_TRIGGER: + wan_clear_bit(WAN_DEBUG_TRIGGER, &wanpipe_debug->u.debug.status); + break; + } + return; +} + +void wan_debug_write(char* msg) +{ + wanpipe_kernel_msg_info_t wan_debug_info; + wanpipe_kernel_msg_hdr_t wan_dbg; + int len = strlen(msg); + wan_smp_flag_t smp_flags; + + if (wanpipe_debug == NULL || !wanpipe_debug->configured){ + return; + } + if (!wan_test_bit(WAN_DEBUG_TRIGGER, &wanpipe_debug->u.debug.status)){ + /* No Debug Trigger */ + return; + } + if (wan_test_bit(WAN_DEBUG_READING, &wanpipe_debug->u.debug.status) || + wan_test_bit(WAN_DEBUG_FULL, &wanpipe_debug->u.debug.status)){ + /* We cannot add new message! */ + return; + } + if (len == 0){ + DEBUG_EVENT("wan_debug_write: Debug message is empty!\n"); + return; + } + wan_spin_lock_irq(&wanpipe_debug->wandev.lock, &smp_flags); + + wanpipe_debug->hw_iface.peek(wanpipe_debug->hw, 0, &wan_debug_info, sizeof(wanpipe_kernel_msg_info_t)); + if (wan_debug_info.magic != ROUTER_MAGIC || wanpipe_debug->u.debug.total_len == 0){ + wan_debug_info.magic = ROUTER_MAGIC; + wan_debug_info.total_len = 0; + wanpipe_debug->hw_iface.poke(wanpipe_debug->hw, 0, + &wan_debug_info, sizeof(wanpipe_kernel_msg_info_t)); + wanpipe_debug->u.debug.total_len = 0; + wanpipe_debug->u.debug.total_num = 0; + wanpipe_debug->u.debug.current_offset = sizeof(wanpipe_kernel_msg_info_t); + } + if (wan_debug_info.total_len + sizeof(wanpipe_kernel_msg_info_t) + len > (256 * 1024)){ + DEBUG_EVENT("wan_debug_write: There are no enought memory (%ld)!\n", + wan_debug_info.total_len); + DEBUG_EVENT("wan_debug_write: Disable debug message output!\n"); + wan_set_bit(WAN_DEBUG_FULL, &wanpipe_debug->u.debug.status); + goto wan_debug_write_done; + } + wan_dbg.len = len; + wan_getcurrenttime(&wan_dbg.time, NULL); + wanpipe_debug->hw_iface.poke(wanpipe_debug->hw, + wanpipe_debug->u.debug.total_len+sizeof(wanpipe_kernel_msg_info_t), + &wan_dbg, + sizeof(wanpipe_kernel_msg_hdr_t)); + wanpipe_debug->u.debug.total_len += sizeof(wanpipe_kernel_msg_hdr_t); + wanpipe_debug->hw_iface.poke(wanpipe_debug->hw, + wanpipe_debug->u.debug.total_len+sizeof(wanpipe_kernel_msg_info_t), + msg, + len); + wanpipe_debug->u.debug.total_len += len; + wanpipe_debug->u.debug.total_num ++; + wan_debug_info.total_len = wanpipe_debug->u.debug.total_len; + wanpipe_debug->hw_iface.poke(wanpipe_debug->hw, + 0, + &wan_debug_info, + sizeof(wanpipe_kernel_msg_info_t)); +wan_debug_write_done: + wan_spin_unlock_irq(&wanpipe_debug->wandev.lock, &smp_flags); + return; +} + +int wan_debug_read(void* device, void* u_dbg_msg) +{ + wanpipe_kernel_msg_info_t wan_debug_info; + wan_kernel_msg_t dbg_msg; + wanpipe_kernel_msg_hdr_t* wan_dbg; + char* data = NULL; + unsigned long next_offset = 0, offset = 0; + int read_done = 0, err = 0; + wan_smp_flag_t smp_flags; + + if (!wanpipe_debug || wanpipe_debug->wandev.state == WAN_UNCONFIGURED){ + return -EINVAL; + } + wan_spin_lock_irq(&wanpipe_debug->wandev.lock, &smp_flags); + /* We are busy to read all debug message. Do not add new messages yet! */ + if (!wan_test_bit(WAN_DEBUG_READING, &wanpipe_debug->u.debug.status)){ + wan_set_bit(WAN_DEBUG_READING, &wanpipe_debug->u.debug.status); + DEBUG_DBG("wan_debug_read: Number of debug messages %ld\n", + wanpipe_debug->u.debug.total_num); + } + if (WAN_COPY_FROM_USER((void*)&dbg_msg, (void*)u_dbg_msg, sizeof(wan_kernel_msg_t))){ + wan_clear_bit(WAN_DEBUG_READING, &wanpipe_debug->u.debug.status); + err = -EFAULT; + goto wan_get_dbg_msg_error; + } + + if (dbg_msg.magic != ROUTER_MAGIC){ + wan_clear_bit(WAN_DEBUG_READING, &wanpipe_debug->u.debug.status); + err = -EINVAL; + goto wan_get_dbg_msg_error; + } + if ((data = wan_malloc(dbg_msg.max_len)) == NULL){ + wan_clear_bit(WAN_DEBUG_READING, &wanpipe_debug->u.debug.status); + err = -ENOMEM; + goto wan_get_dbg_msg_error; + } + + wanpipe_debug->hw_iface.peek(wanpipe_debug->hw, 0, + &wan_debug_info, sizeof(wanpipe_kernel_msg_info_t)); + if (wan_debug_info.total_len == 0 || wan_debug_info.magic != ROUTER_MAGIC){ + DEBUG_DBG("%s: There are no debug messages!\n", + wanpipe_debug->devname); + dbg_msg.len = 0; + goto wan_get_dbg_msg_done; + } + next_offset = wanpipe_debug->u.debug.current_offset; + if (wan_debug_info.total_len-next_offset > dbg_msg.max_len){ + dbg_msg.is_more = 1; + } + + do { + wanpipe_debug->hw_iface.peek(wanpipe_debug->hw, next_offset, + &data[offset], sizeof(wanpipe_kernel_msg_hdr_t)); + wan_dbg = (wanpipe_kernel_msg_hdr_t*)&data[offset]; + if (wan_dbg->len == 0){ + DEBUG_DBG("wan_debug_read: Debug msg is empty!\n"); + } + if (offset + sizeof(wanpipe_kernel_msg_hdr_t) + wan_dbg->len < dbg_msg.max_len){ + next_offset += sizeof(wanpipe_kernel_msg_hdr_t); + offset += sizeof(wanpipe_kernel_msg_hdr_t); + wanpipe_debug->hw_iface.peek(wanpipe_debug->hw, next_offset, &data[offset], wan_dbg->len); + next_offset += wan_dbg->len; + offset += wan_dbg->len; + dbg_msg.num ++; + }else{ + read_done = 1; + } + if (next_offset >= wan_debug_info.total_len){ + read_done = 1; + } + }while(!read_done); + wanpipe_debug->u.debug.current_offset = next_offset; + +wan_get_dbg_msg_done: + if (offset){ + if (WAN_COPY_TO_USER((void*)dbg_msg.data, (void*)data, offset)){ + err = -EFAULT; + goto wan_get_dbg_msg_done; + } + } + dbg_msg.len = offset; + if (!dbg_msg.is_more){ + DEBUG_DBG("%s: There are no more debug messages!\n", + wanpipe_debug->devname); + wan_debug_info.magic = ROUTER_MAGIC; + wan_debug_info.total_len = 0; + wanpipe_debug->u.debug.current_offset = + sizeof(wanpipe_kernel_msg_info_t); + wanpipe_debug->u.debug.total_len = 0; + wanpipe_debug->u.debug.total_num = 0; + wanpipe_debug->hw_iface.poke(wanpipe_debug->hw, 0, + &wan_debug_info, sizeof(wanpipe_kernel_msg_info_t)); + if (wan_test_bit(WAN_DEBUG_FULL, &wanpipe_debug->u.debug.status)){ + DEBUG_EVENT("wan_debug_write: Enable debug message output!\n"); + wan_clear_bit(WAN_DEBUG_FULL, &wanpipe_debug->u.debug.status); + } + wan_clear_bit(WAN_DEBUG_READING, &wanpipe_debug->u.debug.status); + } + if (WAN_COPY_TO_USER((void*)u_dbg_msg, (void*)&dbg_msg, sizeof(wan_kernel_msg_t))){ + err = -EFAULT; + goto wan_get_dbg_msg_done; + } +wan_get_dbg_msg_error: + if (data){ + wan_free(data); + } + wan_spin_unlock_irq(&wanpipe_debug->wandev.lock, &smp_flags); + return err; + +} + +int wan_tracing_enabled(wan_trace_t *trace_info) +{ + WAN_ASSERT(trace_info == NULL); + + if (wan_test_bit(0,&trace_info->tracing_enabled)){ + + if ((SYSTEM_TICKS - trace_info->trace_timeout) > WAN_MAX_TRACE_TIMEOUT){ + DEBUG_EVENT("wanpipe: Disabling trace, timeout!\n"); + wan_clear_bit(0,&trace_info->tracing_enabled); + wan_clear_bit(1,&trace_info->tracing_enabled); + return -EINVAL; + } + + if (wan_skb_queue_len(&trace_info->trace_queue) < trace_info->max_trace_queue){ + + if(wan_test_bit(3,&trace_info->tracing_enabled)){ + /* Trace ALL cells, including Idle. + ** Check that trace queue is NOT more than half full. */ + if (wan_skb_queue_len(&trace_info->trace_queue) < trace_info->max_trace_queue / 2){ + /*it is ok to enqueue an idle cell. */ + return 3; + }else{ + return -ENOBUFS; + } + } + + if (wan_test_bit(1,&trace_info->tracing_enabled)){ + return 1; + } + + if (wan_test_bit(2,&trace_info->tracing_enabled)){ + return 2; + } + + return 0; + } + + if (WAN_NET_RATELIMIT()){ + DEBUG_EVENT("wanpipe: Warning: trace queue overflow %d (max=%d)!\n", + wan_skb_queue_len(&trace_info->trace_queue), + trace_info->max_trace_queue); + } + return -ENOBUFS; + } + return -EINVAL; + +} + +int wan_capture_trace_packet(sdla_t *card, wan_trace_t* trace_info, netskb_t *skb, char direction) +{ + int len = 0; + void* new_skb = NULL; + wan_trace_pkt_t trc_el; + int flag = 0; + + if ((flag = wan_tracing_enabled(trace_info)) >= 0){ + + /* Allocate a header mbuf */ + len = wan_skb_len(skb) + sizeof(wan_trace_pkt_t); + + new_skb = wan_skb_alloc(len); + if (new_skb == NULL) + return -1; + + wan_getcurrenttime(&trc_el.sec, &trc_el.usec); + trc_el.status = direction; + trc_el.data_avail = 1; + trc_el.time_stamp = + (unsigned short)((((trc_el.sec * 1000000) + trc_el.usec) / 1000) % 0xFFFF); + trc_el.real_length = wan_skb_len(skb); + + wan_skb_copyback(new_skb, + wan_skb_len(new_skb), + sizeof(wan_trace_pkt_t), + (caddr_t)&trc_el); + + wan_skb_copyback(new_skb, + wan_skb_len(new_skb), + wan_skb_len(skb), + (caddr_t)wan_skb_data(skb)); + + wan_skb_queue_tail(&trace_info->trace_queue, new_skb); + } + + return 0; +} + + + +int wan_capture_trace_packet_offset(sdla_t *card, wan_trace_t* trace_info, netskb_t *skb, int off,char direction) +{ + int flag = 0; + if ((flag = wan_tracing_enabled(trace_info)) >= 1){ + + int len = 0; + void* new_skb = NULL; + wan_trace_pkt_t trc_el, *trc_el_ptr; + int i,drop=1; + unsigned char diff=0,*src_ptr,*dest_ptr; + + if (off < 1){ + return -EINVAL; + } + + /* Allocate a header mbuf */ + len = wan_skb_len(skb) + sizeof(wan_trace_pkt_t) + 16; + + new_skb = wan_skb_alloc(len); + if (new_skb == NULL) + return -1; + + wan_getcurrenttime(&trc_el.sec, &trc_el.usec); + trc_el.status = direction; + trc_el.data_avail = 1; + trc_el.time_stamp = + (unsigned short)((((trc_el.sec * 1000000) + trc_el.usec) / 1000) % 0xFFFF); + trc_el.real_length = wan_skb_len(skb); + + wan_skb_copyback(new_skb, + wan_skb_len(new_skb), + sizeof(wan_trace_pkt_t), + (caddr_t)&trc_el); + + trc_el.real_length=0; + src_ptr=wan_skb_data(skb); + for (i=(off-1);ireal_length = trc_el.real_length; + + wan_skb_queue_tail(&trace_info->trace_queue, new_skb); + } + + return 0; +} + + +void wan_trace_info_init(wan_trace_t *trace, int max_trace_queue) +{ + wan_skb_queue_t* trace_queue = NULL; + + trace_queue = &trace->trace_queue; + WAN_IFQ_INIT(trace_queue, max_trace_queue); + trace->trace_timeout = SYSTEM_TICKS; + trace->tracing_enabled = 0; + trace->max_trace_queue = max_trace_queue; +} + +int wan_trace_purge (wan_trace_t *trace) +{ + wan_skb_queue_t* trace_queue = NULL; + + WAN_ASSERT(trace == NULL); + trace_queue = &trace->trace_queue; + WAN_IFQ_PURGE(trace_queue); + return 0; +} + +int wan_trace_enqueue(wan_trace_t *trace, void *skb_ptr) +{ + wan_skb_queue_t* trace_queue = NULL; + netskb_t* skb = (netskb_t*)skb_ptr; + int err = 0; + + WAN_ASSERT(trace == NULL); + trace_queue = &trace->trace_queue; + WAN_IFQ_ENQUEUE(trace_queue, skb, NULL, err); + return err; +} + + +/* +***************************************************************************** +** +** +*/ +#if !defined(CONFIG_PRODUCT_WANPIPE_GENERIC) +u_char ds1_variables_oid[] = { 1,3,6,1,2,1,10,18 }; +u_char fr_variables_oid[] = { 1,3,6,1,2,1,10,32 }; +u_char ppp_variables_oid[] = { 1,3,6,1,2,1,10,23 }; +u_char x25_variables_oid[] = { 1,3,6,1,2,1,10,5 }; + +int wan_snmp_data(sdla_t* card, netdevice_t* dev, int cmd, struct ifreq* ifr) +{ + wanpipe_snmp_t snmp; + + switch(cmd){ + case SIOC_WANPIPE_SNMP: + break; + + case SIOC_WANPIPE_SNMP_IFSPEED: + if (WAN_COPY_TO_USER(ifr->ifr_data, &card->wandev.bps, sizeof(card->wandev.bps))){ + return -EFAULT; + } + return 0; + } + + if (WAN_COPY_FROM_USER(&snmp, ifr->ifr_data, sizeof(wanpipe_snmp_t))){ + DEBUG_EVENT("%s: Failed to copy user snmp data to kernel space!\n", + card->devname); + return -EFAULT; + } + + if (strncmp((char *)ds1_variables_oid,(char *)snmp.snmp_name, sizeof(ds1_variables_oid)) == 0){ + /* SNMP call for ds1 */ + DEBUG_SNMP("%s: Get T1/E1 SNMP data\n", + card->devname); + card->wandev.fe_iface.get_snmp_data(&card->fe, dev, &snmp); + }else{ + if (strncmp((char *)fr_variables_oid,(char *)snmp.snmp_name, sizeof(fr_variables_oid)) == 0){ + /* SNMP call for frame relay */ + DEBUG_SNMP("%s: Get Frame Relay SNMP data\n", + card->devname); + } + + if (strncmp((char *)ppp_variables_oid,(char *)snmp.snmp_name, sizeof(ppp_variables_oid)) == 0){ + /* SNMP call for PPP */ + DEBUG_SNMP("%s: Get PPP SNMP data\n", + card->devname); + } + + if (strncmp((char *)x25_variables_oid,(char *)snmp.snmp_name, sizeof(x25_variables_oid)) == 0){ + /* SNMP call for x251 */ + DEBUG_SNMP("%s: Get X.25 SNMP data\n", + card->devname); + } + if (card->get_snmp_data){ + card->get_snmp_data(card, dev, &snmp); + } + } + + if (WAN_COPY_TO_USER(ifr->ifr_data, &snmp, sizeof(wanpipe_snmp_t))){ + DEBUG_EVENT("%s: Failed to copy kernel space to user snmp data!\n", + card->devname); + return -EFAULT; + } + + return 0; +} +#endif + +void wanpipe_card_lock_irq(void *card_id, unsigned long *flags) +{ +#define card ((sdla_t*)card_id) + wan_spin_lock_irq(&card->wandev.lock, (wan_smp_flag_t*)flags); +#undef card +} + +void wanpipe_card_unlock_irq(void *card_id, unsigned long *flags) +{ +#define card ((sdla_t*)card_id) + wan_spin_unlock_irq(&card->wandev.lock,(wan_smp_flag_t*)flags); +#undef card +} + + + +/*=================================================== + * Abstracted Wanpipe Specific Functions + *=================================================== + */ + +/* + * ============================================================================ + * Get WAN device state. + */ +char wpabs_get_state (void* card_id) +{ + return wanpipe_get_state(card_id); +} + +void wpabs_card_lock_irq(void *card_id,unsigned long *flags) +{ + wanpipe_card_lock_irq(card_id,flags); +} + +void wpabs_card_unlock_irq(void *card_id,unsigned long *flags) +{ + wanpipe_card_unlock_irq(card_id,flags); +} + +int wpabs_trace_queue_len(void *trace_ptr) +{ + wan_trace_t* trace = (wan_trace_t *)trace_ptr; + wan_skb_queue_t* trace_queue = NULL; + + WAN_ASSERT(trace == NULL); + trace_queue = &trace->trace_queue; + return WAN_IFQ_LEN(trace_queue); +} + +int wpabs_tracing_enabled(void *trace_ptr) +{ + return wan_tracing_enabled((wan_trace_t*)trace_ptr); +} + +void* wpabs_trace_info_alloc(void) +{ + return wan_malloc(sizeof(wan_trace_t)); +} + +void wpabs_trace_info_init(void *trace_ptr, int max_trace_queue) +{ + wan_trace_info_init(trace_ptr, max_trace_queue); +} + +int wpabs_trace_purge (void *trace_ptr) +{ + return wan_trace_purge(trace_ptr); +} + +int wpabs_trace_enqueue(void *trace_ptr, void *skb_ptr) +{ + return wan_trace_enqueue(trace_ptr, skb_ptr); +} + +void wpabs_set_state (void* card_id, int state) +{ + wanpipe_set_state(card_id, state); +} + +/* + * ============================================================================ + * Get WAN device state. + */ +void wpabs_set_baud (void* card_id, unsigned int baud) +{ + wanpipe_set_baud(card_id, baud); +} + +/*void* wpabs_dma_alloc(void* pcard, DMA_DESCRIPTION* dma_descr) +*/ +void* wpabs_dma_alloc(void* pcard, unsigned long max_length) +{ + sdla_t* card = (sdla_t*)pcard; + wan_dma_descr_t* dma_descr = NULL; + + dma_descr = wan_malloc(sizeof(wan_dma_descr_t)); + if (dma_descr == NULL){ + return NULL; + } + dma_descr->max_length = max_length; +#if defined(__NetBSD__) || defined(__OpenBSD__) + card->hw_iface.getcfg(card->hw, SDLA_DMATAG, &dma_descr->dmat); +#endif + if (wan_dma_alloc(card->hw, dma_descr)){ + wan_free(dma_descr); + return NULL; + } + return dma_descr; +} + +int wpabs_dma_free(void* pcard, void* dma_descr) +{ + int err=0; + sdla_t* card = (sdla_t*)pcard; + err=wan_dma_free(card->hw, (wan_dma_descr_t*)dma_descr); + wan_free(dma_descr); + return err; +} + +/* LIP ATM definitions */ +#define ATM_CELL_SIZE 53 +#define ATM_HEADER_SZ 5 +#define ATM_PAYLOAD_SZ 48 +#define ATM_PAD_CHAR 0x6A + +/*#define DEBUG_ATM DEBUG_EVENT*/ +#define DEBUG_ATM DEBUG_TEST + +int init_atm_idle_buffer(unsigned char *buff, int buff_len, char *if_name, char hardware_flip) +{ + const unsigned char idle_cell_header[ATM_HEADER_SZ] = {0x00, 0x00, 0x00, 0x01, 0x52}; + unsigned char idle_cell[ATM_CELL_SIZE]; + int ind, number_of_cells_fit_idle_buffer; + + /* copy header */ + memcpy(idle_cell, idle_cell_header, ATM_HEADER_SZ); + /* init pad chars */ + memset(&idle_cell[ATM_HEADER_SZ], ATM_PAD_CHAR, ATM_PAYLOAD_SZ); + + number_of_cells_fit_idle_buffer = buff_len / ATM_CELL_SIZE; + + if(number_of_cells_fit_idle_buffer == 0 /*|| buff_len % ATM_CELL_SIZE*/){ + DEBUG_EVENT("%s: Error: Invalid Idle buffer length=%d, not multiple of ATM_CELL_SIZE (53)!\n", + if_name, buff_len); + return 1; + } + + /* finally, init the buffer */ + for(ind = 0; ind < number_of_cells_fit_idle_buffer; ind++){ + memcpy(&buff[ind*ATM_CELL_SIZE], idle_cell, ATM_CELL_SIZE); + } + + return 0; +} + +int atm_add_data_to_skb(void* skb, void *data, int data_len, char *if_name) +{ + unsigned char *skb_data_ptr; + + DEBUG_ATM("%s(): data_len=%d, skb tail room=%d\n", + __FUNCTION__, data_len, wan_skb_tailroom(skb)); + + if(data_len > wan_skb_tailroom(skb)){ + DEBUG_EVENT("%s: %s(): Warining: 'data_len=%d > skb tail room=%d'!\n", + if_name, __FUNCTION__, data_len, wan_skb_tailroom(skb)); + return 1; + } + + skb_data_ptr = wan_skb_put(skb, data_len); + + /* copy data to the new skb */ + memcpy(skb_data_ptr, data, data_len); + + return 0; +} + +int atm_pad_idle_cells_in_tx_skb(void *skb, void *tx_idle_skb, char *if_name) +{ + unsigned char *idle_skb_data_ptr; + int num_of_cells_to_pad, i, empty_space; + + DEBUG_ATM("%s()\n", __FUNCTION__); + + idle_skb_data_ptr = wan_skb_data(tx_idle_skb); + + empty_space = wan_skb_len(tx_idle_skb) - wan_skb_len(skb); + DEBUG_ATM("empty space length: %d\n", empty_space); + + num_of_cells_to_pad = empty_space / ATM_CELL_SIZE; + DEBUG_ATM("num_of_cells_to_pad: %d\n", num_of_cells_to_pad); + + if(empty_space % ATM_CELL_SIZE){ + DEBUG_EVENT("%s: %s(): Error, empty space length (%d) is not multiple of ATM_CELL_SIZE!\n", + if_name, __FUNCTION__, empty_space); + return 1; + } + + if(num_of_cells_to_pad){ + for(i = 0 ; i < num_of_cells_to_pad; i++){ + if(atm_add_data_to_skb(skb, idle_skb_data_ptr, ATM_CELL_SIZE, if_name)){ + return 2; + } + } + } + + return 0; +} + +void *atm_tx_skb_dequeue(void* wp_tx_pending_list, void *tx_idle_skb, char *if_name) +{ + void *tx_skb, *single_cell_skb; + int max_num_of_cells_fit_in_tx_buffer, i; + + if(wan_skb_queue_len(wp_tx_pending_list) == 0){ + return NULL; + } + + DEBUG_ATM("%s(): queue len: %d\n", __FUNCTION__, wan_skb_queue_len(wp_tx_pending_list)); + + tx_skb = wan_skb_alloc(wan_skb_len(tx_idle_skb)); + if (!tx_skb){ + DEBUG_EVENT("%s: Failed to allocate ATM TX skb!\n", if_name); + return NULL; + } + + max_num_of_cells_fit_in_tx_buffer = wan_skb_len(tx_idle_skb) / ATM_CELL_SIZE; + DEBUG_ATM("max_num_of_cells_fit_in_tx_buffer=%d\n", max_num_of_cells_fit_in_tx_buffer); + + i=0; + while(i++ < max_num_of_cells_fit_in_tx_buffer){ + + single_cell_skb = wan_skb_dequeue(wp_tx_pending_list); + if(single_cell_skb == NULL){ + /* no more data, but may be idle cells should be added */ + DEBUG_ATM("no more data\n"); + break; + } + + atm_add_data_to_skb( tx_skb, + wan_skb_data(single_cell_skb), + wan_skb_len (single_cell_skb), + if_name); + + wan_skb_free(single_cell_skb); + } + + /* try to add idle cells, if no space it won't do anything */ + atm_pad_idle_cells_in_tx_skb(tx_skb, tx_idle_skb, if_name); + + return tx_skb; +} + +int wanpipe_globals_util_init(void) +{ + wan_generate_bit_rev_table(); + + return 0; +} + + + +/* + * Verify iovec. The caller must ensure that the iovec is big enough + * to hold the message iovec. + * + * Save time not doing verify_area. copy_*_user will make this work + * in any case. + */ + +#if defined(__LINUX__) + +int wan_verify_iovec(struct msghdr *m, struct iovec *iov, char *address, int mode) +{ + int size, err, ct; + + m->msg_name = NULL; + + size = m->msg_iovlen * sizeof(struct iovec); + + if (copy_from_user(iov, m->msg_iov, size)) + return -EFAULT; + + m->msg_iov = iov; + err = 0; + + for (ct = 0; ct < m->msg_iovlen; ct++) { + err += iov[ct].iov_len; + /* + * Goal is not to verify user data, but to prevent returning + * negative value, which is interpreted as errno. + * Overflow is still possible, but it is harmless. + */ + if (err < 0) + return -EMSGSIZE; + } + + return err; +} + + /* + * Copy iovec to kernel. Returns -EFAULT on error. + * + * Note: this modifies the original iovec. + */ + +int wan_memcpy_fromiovec(unsigned char *kdata, struct iovec *iov, int len) +{ + while (len > 0) { + if (iov->iov_len) { + int copy = min_t(unsigned int, len, iov->iov_len); + if (copy_from_user(kdata, iov->iov_base, copy)) + return -EFAULT; + len -= copy; + kdata += copy; + iov->iov_base += copy; + iov->iov_len -= copy; + } + iov++; + } + + return 0; +} + +/* + * Copy kernel to iovec. Returns -EFAULT on error. + * + * Note: this modifies the original iovec. + */ + +int wan_memcpy_toiovec(struct iovec *iov, unsigned char *kdata, int len) +{ + while (len > 0) { + if (iov->iov_len) { + int copy = min_t(unsigned int, iov->iov_len, len); + if (copy_to_user(iov->iov_base, kdata, copy)) + return -EFAULT; + kdata += copy; + len -= copy; + iov->iov_len -= copy; + iov->iov_base += copy; + } + iov++; + } + + return 0; +} + +#endif diff -Nur linux.org/drivers/net/wan/wanrouter.mod.c linux-2.6.17/drivers/net/wan/wanrouter.mod.c --- linux.org/drivers/net/wan/wanrouter.mod.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/drivers/net/wan/wanrouter.mod.c 2006-08-30 10:07:17.000000000 +0000 @@ -0,0 +1,30 @@ +#include +#include +#include + +MODULE_INFO(vermagic, VERMAGIC_STRING); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,6) || defined(WANPIPE_MOD_266_FORCE_UPDATE) +#undef unix +struct module __this_module +__attribute__((section(".gnu.linkonce.this_module"))) = { + .name = __stringify(KBUILD_MODNAME), + .init = init_module, +#ifdef CONFIG_MODULE_UNLOAD + .exit = cleanup_module, +#endif +}; +#endif + + +static const struct modversion_info ____versions[] +__attribute__((section("__versions"))) = { + +}; + + +static const char __module_depends[] +__attribute_used__ +__attribute__((section(".modinfo"))) = +"depends=sdladrv"; + diff -Nur linux.org/include/linux/aft_a104.h linux-2.6.17/include/linux/aft_a104.h --- linux.org/include/linux/aft_a104.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/aft_a104.h 2006-08-30 10:07:15.000000000 +0000 @@ -0,0 +1,69 @@ +/***************************************************************************** +* aft_a104.h WANPIPE(tm) S51XX Xilinx Hardware Support +* +* Authors: Nenad Corbic +* +* Copyright: (c) 2003 Sangoma Technologies Inc. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version +* 2 of the License, or (at your option) any later version. +* ============================================================================ +* Oct 18, 2005 Nenad Corbic Initial version. +*****************************************************************************/ + + +#ifndef __AFT_A104_H_ +#define __AFT_A104_H_ + +#ifdef WAN_KERNEL + +#if 0 +#define A104_SECURITY_32_ECCHAN 0x00 +#define A104_SECURITY_64_ECCHAN 0x01 +#define A104_SECURITY_96_ECCHAN 0x02 +#define A104_SECURITY_128_ECCHAN 0x03 +#define A104_SECURITY_256_ECCHAN 0x04 +#define A104_SECURITY_PROTO_128_ECCHAN 0x05 +#define A104_SECURITY_0_ECCHAN 0x07 + +#define A104_ECCHAN(val) \ + ((val) == A104_SECURITY_32_ECCHAN) ? 32 : \ + ((val) == A104_SECURITY_64_ECCHAN) ? 64 : \ + ((val) == A104_SECURITY_96_ECCHAN) ? 96 : \ + ((val) == A104_SECURITY_128_ECCHAN) ? 128 : \ + ((val) == A104_SECURITY_PROTO_128_ECCHAN) ? 128 : \ + ((val) == A104_SECURITY_256_ECCHAN) ? 256 : 0 +#endif + +int a104_global_chip_config(sdla_t *card); +int a104_global_chip_unconfig(sdla_t *card); +int a104_chip_config(sdla_t *card); +int a104_chip_unconfig(sdla_t *card); +int a104_chan_dev_config(sdla_t *card, void *chan); +int a104_chan_dev_unconfig(sdla_t *card, void *chan); +int a104_led_ctrl(sdla_t *card, int color, int led_pos, int on); +int a104_test_sync(sdla_t *card, int tx_only); +int a104_check_ec_security(sdla_t *card); + + +//int a104_write_fe (sdla_t* card, unsigned short off, unsigned char value); +//unsigned char a104_read_fe (sdla_t* card, unsigned short off); +int a104_write_fe (void *pcard, ...); +unsigned char __a104_read_fe (void *pcard, ...); +unsigned char a104_read_fe (void *pcard, ...); + +int a104_write_cpld(sdla_t *card, unsigned short off,unsigned char data); +unsigned char a104_read_cpld(sdla_t *card, unsigned short cpld_off); + +int a108m_write_cpld(sdla_t *card, unsigned short off,unsigned char data); +unsigned char a108m_read_cpld(sdla_t *card, unsigned short cpld_off); + +void a104_fifo_adjust(sdla_t *card,u32 level); + + + +#endif + +#endif diff -Nur linux.org/include/linux/aft_analog.h linux-2.6.17/include/linux/aft_analog.h --- linux.org/include/linux/aft_analog.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/aft_analog.h 2006-08-30 10:07:15.000000000 +0000 @@ -0,0 +1,54 @@ +/***************************************************************************** +* aft_analog.h WANPIPE(tm) S51XX Xilinx Hardware Support +* +* Authors: Nenad Corbic +* +* Copyright: (c) 2003 Sangoma Technologies Inc. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version +* 2 of the License, or (at your option) any later version. +* ============================================================================ +* Oct 18, 2005 Nenad Corbic Initial version. +*****************************************************************************/ + + +#ifndef __AFT_A104_ANALOG_H_ +#define __AFT_A104_ANALOG_H_ + +#ifdef WAN_KERNEL + +#if 0 +#define A200_SECURITY_16_ECCHAN 0x00 +#define A200_SECURITY_32_ECCHAN 0x01 +#define A200_SECURITY_0_ECCHAN 0x05 +#define A200_ECCHAN(val) \ + ((val) == A200_SECURITY_16_ECCHAN) ? 16 : \ + ((val) == A200_SECURITY_32_ECCHAN) ? 32 : 0 +#endif + +int aft_analog_global_chip_config(sdla_t *card); +int aft_analog_global_chip_unconfig(sdla_t *card); +int aft_analog_chip_config(sdla_t *card); +int aft_analog_chip_unconfig(sdla_t *card); +int aft_analog_chan_dev_config(sdla_t *card, void *chan); +int aft_analog_chan_dev_unconfig(sdla_t *card, void *chan); +int aft_analog_led_ctrl(sdla_t *card, int color, int led_pos, int on); +int aft_analog_test_sync(sdla_t *card, int tx_only); +int a200_check_ec_security(sdla_t *card); + +int __aft_analog_write_fe (void* card, ...); +int aft_analog_write_fe (void* card, ...); +unsigned char __aft_analog_read_fe (void* card, ...); +unsigned char aft_analog_read_fe (void* card, ...); + +int aft_analog_write_cpld(sdla_t *card, unsigned short off,unsigned char data); +unsigned char aft_analog_read_cpld(sdla_t *card, unsigned short cpld_off); + +void aft_analog_fifo_adjust(sdla_t *card,u32 level); + + +#endif + +#endif diff -Nur linux.org/include/linux/if_wanpipe_common.h linux-2.6.17/include/linux/if_wanpipe_common.h --- linux.org/include/linux/if_wanpipe_common.h 2006-06-18 01:49:35.000000000 +0000 +++ linux-2.6.17/include/linux/if_wanpipe_common.h 2006-08-30 10:07:15.000000000 +0000 @@ -17,28 +17,103 @@ #ifndef _WANPIPE_SOCK_DRIVER_COMMON_H #define _WANPIPE_SOCK_DRIVER_COMMON_H +#if defined(WAN_KERNEL) + +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) +# include +# include +# include +#elif defined(__LINUX__) +# include +# include +# include +# include +# include +#endif + + +/*#define wan_next_dev(dev) *((netdevice_t**)dev->priv)*/ +#define wan_next_dev(dev) *((netdevice_t**)wan_netif_priv(dev)) + typedef struct { - struct net_device *slave; - atomic_t packet_sent; + int (*open) (netdevice_t*); + int (*close) (netdevice_t*); +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) + int (*output) (netdevice_t*,netskb_t*,struct sockaddr*, struct rtentry*); +#else + int (*send) (netskb_t* skb, netdevice_t*); +#endif + struct net_device_stats* (*get_stats) (netdevice_t*); + int (*ioctl) (netdevice_t*, struct ifreq*, int); + void (*tx_timeout) (netdevice_t*); +} wanpipe_common_iface_t; + +typedef struct { +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) + /* !!! IMPORTANT !!! <- Do not move this parameter (GENERIC-PPP) */ + void *prot_ptr; +/* netdevice_t *next; */ /* netdevice_t *slave; */ + void *card; + netdevice_t *dev; + unsigned char state; + unsigned char usedby; + wan_tasklet_t bh_task; + wan_timer_t dev_timer; + struct socket *sk; /* Wanpipe Sock bind's here (Not used)*/ + unsigned int protocol; + unsigned short lcn; + void *lip; + unsigned int lip_prot; +#elif defined(__LINUX__) + /* !!! IMPORTANT !!! <- Do not move this parameter (GENERIC-PPP) */ + void* *prot_ptr; + netdevice_t *next; /*slave;*/ + void *card; + atomic_t receive_block; atomic_t command; atomic_t disconnect; - atomic_t driver_busy; - long common_critical; - struct timer_list *tx_timer; + struct sock *sk; /* Wanpipe Sock bind's here */ - int (*func)(struct sk_buff *skb, struct net_device *dev, - struct sock *sk); - - struct work_struct wanpipe_work; /* deferred keventd work */ + + struct tq_struct wanpipe_task; /* Immediate BH handler task */ + unsigned char rw_bind; /* Sock bind state */ unsigned char usedby; unsigned char state; unsigned char svc; unsigned short lcn; - void *mbox; + unsigned int config_id; + + unsigned long used; + unsigned long api_state; + netdevice_t *dev; + wan_skb_queue_t rx_queue; + wan_tasklet_t bh_task; + wan_timer_t dev_timer; + + unsigned int protocol; + + void *lip; + unsigned int lip_prot; +#endif + int is_netdev; + wanpipe_common_iface_t iface; } wanpipe_common_t; +/* Used flags: Resources */ +enum { +LCN_USED, +LCN_DEV, +LCN_TX_DEV, +LCN_X25_LINK, +LCN_SK_ID, +LCN_DSP_ID, +WAN_API_INIT +}; + +#define SK_ID LCN_SK_ID + enum { WANSOCK_UNCONFIGURED, /* link/channel is not configured */ @@ -53,6 +128,291 @@ WANSOCK_LISTEN }; + +static __inline void *wan_get_lip_ptr(netdevice_t *dev) +{ + if (wan_netif_priv(dev)){ + return ((wanpipe_common_t*)wan_netif_priv(dev))->lip; + } + return NULL; +} + +static __inline int wan_set_lip_ptr(netdevice_t *dev, void *lipreg) +{ + if (wan_netif_priv(dev)){ + ((wanpipe_common_t*)wan_netif_priv(dev))->lip = lipreg; + return 0; + } + return -ENODEV; +} + +static __inline int wan_set_lip_prot(netdevice_t *dev, int protocol) +{ + if (wan_netif_priv(dev)){ + ((wanpipe_common_t*)wan_netif_priv(dev))->lip_prot = protocol; + return 0; + } + return -ENODEV; +} + + +static __inline int wan_api_rx(void *chan_ptr,netskb_t *skb) +{ +#if defined(__LINUX__) + wanpipe_common_t *chan = (wanpipe_common_t*)chan_ptr; + + if (test_bit(SK_ID,&chan->used) && chan->sk){ + return wanpipe_api_sock_rx(skb,chan->dev,chan->sk); + } #endif + return -EINVAL; +} +static __inline int wan_api_rx_dtmf(void *chan_ptr,netskb_t *skb) +{ +#if defined(__LINUX__) + wanpipe_common_t *chan = (wanpipe_common_t*)chan_ptr; + + if (test_bit(SK_ID,&chan->used) && chan->sk){ + return wanpipe_api_sock_rx(skb,chan->dev,chan->sk); + } +#endif + return -EINVAL; +} + +static __inline void wan_wakeup_api(void *chan_ptr) +{ +#if defined(__LINUX__) + wanpipe_common_t *chan = (wanpipe_common_t*)chan_ptr; + + if (test_bit(SK_ID,&chan->used) && chan->sk){ + wanpipe_api_poll_wake(chan->sk); + } +#endif +} + + + +static __inline int wan_reg_api(void *chan_ptr, void *dev, char *devname) +{ +#if defined(__LINUX__) + wanpipe_common_t *common = (wanpipe_common_t*)chan_ptr; + + if (wan_test_and_set_bit(WAN_API_INIT,&common->used)){ + DEBUG_EVENT("%s: Error: Failed to initialize API!\n", + devname); + return -EINVAL; + } + + DEBUG_TEST("%s: Initializing API\n", + devname); + + common->sk=NULL; + common->state = WAN_CONNECTING; + common->dev = dev; + common->api_state=0; + + WAN_IFQ_INIT(&common->rx_queue,10); + + /*WAN_TASKLET_INIT((&common->task),0,func,(unsigned long)common);*/ + + wan_set_bit(WAN_API_INIT,&common->used); +#else + DEBUG_EVENT("%s: Initializing API\n", + devname); + +#endif + return 0; +} + +static __inline int wan_unreg_api(void *chan_ptr, char *devname) +{ +#if defined(__LINUX__) + wanpipe_common_t *common = (wanpipe_common_t*)chan_ptr; + + if (!wan_test_and_clear_bit(WAN_API_INIT,&common->used)){ + DEBUG_EVENT("%s: Error: Failed to unregister API!\n", + devname); + return -EINVAL; + } + + DEBUG_EVENT("%s: Unregistering API\n", + devname); + + common->state = WAN_DISCONNECTED; +// WAN_TASKLET_KILL((&common->task)); + wan_skb_queue_purge(&common->rx_queue); +#else + DEBUG_EVENT("%s: Unregistering API\n", + devname); + +#endif + return 0; +} + +static __inline void wan_release_svc_dev(wanpipe_common_t *chan) +{ +#if defined(__LINUX__) + wan_clear_bit(0,(void *)&chan->rw_bind); +#endif +} +static __inline void wan_get_svc_dev(wanpipe_common_t *chan) +{ +#if defined(__LINUX__) + wan_set_bit(0,(void *)&chan->rw_bind); +#endif +} + + +static __inline int wan_bind_api_to_svc(void *chan_ptr, void *sk_id) +{ +#if defined(__LINUX__) + wanpipe_common_t *chan = (wanpipe_common_t*)chan_ptr; + + if (!sk_id){ + return -EINVAL; + } + + if (test_bit(SK_ID,&chan->used) || chan->sk){ + return -EBUSY; + } + + wan_get_svc_dev(chan); + chan->sk = sk_id; + sock_hold(chan->sk); + wan_set_bit(SK_ID,&chan->used); +#endif + return 0; +} + + +static __inline int wan_unbind_api_from_svc(void *chan_ptr, void *sk_id) +{ +#if defined(__LINUX__) + wanpipe_common_t *chan=(wanpipe_common_t*)chan_ptr; + + WAN_ASSERT_EINVAL((!chan)); + WAN_ASSERT_EINVAL((!chan->dev)); + + DEBUG_TEST("%s:%s: BEGIN\n",__FUNCTION__,chan->dev->name); + + if (test_bit(SK_ID,&chan->used) && chan->sk){ + + if ((struct sock*)sk_id != chan->sk){ + DEBUG_TEST("%s: ERROR: API trying to unbind invalid sock api! New=%p Orig=%p\n", + chan->dev->name,sk_id,chan->sk); + return -ENODEV; + } + + wan_clear_bit(SK_ID,&chan->used); + __sock_put(chan->sk); + chan->sk=NULL; + + DEBUG_TEST("%s SK UNBIND SUCCESS\n", + __FUNCTION__); + + wan_release_svc_dev(chan); + return 0; + } + + DEBUG_TEST("%s: ERROR: API trying to unbind invalid sock api! New=%p Orig=%p\n", + chan->dev->name,sk_id,chan->sk); + return -ENODEV; +#else + return 0; +#endif +} + + +static __inline void wan_update_api_state(void *chan_ptr) +{ + +#if defined(__LINUX__) + + int err=0; + wanpipe_common_t *chan = (wanpipe_common_t*)chan_ptr; + + /* If the LCN state changes from Connected to Disconnected, and + * we are in the API mode, then notify the socket that the + * connection has been lost */ + + if (chan->usedby != API) + return; + + if (test_bit(SK_ID,&chan->used) && chan->sk){ + + if (chan->state != WAN_CONNECTED && test_bit(0,&chan->api_state)){ + wan_clear_bit(0,&chan->api_state); + protocol_disconnected (chan->sk); + return; + } + + + if (chan->state == WAN_CONNECTED){ + wan_set_bit(0,&chan->api_state); + err=protocol_connected (chan->dev,chan->sk); + if (err == -EINVAL){ + printk(KERN_INFO "%s:Major Error in Socket Above: CONN!!!\n", + chan->dev->name); + wan_unbind_api_from_svc(chan,chan->sk); + } + return; + } + + if (chan->state == WAN_DISCONNECTED){ + err = protocol_disconnected (chan->sk); + } + }else{ + DEBUG_TEST("%s: Error: no sk device\n",__FUNCTION__); + } + + if (chan->state != WAN_CONNECTED){ + wan_clear_bit(0,&chan->api_state); + } +#endif +} + + + +#define MAX_API_RX_QUEUE 10 +static __inline int wan_api_enqueue_skb(void *chan_ptr,netskb_t *skb) +{ +#if defined(__LINUX__) + wanpipe_common_t *chan = (wanpipe_common_t*)chan_ptr; + + if (wan_skb_queue_len(&chan->rx_queue) > MAX_API_RX_QUEUE){ + return -EBUSY; + } + wan_skb_queue_tail(&chan->rx_queue,skb); + + if (wan_skb_queue_len(&chan->rx_queue) >= MAX_API_RX_QUEUE){ + return 1; + } +#endif + return 0; +} + +static __inline netskb_t* wan_api_dequeue_skb(void *chan_ptr) +{ +#if defined(__LINUX__) + wanpipe_common_t *chan = (wanpipe_common_t*)chan_ptr; + return wan_skb_dequeue(&chan->rx_queue); +#else + return NULL; +#endif + +} + +#if 0 +void wp_debug_func_init(void) +{ + DBG_ARRAY_CNT=0; +} +#endif + + +#endif /* WAN_KERNEL */ + + +#endif diff -Nur linux.org/include/linux/if_wanpipe.h linux-2.6.17/include/linux/if_wanpipe.h --- linux.org/include/linux/if_wanpipe.h 2006-06-18 01:49:35.000000000 +0000 +++ linux-2.6.17/include/linux/if_wanpipe.h 2006-08-30 10:07:15.000000000 +0000 @@ -18,6 +18,8 @@ #ifndef __LINUX_IF_WAN_PACKET_H #define __LINUX_IF_WAN_PACKET_H +#include + struct wan_sockaddr_ll { unsigned short sll_family; @@ -29,12 +31,17 @@ unsigned char sll_addr[8]; unsigned char sll_device[14]; unsigned char sll_card[14]; + + unsigned int sll_active_ch; + unsigned char sll_prot; + unsigned char sll_prot_opt; + unsigned short sll_mult_cnt; + unsigned char sll_seven_bit_hdlc; }; -typedef struct -{ +typedef struct wan_debug_hdr{ unsigned char free; - unsigned char state_sk; + unsigned char wp_sk_state; int rcvbuf; int sndbuf; int rmem; @@ -53,24 +60,152 @@ int rblock; } wan_debug_hdr_t; -#define MAX_NUM_DEBUG 10 -#define X25_PROT 0x16 -#define PVC_PROT 0x17 +#pragma pack(1) +typedef struct { + unsigned char error_flag; + unsigned short time_stamp; + unsigned char channel; + unsigned char direction; + unsigned char reserved[11]; +} wp_sock_rx_hdr_t; + +typedef struct { + wp_sock_rx_hdr_t api_rx_hdr; + unsigned char data[1]; +} wp_sock_rx_element_t; +#pragma pack() + +#define MAX_NUM_DEBUG 10 + +#define LAPB_PROT 0x15 +#define WP_LAPB_PROT LAPB_PROT + +#define X25_PROT 0x16 +#define WP_X25_PROT X25_PROT + +#define PVC_PROT 0x17 +#define WP_PVC_PROT PVC_PROT + +#define SS7_PROT 0x18 +#define WP_SS7_PROT SS7_PROT + +#define SS7_MONITOR_PROT 0x19 +#define WP_SS7_MONITOR_PROT SS7_MONITOR_PROT + +#define DSP_PROT 0x20 +#define WP_DSP_PROT DSP_PROT + +#define SS7_FISU 0x01 +#define SS7_LSSU 0x02 +#define SS7_MSU 0x04 +#define RAW_HDLC 0x08 +#define SS7_ALL_PROT (SS7_MSU|SS7_LSSU|SS7_FISU) + +#define SS7_FISU_BIT_MAP 0 +#define SS7_LSSU_BIT_MAP 1 +#define SS7_MSU_BIT_MAP 2 +#define HDLC_BIT_MAP 3 + +#define SS7_FISU_LEN 5 +#define SS7_MSU_LEN 8 +#define SS7_MSU_END_LEN 278 + +#define DECODE_SS7_PROT(a) ((a==SS7_MSU)?"SS7 MSU":\ + (a==SS7_LSSU)?"SS7 LSSU":\ + (a==SS7_FISU)?"SS7 FISU":\ + (a==RAW_HDLC)?"RAW HDLC":\ + (a==(SS7_MSU|SS7_LSSU))?"SS7 MSU LSSU":\ + (a==(SS7_MSU|SS7_FISU))?"SS7 MSU FISU":\ + (a==(SS7_LSSU|SS7_FISU))?"SS7 LSSU FISU":\ + (a==(SS7_LSSU|SS7_FISU|SS7_MSU))?"SS7 MSU LSSU FISU":\ + "Unknown SS7 Prot") +#define DELTA_PROT_OPT 1 +#define MULTI_PROT_OPT 2 typedef struct { wan_debug_hdr_t debug[MAX_NUM_DEBUG]; }wan_debug_t; +#if 0 #define SIOC_WANPIPE_GET_CALL_DATA (SIOCPROTOPRIVATE + 0) #define SIOC_WANPIPE_SET_CALL_DATA (SIOCPROTOPRIVATE + 1) #define SIOC_WANPIPE_ACCEPT_CALL (SIOCPROTOPRIVATE + 2) #define SIOC_WANPIPE_CLEAR_CALL (SIOCPROTOPRIVATE + 3) #define SIOC_WANPIPE_RESET_CALL (SIOCPROTOPRIVATE + 4) -#define SIOC_WANPIPE_DEBUG (SIOCPROTOPRIVATE + 5) -#define SIOC_WANPIPE_SET_NONBLOCK (SIOCPROTOPRIVATE + 6) -#define SIOC_WANPIPE_CHECK_TX (SIOCPROTOPRIVATE + 7) -#define SIOC_WANPIPE_SOCK_STATE (SIOCPROTOPRIVATE + 8) +#endif + +enum { + SIOC_WANPIPE_DEBUG = (SIOCPROTOPRIVATE), + SIOC_WANPIPE_SET_NONBLOCK, + SIOC_WANPIPE_CHECK_TX, + SIOC_WANPIPE_SOCK_STATE, + SIOC_WANPIPE_SOCK_FLUSH_BUFS +}; + +#define SIOC_ANNEXG_SOCK_STATE SIOC_WANPIPE_SOCK_STATE + +enum { + SIOCC_IF_WANPIPE_RESERVED = (SIOCDEVPRIVATE), + SIOC_WANPIPE_PIPEMON, + SIOC_WANPIPE_SNMP, + SIOC_WANPIPE_SNMP_IFSPEED, + +#if 0 + SIOC_WANPIPE_DEVICE, /* GENERIC */ + SIOC_WANPIPE_DUMP, /* GENERIC */ +#endif + + SIOC_WAN_DEVEL_IOCTL, /* uses wan_cmd_api_t */ + SIOC_WAN_EC_IOCTL, + SIOC_WAN_FE_IOCTL, + + SIOC_WANAPI_DEVPRIVATE = SIOCDEVPRIVATE + 20, + + SIOC_ANNEXG_SET_NONBLOCK, + SIOC_ANNEXG_CHECK_TX, + SIOC_ANNEXG_DEV_STATE, + + SIOC_ANNEXG_BIND_SK, + SIOC_ANNEXG_UNBIND_SK, + SIOC_ANNEXG_GET_SK, + SIOC_ANNEXG_KICK, + + SIOC_ANNEXG_PLACE_CALL, + SIOC_ANNEXG_CLEAR_CALL, + + SIOC_WANPIPE_GET_TIME_SLOTS, + SIOC_WANPIPE_GET_MEDIA_TYPE, + + SIOC_WANPIPE_GET_DEVICE_CONFIG_ID, + + SIOC_WANPIPE_TDM_API, + + SIOC_WANPIPE_DEVPRIVATE + +}; + +#define WAN_DEVPRIV_SIOC(_val) (SIOC_WANPIPE_DEVPRIVATE+(_val)) + +#define SIOC_WANPIPE_BIND_SK SIOC_ANNEXG_BIND_SK +#define SIOC_WANPIPE_UNBIND_SK SIOC_ANNEXG_UNBIND_SK +#define SIOC_WANPIPE_GET_SK SIOC_ANNEXG_GET_SK +#define SIOC_WANPIPE_KICK SIOC_ANNEXG_KICK +#define SIOC_WANPIPE_DEV_STATE SIOC_ANNEXG_DEV_STATE + +#define DECODE_API_CMD(cmd) ((cmd==SIOC_WANPIPE_PIPEMON)?"PIPEMON" : \ + (cmd==SIOC_WANPIPE_SNMP)?"SNMP": \ + (cmd==SIOC_ANNEXG_CHECK_TX)?"CHECK TX": \ + (cmd==SIOC_ANNEXG_SOCK_STATE)?"SOCK STATE": \ + (cmd==SIOC_ANNEXG_BIND_SK)?"BIND SK" : \ + (cmd==SIOC_ANNEXG_UNBIND_SK)?"UNBIND SK" : \ + (cmd==SIOC_ANNEXG_GET_SK)?"GET SK" : \ + (cmd==SIOC_ANNEXG_DEV_STATE)?"DEV STATE" : \ + (cmd==SIOC_ANNEXG_KICK)? "KICK" : "UNKNOWN") + + +#define SIOC_WANPIPE_BSC_CMD SIOC_WANPIPE_EXEC_CMD +#define SIOC_WANPIPE_POS_CMD SIOC_WANPIPE_EXEC_CMD /* Packet types */ @@ -99,14 +234,20 @@ #define WAN_PACKET_MR_PROMISC 1 #define WAN_PACKET_MR_ALLMULTI 2 + #ifdef __KERNEL__ +#include + +#define MAX_PARENT_PROT_NUM 10 + /* Private wanpipe socket structures. */ +#if 0 struct wanpipe_opt { void *mbox; /* Mail box */ void *card; /* Card bouded to */ - struct net_device *dev; /* Bounded device */ + netdevice_t *dev; /* Bounded device */ unsigned short lcn; /* Binded LCN */ unsigned char svc; /* 0=pvc, 1=svc */ unsigned char timer; /* flag for delayed transmit*/ @@ -114,10 +255,184 @@ unsigned poll_cnt; unsigned char force; /* Used to force sock release */ atomic_t packet_sent; - unsigned short num; + void *datascope; +}; +#else +struct wanpipe_opt +{ + netdevice_t *dev; /* Bounded device */ + void *datascope; + unsigned short num; +}; +#endif + +#define MAX_SOCK_CRC_QUEUE 3 +#define MAX_SOCK_HDLC_BUF 2000 +#define MAX_SOCK_HDLC_LIMIT MAX_SOCK_HDLC_BUF-500 + +typedef struct wanpipe_hdlc_decoder{ + unsigned char rx_decode_buf[MAX_SOCK_HDLC_BUF]; + unsigned int rx_decode_len; + unsigned char rx_decode_bit_cnt; + unsigned char rx_decode_onecnt; + + unsigned long hdlc_flag; + unsigned short rx_orig_crc; + unsigned short rx_crc[MAX_SOCK_CRC_QUEUE]; + unsigned short crc_fin; + + unsigned short rx_crc_tmp; + int crc_cur; + int crc_prv; +}wanpipe_hdlc_decoder_t; + + +typedef struct wanpipe_hdlc_engine +{ + + wanpipe_hdlc_decoder_t tx_decoder; + wanpipe_hdlc_decoder_t rx_decoder; + + struct sk_buff *raw_rx_skb; + struct sk_buff *raw_tx_skb; + + struct sk_buff_head data_q; + + atomic_t refcnt; + + unsigned char bound; + + unsigned long active_ch; + unsigned short timeslots; + struct wanpipe_hdlc_engine *next; + + int skb_decode_size; + unsigned char seven_bit_hdlc; + + void *sk_to_prot_map[MAX_PARENT_PROT_NUM]; + +}wanpipe_hdlc_engine_t; + +typedef struct hdlc_list +{ + wanpipe_hdlc_engine_t *hdlc; + struct hdlc_list *next; +}wanpipe_hdlc_list_t; + +#define MAX_SOCK_CHANNELS 33 +typedef struct wanpipe_parent +{ + wanpipe_hdlc_list_t *time_slot_hdlc_map[MAX_SOCK_CHANNELS]; + wanpipe_hdlc_engine_t *hdlc_eng_list; + unsigned char hdlc_enabled; + + rwlock_t lock; + signed char time_slots; + char media; + unsigned char seven_bit_hdlc; + + struct tasklet_struct rx_task; + struct sk_buff_head rx_queue; + + void *sk_to_prot_map[MAX_PARENT_PROT_NUM]; +}wanpipe_parent_t; + +typedef struct wanpipe_datascope +{ + unsigned long prot_type; + unsigned int active_ch; + struct sock *parent_sk; + unsigned char delta; + unsigned short max_mult_cnt; + union { + struct { + unsigned short tx_fisu_skb_csum; + unsigned short tx_lssu_skb_csum; + void *tx_fisu_skb; + void *tx_lssu_skb; + + unsigned short rx_fisu_skb_csum; + unsigned short rx_lssu_skb_csum; + void *rx_fisu_skb; + void *rx_lssu_skb; + }ss7; + }u; + + unsigned char parent; + wanpipe_hdlc_engine_t *hdlc_eng; + wanpipe_parent_t *parent_priv; + +}wanpipe_datascope_t; + + + +#define STACK_IF_REQ 0x04 +#define WANPIPE_HEADER_SZ 16 + + +#ifdef LINUX_2_6 +#define SK_PRIV(x) ((struct wanpipe_opt*)(x->sk_user_data)) +#define SK_PRIV_INIT(x,val) (x)->sk_user_data=(void*)(val) +#else +#define SK_PRIV(x) ((struct wanpipe_opt*)(x->user_data)) +#define SK_PRIV_INIT(x,val) (x)->user_data=(void*)(val) +#endif + +#define DATA_SC(x) ((wanpipe_datascope_t*)(SK_PRIV(x)->datascope)) +#define DATA_SC_INIT(x,val) (SK_PRIV(x)->datascope = (void*)(val)) +#define PPRIV(x) ((wanpipe_parent_t*)(DATA_SC(x)->parent_priv)) +#define PPRIV_INIT(x,val) (DATA_SC(x)->parent_priv = (void*)(val)) + +#define wp_dev_hold(dev) atomic_inc(&(dev)->refcnt) + +#define wp_dev_put(dev) if (atomic_dec_and_test(&dev->refcnt)){ \ + DEBUG_TEST("%s: %d: Freeing ptr %p\n",__FUNCTION__,__LINE__,dev);\ + wan_free(dev); \ + } + +#define wp_sock_hold(sk) atomic_inc(&(sk)->sk_refcnt) +#define wp_sock_put(sk) atomic_dec_and_test(&(sk)->sk_refcnt) + + +struct wanpipe_api_register_struct +{ + unsigned char init; + int (*wanpipe_api_sock_rcv)(struct sk_buff *skb, netdevice_t *dev, struct sock *sk); + int (*wanpipe_api_connected)(struct net_device *dev, struct sock *sk); + int (*wanpipe_api_disconnected)(struct sock *sk); + int (*wanpipe_listen_rcv) (struct sk_buff *skb, struct sock *sk); + int (*sk_buf_check) (struct sock *sk, int len); + int (*sk_poll_wake) (struct sock *sk); + int (*wanpipe_api_connecting)(struct net_device *dev, struct sock *sk); }; -#define wp_sk(__sk) ((struct wanpipe_opt *)(__sk)->sk_protinfo) + +extern int register_wanpipe_api_socket (struct wanpipe_api_register_struct *wan_api_reg); +extern void unregister_wanpipe_api_socket (void); + +extern int bind_api_to_protocol (netdevice_t *dev, char *, unsigned short protocol, void *sk); +extern int bind_api_listen_to_protocol (netdevice_t *dev, char *,unsigned short protocol, void *sk_id); +extern int unbind_api_listen_from_protocol (unsigned short protocol, void *sk_id); + +extern int wanpipe_lip_rx(void *chan, void *sk_id); +extern int wanpipe_lip_connect(void *chan, int ); +extern int wanpipe_lip_disconnect(void *chan, int); +extern int wanpipe_lip_kick(void *chan,int); +extern int wanpipe_lip_get_if_status(void *chan, void *m); + +extern int protocol_connected (netdevice_t *dev, void *sk_id); +extern int protocol_connecting (netdevice_t *dev, void *sk_id); +extern int protocol_disconnected (void *sk_id); +extern int wanpipe_api_sock_rx (struct sk_buff *skb, netdevice_t *dev, void *sk_id); +extern int wanpipe_api_listen_rx (struct sk_buff *skb, void *sk_id); +extern int wanpipe_api_buf_check (void *sk_id, int len); +extern int wanpipe_api_poll_wake(void *sk_id); + +extern void signal_user_state_change(void); + + + + #endif diff -Nur linux.org/include/linux/if_wanpipe_kernel.h linux-2.6.17/include/linux/if_wanpipe_kernel.h --- linux.org/include/linux/if_wanpipe_kernel.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/if_wanpipe_kernel.h 2006-08-30 10:07:15.000000000 +0000 @@ -0,0 +1,68 @@ +#ifndef _IF_WANPIPE_KERNEL_ +#define _IF_WANPIPE_KERNEL_ + +#ifdef __KERNEL__ + +#ifdef LINUX_2_6 + +#define pkt_sk(__sk) ((struct packet_opt *)(__sk)->sk_protinfo) + +# if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,11)) || defined(AF_WANPIPE_2612_FORCE_UPDATE) +#define AF_WANPIPE_2612_UPDATE +#define wansk_set_zapped(__sk) sock_set_flag(__sk, SOCK_ZAPPED) +#define wansk_reset_zapped(__sk) sock_reset_flag(__sk, SOCK_ZAPPED) +#define wansk_is_zapped(__sk) sock_flag(__sk, SOCK_ZAPPED) +#define sk_debug sk_type +#else +#define wansk_set_zapped(__sk) __sk->sk_zapped=1 +#define wansk_reset_zapped(__sk) __sk->sk_zapped=0 +#define wansk_is_zapped(__sk) __sk->sk_zapped +#endif + +#else + +#define pkt_sk(__sk) (__sk) + +#define sk_zapped zapped +#define sk_state state +#define sk_num num +#define sk_wmem_alloc wmem_alloc +#define sk_family family +#define sk_type type +#define sk_socket socket +#define sk_priority priority +#define sk_protocol protocol +#define sk_num num +#define sk_rcvbuf rcvbuf +#define sk_sndbuf sndbuf +#define sk_sleep sleep +#define sk_data_ready data_ready +#define sk_rmem_alloc rmem_alloc +#define sk_bound_dev_if bound_dev_if +#define sk_ack_backlog ack_backlog +#define sk_data_ready data_ready +#define sk_receive_queue receive_queue +#define sk_max_ack_backlog max_ack_backlog +#define sk_debug debug +#define sk_pair pair +#define sk_error_queue error_queue +#define sk_refcnt refcnt +#define sk_state_change state_change +#define sk_error_queue error_queue +#define sk_reuse reuse +#define sk_err err +#define sk_shutdown shutdown +#define sk_reuse reuse +#define sk_write_queue write_queue +#define sk_user_data user_data + +#define wansk_set_zapped(__sk) __sk->sk_zapped=1 +#define wansk_reset_zapped(__sk) __sk->sk_zapped=0 +#define wansk_is_zapped(__sk) __sk->sk_zapped + + +#endif + +#endif + +#endif diff -Nur linux.org/include/linux/sdla_56k.h linux-2.6.17/include/linux/sdla_56k.h --- linux.org/include/linux/sdla_56k.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/sdla_56k.h 2006-08-30 10:07:15.000000000 +0000 @@ -0,0 +1,104 @@ +/***************************************************************************** + * sdla_56k.h Sangoma 56K configuration definitions. + * + * Author: Nenad Corbic + * + * Copyright: (c) 1995-2001 Sangoma Technologies Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + + * ============================================================================ + * July 20, 2001 Nenad Corbic Initial version. + **************************************************************************** +*/ + +#ifndef _SDLA_56K_H_ +#define _SDLA_56K_H_ + +/******************************************************************************* + DEFINES AND MACROS + ******************************************************************************/ + +#define IS_56K_CARD(card) IS_56K_FEMEDIA(&(card)->fe) + +#define RRA(alarm) ((alarm>>8)&0xFF) +#define RRC(alarm) ((alarm)&0xFF) + +#define INS_ALARM_56K(alarm) ((RRA(alarm)&0x0F) > 8) ? "GREEN" : "RED" +#define DMI_ALARM_56K(alarm) (RRC(alarm)&0x80) ? "RED" : "OFF" +#define ZCS_ALARM_56K(alarm) (RRC(alarm)&0x40) ? "RED" : "OFF" +#define CMI_ALARM_56K(alarm) (RRC(alarm)&0x20) ? "RED" : "OFF" +#define OOS_ALARM_56K(alarm) (RRC(alarm)&0x10) ? "RED" : "OFF" +#define OOF_ALARM_56K(alarm) (RRC(alarm)&0x08) ? "RED" : "OFF" +#define DLP_ALARM_56K(alarm) (RRC(alarm)&0x04) ? "RED" : "OFF" +#define UMC_ALARM_56K(alarm) (RRC(alarm)&0x02) ? "RED" : "OFF" +#define RLOS_ALARM_56K(alarm) (RRA(alarm)&0x80) ? "RED" : "OFF" + + +/* registers on 56K card */ +#define REG_DEV_CTRL 0x00 +#define REG_TX_CTRL 0x01 +#define REG_RX_CTRL 0x02 +#define REG_EIA_SEL 0x05 +#define REG_EIA_TX_DATA 0x07 +#define REG_INT_EN_STAT 0x08 +#define REG_EIA_CTRL 0x09 +#define REG_DEV_STAT 0x0A +#define REG_RX_SLICER_LVL 0x0B +#define REG_RX_CODES 0x0C +#define REG_RX_INVALID_BPV 0x0D + +/* setting for each register */ +#define BIT_DEV_CTRL_DDS_PRI 0x00 +#define BIT_DEV_CTRL_SCT_E_OUT 0x10 +#define BIT_DEV_CTRL_XTALI_INT 0x40 +#define BIT_INT_EN_STAT_ACTIVE 0x01 +#define BIT_INT_EN_STAT_RX_CODE 0x20 +#define BIT_INT_EN_STAT_IDEL 0x40 +#define BIT_EIA_CTRL_RTS_ACTIVE 0x01 +#define BIT_EIA_CTRL_DTR_ACTIVE 0x02 +#define BIT_EIA_CTRL_DTE_ENABLE 0x04 +#define BIT_DEV_STAT_IL_44_dB 0x08 +#define BIT_DEV_STAT_RLOS 0x80 +#define BIT_RX_CODES_UNMTCH 0x01 +#define BIT_RX_CODES_UMC 0x02 +#define BIT_RX_CODES_DLP 0x04 +#define BIT_RX_CODES_OOF 0x08 +#define BIT_RX_CODES_OOS 0x10 +#define BIT_RX_CODES_CMI 0x20 +#define BIT_RX_CODES_ZSC 0x40 +#define BIT_RX_CODES_DMI 0x80 + + +/******************************************************************************* + FUNCTION PROTOTYPES + ******************************************************************************/ + +#ifdef WAN_KERNEL + +#if defined(__NetBSD__) || defined (__FreeBSD__) || defined (__OpenBSD__) +/*# include */ +#elif defined (__WINDOWS__) +# include "sdla_front_end.h" +#else +//# include +#endif + +typedef struct { + unsigned char RLOS_56k; + unsigned char RR8_reg_56k; + unsigned char RRA_reg_56k; + unsigned char RRC_reg_56k; + unsigned char prev_RRC_reg_56k; + unsigned char delta_RRC_reg_56k; +} sdla_56k_param_t; + +extern int sdla_56k_default_cfg(void* arg1, void* p56k_cfg); +extern int sdla_56k_iface_init(void* pfe); + +#endif /* WAN_KERNEL */ + +#endif diff -Nur linux.org/include/linux/sdla_adccp.h linux-2.6.17/include/linux/sdla_adccp.h --- linux.org/include/linux/sdla_adccp.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/sdla_adccp.h 2006-08-30 10:07:15.000000000 +0000 @@ -0,0 +1,774 @@ +/***************************************************************************** +* sdla_adccp.h Sangoma HDLC LAPB firmware API definitions. +* +* Author: Nenad Corbic +* +* Copyright: (c) 1995-2003 Sangoma Technologies Inc. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version + 2 of the License, or (at your option) any later version. +* ============================================================================ +* Apr 30, 2003 Nenad Corbic Initial Version +*****************************************************************************/ + +#ifndef _SDLA_ADCCP_H +#define _SDLA_ADCCP_H + +/*---------------------------------------------------------------------------- + * Notes: + * ------ + * 1. All structures defined in this file are byte-alined. + * Compiler Platform + * -------- -------- + * GNU C Linux + * + */ + +#ifndef PACKED +# define PACKED __attribute__((packed)) +#endif /* PACKED */ + +/****** CONSTANTS DEFINITIONS ***********************************************/ + +#define X25_MAX_CHAN 255 /* max number of open X.25 circuits */ +#define X25_MAX_DATA 1024 /* max length of X.25 data buffer */ +/* + * X.25 shared memory layout. + */ +#define X25_MBOX_OFFS 0x16B0 /* general mailbox block */ +#define X25_RXMBOX_OFFS 0x1AD0 /* receive mailbox */ +#define X25_STATUS_OFFS 0x1EF8 /* X.25 status structure */ + +#define X25_MB_VECTOR 0xE000 /* S514 mailbox window vecotr */ +#define X25_MISC_HDLC_BITS 0x1EFF /*X.25 miscallaneous HDLC bits */ + +/* code levels */ +#define HDLC_LEVEL 0x01 +#define X25_LEVEL 0x02 +#define X25_AND_HDLC_LEVEL 0x03 +#define DO_HDLC_LEVEL_ERROR_CHECKING 0x04 + +/****** DATA STRUCTURES *****************************************************/ + +/*---------------------------------------------------------------------------- + * X.25 Command Block. + */ +typedef struct X25Cmd +{ + unsigned char command PACKED; /* command code */ + unsigned short length PACKED; /* transfer data length */ + unsigned char result PACKED; /* return code */ + unsigned char pf PACKED; /* P/F bit */ + unsigned short lcn PACKED; /* logical channel */ + unsigned char qdm PACKED; /* Q/D/M bits */ + unsigned char cause PACKED; /* cause field */ + unsigned char diagn PACKED; /* diagnostics */ + unsigned char pktType PACKED; /* packet type */ + unsigned char resrv[4] PACKED; /* reserved */ +} TX25Cmd; + +/* + * Defines for the 'command' field. + */ +/*----- General commands --------------*/ +#define X25_SET_GLOBAL_VARS 0x0B /* set global variables */ +#define X25_READ_MODEM_STATUS 0x0C /* read modem status */ +#define X25_READ_CODE_VERSION 0x15 /* read firmware version number */ +#define X25_TRACE_CONFIGURE 0x14 /* configure trace facility */ +#define X25_READ_TRACE_DATA 0x16 /* read trace data */ +#define X25_SET_INTERRUPT_MODE 0x17 /* set interrupt generation mode */ +#define X25_READ_INTERRUPT_MODE 0x18 /* read interrupt generation mode */ +/*----- HDLC-level commands -----------*/ +#define X25_HDLC_LINK_CONFIGURE 0x01 /* configure HDLC link level */ +#define X25_HDLC_LINK_OPEN 0x02 /* open HDLC link */ +#define X25_HDLC_LINK_CLOSE 0x03 /* close HDLC link */ +#define X25_HDLC_LINK_SETUP 0x04 /* set up HDLC link */ +#define X25_HDLC_LINK_DISC 0x05 /* disconnect DHLC link */ +#define X25_HDLC_LINK_STATUS 0x06 /* read DHLC link status */ +#define X25_HDLC_READ_STATS 0x07 /* read operational statistics */ +#define X25_HDLC_FLUSH_STATS 0x08 /* flush operational statistics */ +#define X25_HDLC_READ_COMM_ERR 0x09 /* read error statistics */ +#define X25_HDLC_FLUSH_COMM_ERR 0x0A /* flush error statistics */ +#define X25_HDLC_FLUSH_BUFFERS 0x0D /* flush HDLC-level data buffers */ +#define X25_HDLC_SPRVS_CNT_STAT 0x0F /* read surervisory count status */ +#define X25_HDLC_SEND_UI_FRAME 0x10 /* send unnumbered information frame */ +#define X25_HDLC_WRITE 0x11 /* send HDLC information frame */ +#define X25_HDLC_READ 0x21 /* read HDLC information frame */ +#define X25_HDLC_READ_CONFIG 0x12 /* read HDLC configuration */ +#define X25_HDLC_SET_CONFIG 0x13 /* set HDLC configuration */ +#define SET_PROTOCOL_LEVEL 0x1F /* set protocol level */ +/*----- X.25-level commands -----------*/ +#define X25_READ 0x22 /* read X.25 packet */ +#define X25_WRITE 0x23 /* send X.25 packet */ +#define X25_PLACE_CALL 0x30 /* place a call on SVC */ +#define X25_ACCEPT_CALL 0x31 /* accept incomming call */ +#define X25_CLEAR_CALL 0x32 /* clear call */ +#define X25_CLEAR_CONFRM 0x33 /* send clear confirmation packet */ +#define X25_RESET 0x34 /* send reset request packet */ +#define X25_RESET_CONFRM 0x35 /* send reset confirmation packet */ +#define X25_RESTART 0x36 /* send restart request packet */ +#define X25_RESTART_CONFRM 0x37 /* send restart confirmation packet */ +#define X25_WP_INTERRUPT 0x38 /* send interrupt request packet */ +#define X25_INTERRUPT_CONFRM 0x39 /* send interrupt confirmation pkt */ +#define X25_REGISTRATION_RQST 0x3A /* send registration request packet */ +#define X25_REGISTRATION_CONFRM 0x3B /* send registration confirmation */ +#define X25_IS_DATA_AVAILABLE 0x40 /* querry receive queue */ +#define X25_INCOMMING_CALL_CTL 0x41 /* select incomming call options */ +#define X25_CONFIGURE_PVC 0x42 /* configure PVC */ +#define X25_GET_ACTIVE_CHANNELS 0x43 /* get a list of active circuits */ +#define X25_READ_CHANNEL_CONFIG 0x44 /* read virt. circuit configuration */ +#define X25_FLUSH_DATA_BUFFERS 0x45 /* flush X.25-level data buffers */ +#define X25_READ_HISTORY_TABLE 0x46 /* read asynchronous event log */ +#define X25_HISTORY_TABLE_CTL 0x47 /* control asynchronous event log */ +#define X25_GET_TX_D_BIT_STATUS 0x48 /* is packet with D-bit acknowleged */ +#define X25_READ_STATISTICS 0x49 /* read X.25-level statistics */ +#define X25_FLUSH_STATISTICS 0x4A /* flush X.25-level statistics */ +#define X25_READ_CONFIGURATION 0x50 /* read HDLC & X.25 configuration */ +#define X25_SET_CONFIGURATION 0x51 /* set HDLC & X.25 configuration */ + +/* + * Defines for the 'result' field. + */ +/*----- General results ---------------*/ +#define X25RES_OK 0x00 +#define X25RES_ERROR 0x01 +#define X25RES_LINK_NOT_IN_ABM 0x02 /* link is not in ABM mode */ +#define X25RES_LINK_CLOSED 0x03 +#define X25RES_INVAL_LENGTH 0x04 +#define X25RES_INVAL_CMD 0x05 +#define X25RES_UNNUMBERED_FRAME 0x06 /* unnunbered frame received */ +#define X25RES_FRM_REJECT_MODE 0x07 /* link is in Frame Reject mode */ +#define X25RES_MODEM_FAILURE 0x08 /* DCD and/or CTS dropped */ +#define X25RES_N2_RETRY_LIMIT 0x09 /* N2 retry limit has been exceeded */ +#define X25RES_INVAL_LCN 0x30 /* invalid logical channel number */ +#define X25RES_INVAL_STATE 0x31 /* channel is not in data xfer mode */ +#define X25RES_INVAL_DATA_LEN 0x32 /* invalid data length */ +#define X25RES_NOT_READY 0x33 /* no data available / buffers full */ +#define X25RES_NETWORK_DOWN 0x34 +#define X25RES_CHANNEL_IN_USE 0x35 /* there is data queued on this LCN */ +#define X25RES_REGST_NOT_SUPPRT 0x36 /* registration not supported */ +#define X25RES_INVAL_FORMAT 0x37 /* invalid packet format */ +#define X25RES_D_BIT_NOT_SUPPRT 0x38 /* D-bit pragmatics not supported */ +#define X25RES_FACIL_NOT_SUPPRT 0x39 /* Call facility not supported */ +#define X25RES_INVAL_CALL_ARG 0x3A /* errorneous call arguments */ +#define X25RES_INVAL_CALL_DATA 0x3B /* errorneous call user data */ +#define X25RES_ASYNC_PACKET 0x40 /* asynchronous packet received */ +#define X25RES_PROTO_VIOLATION 0x41 /* protocol violation occured */ +#define X25RES_PKT_TIMEOUT 0x42 /* X.25 packet time out */ +#define X25RES_PKT_RETRY_LIMIT 0x43 /* X.25 packet retry limit exceeded */ +/*----- Command-dependant results -----*/ +#define X25RES_LINK_DISC 0x00 /* HDLC_LINK_STATUS */ +#define X25RES_LINK_IN_ABM 0x01 /* HDLC_LINK_STATUS */ +#define X25RES_NO_DATA 0x01 /* HDLC_READ/READ_TRACE_DATA*/ +#define X25RES_TRACE_INACTIVE 0x02 /* READ_TRACE_DATA */ +#define X25RES_LINK_IS_OPEN 0x01 /* HDLC_LINK_OPEN */ +#define X25RES_LINK_IS_DISC 0x02 /* HDLC_LINK_DISC */ +#define X25RES_LINK_IS_CLOSED 0x03 /* HDLC_LINK_CLOSE */ +#define X25RES_INVAL_PARAM 0x31 /* INCOMMING_CALL_CTL */ +#define X25RES_INVAL_CONFIG 0x35 /* REGISTR_RQST/CONFRM */ + +/* + * Defines for the 'qdm_bits' field. + */ +#define X25CMD_Q_BIT_MASK 0x04 +#define X25CMD_D_BIT_MASK 0x02 +#define X25CMD_M_BIT_MASK 0x01 + +/* + * Defines for the 'pkt_type' field. + */ +/*----- Asynchronous events ------*/ +#define ASE_CLEAR_RQST 0x02 +#define ASE_RESET_RQST 0x04 +#define ASE_RESTART_RQST 0x08 +#define ASE_INTERRUPT 0x10 +#define ASE_DTE_REGISTR_RQST 0x20 +#define ASE_CALL_RQST 0x30 +#define ASE_CALL_ACCEPTED 0x31 +#define ASE_CLEAR_CONFRM 0x32 +#define ASE_RESET_CONFRM 0x33 +#define ASE_RESTART_CONFRM 0x34 +#define ASE_INTERRUPT_CONFRM 0x35 +#define ASE_DCE_REGISTR_CONFRM 0x36 +#define ASE_DIAGNOSTIC 0x37 +#define ASE_CALL_AUTO_CLEAR 0x38 +#define AUTO_RESPONSE_FLAG 0x80 +/*----- Time-Out events ----------*/ +#define TOE_RESTART_RQST 0x03 +#define TOE_CALL_RQST 0x05 +#define TOE_CLEAR_RQST 0x08 +#define TOE_RESET_RQST 0x0A +/*----- Protocol Violation events */ +#define PVE_CLEAR_RQST 0x32 +#define PVE_RESET_RQST 0x33 +#define PVE_RESTART_RQST 0x34 +#define PVE_DIAGNOSTIC 0x37 + +#define INTR_ON_RX_FRAME 0x01 +#define INTR_ON_TX_FRAME 0x02 +#define INTR_ON_MODEM_STATUS_CHANGE 0x04 +#define INTR_ON_COMMAND_COMPLETE 0x08 +#define INTR_ON_X25_ASY_TRANSACTION 0x10 +#define INTR_ON_TIMER 0x40 +#define DIRECT_RX_INTR_USAGE 0x80 + +#define NO_INTR_PENDING 0x00 +#define RX_INTR_PENDING 0x01 +#define TX_INTR_PENDING 0x02 +#define MODEM_INTR_PENDING 0x04 +#define COMMAND_COMPLETE_INTR_PENDING 0x08 +#define X25_ASY_TRANS_INTR_PENDING 0x10 +#define TIMER_INTR_PENDING 0x40 + +/*---------------------------------------------------------------------------- + * X.25 Mailbox. + * This structure is located at offsets X25_MBOX_OFFS and X25_RXMBOX_OFFS + * into shared memory window. + */ +typedef struct X25Mbox +{ + unsigned char opflag PACKED; /* 00h: execution flag */ + TX25Cmd cmd PACKED; /* 01h: command block */ + unsigned char data[1] PACKED; /* 10h: data buffer */ +} TX25Mbox; + +/*---------------------------------------------------------------------------- + * X.25 Time Stamp Structure. + */ +typedef struct X25TimeStamp +{ + unsigned char month PACKED; + unsigned char date PACKED; + unsigned char sec PACKED; + unsigned char min PACKED; + unsigned char hour PACKED; +} TX25TimeStamp; + +/*---------------------------------------------------------------------------- + * X.25 Status Block. + * This structure is located at offset X25_STATUS_OFF into shared memory + * window. + */ +typedef struct X25Status +{ + TX25TimeStamp tstamp PACKED; /* 08h: timestamp (BCD) */ + unsigned char iflags PACKED; /* 0Dh: interrupt flags */ + unsigned char imask PACKED; /* 0Eh: interrupt mask */ + unsigned char hdlc_status PACKED; /* 10h: misc. HDLC/X25 flags */ + unsigned char ghdlc_status PACKED; /* channel status bytes */ +} TX25Status; + +/* + * Bitmasks for the 'iflags' field. + */ +#define X25_RX_INTR 0x01 /* receive interrupt */ +#define X25_TX_INTR 0x02 /* transmit interrupt */ +#define X25_MODEM_INTR 0x04 /* modem status interrupt (CTS/DCD) */ +#define X25_EVENT_INTR 0x10 /* asyncronous event encountered */ +#define X25_CMD_INTR 0x08 /* interface command complete */ + +/* + * Bitmasks for the 'gflags' field. + */ +#define X25_HDLC_ABM 0x01 /* HDLC is in ABM mode */ +#define X25_RX_READY 0x02 /* X.25 data available */ +#define X25_TRACE_READY 0x08 /* trace data available */ +#define X25_EVENT_IND 0x20 /* asynchronous event indicator */ +#define X25_TX_READY 0x40 /* space is available in Tx buf.*/ + +/* + * Bitmasks for the 'cflags' field. + */ +#define X25_XFER_MODE 0x80 /* channel is in data transfer mode */ +#define X25_TXWIN_OPEN 0x40 /* transmit window open */ +#define X25_RXBUF_MASK 0x3F /* number of data buffers available */ + +/***************************************************************************** + * Following definitions structurize contents of the TX25Mbox.data field for + * different X.25 interface commands. + ****************************************************************************/ + +/* --------------------------------------------------------------------------- + * X25_SET_GLOBAL_VARS Command. + */ +typedef struct X25GlobalVars +{ + unsigned char resrv PACKED; /* 00h: reserved */ + unsigned char dtrCtl PACKED; /* 01h: DTR control code */ + unsigned char resErr PACKED; /* 01h: '1' - reset modem error */ +} TX25GlobalVars; + +/* + * Defines for the 'dtrCtl' field. + */ +#define X25_RAISE_DTR 0x01 +#define X25_DROP_DTR 0x02 + +/* --------------------------------------------------------------------------- + * X25_READ_MODEM_STATUS Command. + */ +typedef struct X25ModemStatus +{ + unsigned char status PACKED; /* 00h: modem status */ +} TX25ModemStatus; + +/* + * Defines for the 'status' field. + */ +#define X25_CTS_MASK 0x20 +#define X25_DCD_MASK 0x08 + +/* --------------------------------------------------------------------------- + * X25_HDLC_LINK_STATUS Command. + */ +typedef struct X25LinkStatus +{ + unsigned char txQueued PACKED; /* 00h: queued Tx I-frames*/ + unsigned char rxQueued PACKED; /* 01h: queued Rx I-frames*/ + unsigned char station PACKED; /* 02h: DTE/DCE config. */ + unsigned char reserved PACKED; /* 03h: reserved */ + unsigned char sfTally PACKED; /* 04h: supervisory frame tally */ +} TX25LinkStatus; + +/* + * Defines for the 'station' field. + */ +#define X25_STATION_DTE 0x01 /* station configured as DTE */ +#define X25_STATION_DCE 0x02 /* station configured as DCE */ + +/* --------------------------------------------------------------------------- + * X25_HDLC_READ_STATS Command. + */ +typedef struct HdlcStats +{ /* a number of ... */ + unsigned short rxIFrames PACKED; /* 00h: ready Rx I-frames */ + unsigned short rxNoseq PACKED; /* 02h: frms out-of-sequence */ + unsigned short rxNodata PACKED; /* 04h: I-frms without data */ + unsigned short rxDiscarded PACKED; /* 06h: discarded frames */ + unsigned short rxTooLong PACKED; /* 08h: frames too long */ + unsigned short rxBadAddr PACKED; /* 0Ah: frms with inval.addr*/ + unsigned short txAcked PACKED; /* 0Ch: acknowledged I-frms */ + unsigned short txRetransm PACKED; /* 0Eh: re-transmit. I-frms */ + unsigned short t1Timeout PACKED; /* 10h: T1 timeouts */ + unsigned short rxSABM PACKED; /* 12h: received SABM frames */ + unsigned short rxDISC PACKED; /* 14h: received DISC frames */ + unsigned short rxDM PACKED; /* 16h: received DM frames */ + unsigned short rxFRMR PACKED; /* 18h: FRMR frames received */ + unsigned short txSABM PACKED; /* 1Ah: transm. SABM frames*/ + unsigned short txDISC PACKED; /* 1Ch: transm. DISC frames*/ + unsigned short txDM PACKED; /* 1Eh: transm. DM frames */ + unsigned short txFRMR PACKED; /* 20h: transm. FRMR frames*/ +} THdlcStats; + +/* --------------------------------------------------------------------------- + * X25_HDLC_READ_COMM_ERR Command. + */ +typedef struct HdlcCommErr +{ /* a number of ... */ + unsigned char rxOverrun PACKED; /* 00h: Rx overrun errors */ + unsigned char rxBadCrc PACKED; /* 01h: Rx CRC errors */ + unsigned char rxAborted PACKED; /* 02h: Rx aborted frames */ + unsigned char rxDropped PACKED; /* 03h: frames lost */ + unsigned char txAborted PACKED; /* 04h: Tx aborted frames */ + unsigned char txUnderrun PACKED; /* 05h: Tx underrun errors */ + unsigned char txMissIntr PACKED; /* 06h: missed underrun ints */ + unsigned char reserved PACKED; /* 07h: reserved */ + unsigned char droppedDCD PACKED; /* 08h: times DCD dropped */ + unsigned char droppedCTS PACKED; /* 09h: times CTS dropped */ +} THdlcCommErr; + +/* --------------------------------------------------------------------------- + * X25_SET_CONFIGURATION & X25_READ_CONFIGURATION Commands. + */ +typedef struct X25Config +{ + unsigned char baudRate PACKED; /* 00h: */ + unsigned char t1 PACKED; /* 01h: */ + unsigned char t2 PACKED; /* 02h: */ + unsigned char n2 PACKED; /* 03h: */ + unsigned short hdlcMTU PACKED; /* 04h: */ + unsigned char hdlcWindow PACKED; /* 06h: */ + unsigned char t4 PACKED; /* 07h: */ + unsigned char autoModem PACKED; /* 08h: */ + unsigned char autoHdlc PACKED; /* 09h: */ + unsigned char hdlcOptions PACKED; /* 0Ah: */ + unsigned char station PACKED; /* 0Bh: */ + unsigned char local_station_address PACKED; + +#if 0 + unsigned char pktWindow PACKED; /* 0Ch: */ + unsigned short defPktSize PACKED; /* 0Dh: */ + unsigned short pktMTU PACKED; /* 0Fh: */ + unsigned short loPVC PACKED; /* 11h: */ + unsigned short hiPVC PACKED; /* 13h: */ + unsigned short loIncommingSVC PACKED; /* 15h: */ + unsigned short hiIncommingSVC PACKED; /* 17h: */ + unsigned short loTwoWaySVC PACKED; /* 19h: */ + unsigned short hiTwoWaySVC PACKED; /* 1Bh: */ + unsigned short loOutgoingSVC PACKED; /* 1Dh: */ + unsigned short hiOutgoingSVC PACKED; /* 1Fh: */ + unsigned short options PACKED; /* 21h: */ + unsigned char responseOpt PACKED; /* 23h: */ + unsigned short facil1 PACKED; /* 24h: */ + unsigned short facil2 PACKED; /* 26h: */ + unsigned short ccittFacil PACKED; /* 28h: */ + unsigned short otherFacil PACKED; /* 2Ah: */ + unsigned short ccittCompat PACKED; /* 2Ch: */ + unsigned char t10t20 PACKED; /* 2Eh: */ + unsigned char t11t21 PACKED; /* 2Fh: */ + unsigned char t12t22 PACKED; /* 30h: */ + unsigned char t13t23 PACKED; /* 31h: */ + unsigned char t16t26 PACKED; /* 32H: */ + unsigned char t28 PACKED; /* 33h: */ + unsigned char r10r20 PACKED; /* 34h: */ + unsigned char r12r22 PACKED; /* 35h: */ + unsigned char r13r23 PACKED; /* 36h: */ +#endif +} TX25Config; + +#define X25_PACKET_WINDOW 0x02 /* Default value for Window Size */ +/* --------------------------------------------------------------------------- + * X25_READ_CHANNEL_CONFIG Command. + */ +typedef struct X25ChanAlloc /*----- Channel allocation -*/ +{ + unsigned short loPVC PACKED; /* 00h: lowest PVC number */ + unsigned short hiPVC PACKED; /* 02h: highest PVC number */ + unsigned short loIncommingSVC PACKED; /* 04h: lowest incoming SVC */ + unsigned short hiIncommingSVC PACKED; /* 06h: highest incoming SVC */ + unsigned short loTwoWaySVC PACKED; /* 08h: lowest two-way SVC */ + unsigned short hiTwoWaySVC PACKED; /* 0Ah: highest two-way SVC */ + unsigned short loOutgoingSVC PACKED; /* 0Ch: lowest outgoing SVC */ + unsigned short hiOutgoingSVC PACKED; /* 0Eh: highest outgoing SVC */ +} TX25ChanAlloc; + +typedef struct X25ChanCfg /*------ Channel configuration -----*/ +{ + unsigned char type PACKED; /* 00h: channel type */ + unsigned char txConf PACKED; /* 01h: Tx packet and window sizes */ + unsigned char rxConf PACKED; /* 01h: Rx packet and window sizes */ +} TX25ChanCfg; + +/* + * Defines for the 'type' field. + */ +#define X25_PVC 0x01 /* PVC */ +#define X25_SVC_IN 0x03 /* Incoming SVC */ +#define X25_SVC_TWOWAY 0x07 /* Two-way SVC */ +#define X25_SVC_OUT 0x0B /* Outgoing SVC */ + +/*---------------------------------------------------------------------------- + * X25_READ_STATISTICS Command. + */ +typedef struct X25Stats +{ /* number of packets Tx/Rx'ed */ + unsigned short txRestartRqst PACKED; /* 00h: Restart Request */ + unsigned short rxRestartRqst PACKED; /* 02h: Restart Request */ + unsigned short txRestartConf PACKED; /* 04h: Restart Confirmation */ + unsigned short rxRestartConf PACKED; /* 06h: Restart Confirmation */ + unsigned short txResetRqst PACKED; /* 08h: Reset Request */ + unsigned short rxResetRqst PACKED; /* 0Ah: Reset Request */ + unsigned short txResetConf PACKED; /* 0Ch: Reset Confirmation */ + unsigned short rxResetConf PACKED; /* 0Eh: Reset Confirmation */ + unsigned short txCallRequest PACKED; /* 10h: Call Request */ + unsigned short rxCallRequest PACKED; /* 12h: Call Request */ + unsigned short txCallAccept PACKED; /* 14h: Call Accept */ + unsigned short rxCallAccept PACKED; /* 16h: Call Accept */ + unsigned short txClearRqst PACKED; /* 18h: Clear Request */ + unsigned short rxClearRqst PACKED; /* 1Ah: Clear Request */ + unsigned short txClearConf PACKED; /* 1Ch: Clear Confirmation */ + unsigned short rxClearConf PACKED; /* 1Eh: Clear Confirmation */ + unsigned short txDiagnostic PACKED; /* 20h: Diagnostic */ + unsigned short rxDiagnostic PACKED; /* 22h: Diagnostic */ + unsigned short txRegRqst PACKED; /* 24h: Registration Request */ + unsigned short rxRegRqst PACKED; /* 26h: Registration Request */ + unsigned short txRegConf PACKED; /* 28h: Registration Confirm.*/ + unsigned short rxRegConf PACKED; /* 2Ah: Registration Confirm.*/ + unsigned short txInterrupt PACKED; /* 2Ch: Interrupt */ + unsigned short rxInterrupt PACKED; /* 2Eh: Interrupt */ + unsigned short txIntrConf PACKED; /* 30h: Interrupt Confirm. */ + unsigned short rxIntrConf PACKED; /* 32h: Interrupt Confirm. */ + unsigned short txData PACKED; /* 34h: Data */ + unsigned short rxData PACKED; /* 36h: Data */ + unsigned short txRR PACKED; /* 38h: RR */ + unsigned short rxRR PACKED; /* 3Ah: RR */ + unsigned short txRNR PACKED; /* 3Ch: RNR */ + unsigned short rxRNR PACKED; /* 3Eh: RNR */ +} TX25Stats; + +/*---------------------------------------------------------------------------- + * X25_READ_HISTORY_TABLE Command. + */ +typedef struct X25EventLog +{ + unsigned char type PACKED; /* 00h: transaction type */ + unsigned short lcn PACKED; /* 01h: logical channel num */ + unsigned char packet PACKED; /* 03h: async packet type */ + unsigned char cause PACKED; /* 04h: X.25 cause field */ + unsigned char diag PACKED; /* 05h: X.25 diag field */ + TX25TimeStamp ts PACKED; /* 06h: time stamp */ +} TX25EventLog; + +/* + * Defines for the 'type' field. + */ +#define X25LOG_INCOMMING 0x00 +#define X25LOG_APPLICATION 0x01 +#define X25LOG_AUTOMATIC 0x02 +#define X25LOG_ERROR 0x04 +#define X25LOG_TIMEOUT 0x08 +#define X25LOG_RECOVERY 0x10 + +/* + * Defines for the 'packet' field. + */ +#define X25LOG_CALL_RQST 0x0B +#define X25LOG_CALL_ACCEPTED 0x0F +#define X25LOG_CLEAR_RQST 0x13 +#define X25LOG_CLEAR_CONFRM 0x17 +#define X25LOG_RESET_RQST 0x1B +#define X25LOG_RESET_CONFRM 0x1F +#define X25LOG_RESTART_RQST 0xFB +#define X25LOG_RESTART_COMFRM 0xFF +#define X25LOG_DIAGNOSTIC 0xF1 +#define X25LOG_DTE_REG_RQST 0xF3 +#define X25LOG_DTE_REG_COMFRM 0xF7 + +/* --------------------------------------------------------------------------- + * X25_TRACE_CONFIGURE Command. + */ +typedef struct X25TraceCfg +{ + unsigned char flags PACKED; /* 00h: trace configuration flags */ + unsigned char timeout PACKED; /* 01h: timeout for trace delay mode*/ +} TX25TraceCfg; + +/* + * Defines for the 'flags' field. + */ +#define X25_TRC_ENABLE 0x01 /* bit0: '1' - trace enabled */ +#define X25_TRC_TIMESTAMP 0x02 /* bit1: '1' - time stamping enabled*/ +#define X25_TRC_DELAY 0x04 /* bit2: '1' - trace delay enabled */ +#define X25_TRC_DATA 0x08 /* bit3: '1' - trace data packets */ +#define X25_TRC_SUPERVISORY 0x10 /* bit4: '1' - trace suprvisory pkts*/ +#define X25_TRC_ASYNCHRONOUS 0x20 /* bit5: '1' - trace asynch. packets*/ +#define X25_TRC_HDLC 0x40 /* bit6: '1' - trace all packets */ +#define X25_TRC_READ 0x80 /* bit7: '1' - get current config. */ + +/* --------------------------------------------------------------------------- + * X25_READ_TRACE_DATA Command. + */ +typedef struct X25Trace /*----- Trace data structure -------*/ +{ + unsigned short length PACKED; /* 00h: trace data length */ + unsigned char type PACKED; /* 02h: trace type */ + unsigned char lost_cnt PACKED; /* 03h: N of traces lost */ + TX25TimeStamp tstamp PACKED; /* 04h: mon/date/sec/min/hour */ + unsigned short millisec PACKED; /* 09h: ms time stamp */ + unsigned char data[0] PACKED; /* 0Bh: traced frame */ +} TX25Trace; + +/* + * Defines for the 'type' field. + */ +#define X25_TRC_TYPE_MASK 0x0F /* bits 0..3: trace type */ +#define X25_TRC_TYPE_RX_FRAME 0x00 /* received frame trace */ +#define X25_TRC_TYPE_TX_FRAME 0x01 /* transmitted frame */ +#define X25_TRC_TYPE_ERR_FRAME 0x02 /* error frame */ + +#define X25_TRC_ERROR_MASK 0xF0 /* bits 4..7: error code */ +#define X25_TRCERR_RX_ABORT 0x10 /* receive abort error */ +#define X25_TRCERR_RX_BADCRC 0x20 /* receive CRC error */ +#define X25_TRCERR_RX_OVERRUN 0x30 /* receiver overrun error */ +#define X25_TRCERR_RX_TOO_LONG 0x40 /* excessive frame length error */ +#define X25_TRCERR_TX_ABORT 0x70 /* aborted frame transmittion error */ +#define X25_TRCERR_TX_UNDERRUN 0x80 /* transmit underrun error */ + +/***************************************************************************** + * Following definitions describe HDLC frame and X.25 packet formats. + ****************************************************************************/ + +typedef struct HDLCFrame /*----- DHLC Frame Format ----------*/ +{ + unsigned char addr PACKED; /* address field */ + unsigned char cntl PACKED; /* control field */ + unsigned char data[0] PACKED; +} THDLCFrame; + +typedef struct X25Pkt /*----- X.25 Paket Format ----------*/ +{ + unsigned char lcn_hi PACKED; /* 4 MSB of Logical Channel Number */ + unsigned char lcn_lo PACKED; /* 8 LSB of Logical Channel Number */ + unsigned char type PACKED; + unsigned char data[0] PACKED; +} TX25Pkt; + +/* + * Defines for the 'lcn_hi' field. + */ +#define X25_Q_BIT_MASK 0x80 /* Data Qualifier Bit mask */ +#define X25_D_BIT_MASK 0x40 /* Delivery Confirmation Bit mask */ +#define X25_M_BITS_MASK 0x30 /* Modulo Bits mask */ +#define X25_LCN_MSB_MASK 0x0F /* LCN most significant bits mask */ + +/* + * Defines for the 'type' field. + */ +#define X25PKT_DATA 0x01 /* Data packet mask */ +#define X25PKT_SUPERVISORY 0x02 /* Supervisory packet mask */ +#define X25PKT_CALL_RQST 0x0B /* Call Request/Incoming */ +#define X25PKT_CALL_ACCEPTED 0x0F /* Call Accepted/Connected */ +#define X25PKT_CLEAR_RQST 0x13 /* Clear Request/Indication */ +#define X25PKT_CLEAR_CONFRM 0x17 /* Clear Confirmation */ +#define X25PKT_RESET_RQST 0x1B /* Reset Request/Indication */ +#define X25PKT_RESET_CONFRM 0x1F /* Reset Confirmation */ +#define X25PKT_RESTART_RQST 0xFB /* Restart Request/Indication */ +#define X25PKT_RESTART_CONFRM 0xFF /* Restart Confirmation */ +#define X25PKT_INTERRUPT 0x23 /* Interrupt */ +#define X25PKT_INTERRUPT_CONFRM 0x27 /* Interrupt Confirmation */ +#define X25PKT_DIAGNOSTIC 0xF1 /* Diagnostic */ +#define X25PKT_REGISTR_RQST 0xF3 /* Registration Request */ +#define X25PKT_REGISTR_CONFRM 0xF7 /* Registration Confirmation */ +#define X25PKT_RR_MASKED 0x01 /* Receive Ready packet after masking */ +#define X25PKT_RNR_MASKED 0x05 /* Receive Not Ready after masking */ + + +typedef struct { + TX25Cmd cmd PACKED; + char data[X25_MAX_DATA] PACKED; +} mbox_cmd_t; + + +#if 0 +typedef struct { + unsigned char qdm PACKED; /* Q/D/M bits */ + unsigned char cause PACKED; /* cause field */ + unsigned char diagn PACKED; /* diagnostics */ + unsigned char pktType PACKED; + unsigned short length PACKED; + unsigned char result PACKED; + unsigned short lcn PACKED; + char reserved[7] PACKED; +}x25api_hdr_t; + + +typedef struct { + x25api_hdr_t hdr PACKED; + char data[X25_MAX_DATA] PACKED; +}x25api_t; +#endif + +/* + * XPIPEMON Definitions + */ + +/* valid ip_protocol for UDP management */ +#define UDPMGMT_UDP_PROTOCOL 0x11 +#define UDPMGMT_XPIPE_SIGNATURE "XLINK8ND" +#define UDPMGMT_DRVRSTATS_SIGNATURE "DRVSTATS" + +/* values for request/reply byte */ +#define UDPMGMT_REQUEST 0x01 +#define UDPMGMT_REPLY 0x02 +#define UDP_OFFSET 12 + +#if 0 +typedef struct { + unsigned char opp_flag PACKED; /* the opp flag */ + unsigned char command PACKED; /* command code */ + unsigned short length PACKED; /* transfer data length */ + unsigned char result PACKED; /* return code */ + unsigned char pf PACKED; /* P/F bit */ + unsigned short lcn PACKED; /* logical channel */ + unsigned char qdm PACKED; /* Q/D/M bits */ + unsigned char cause PACKED; /* cause field */ + unsigned char diagn PACKED; /* diagnostics */ + unsigned char pktType PACKED; /* packet type */ + unsigned char resrv[4] PACKED; /* reserved */ +} cblock_t; + +typedef struct { + ip_pkt_t ip_pkt PACKED; + udp_pkt_t udp_pkt PACKED; + wp_mgmt_t wp_mgmt PACKED; + cblock_t cblock PACKED; + unsigned char data[4080] PACKED; +} x25_udp_pkt_t; +#endif + +typedef struct read_hdlc_stat { + unsigned short inf_frames_rx_ok PACKED; + unsigned short inf_frames_rx_out_of_seq PACKED; + unsigned short inf_frames_rx_no_data PACKED; + unsigned short inf_frames_rx_dropped PACKED; + unsigned short inf_frames_rx_data_too_long PACKED; + unsigned short inf_frames_rx_invalid_addr PACKED; + unsigned short inf_frames_tx_ok PACKED; + unsigned short inf_frames_tx_retransmit PACKED; + unsigned short T1_timeouts PACKED; + unsigned short SABM_frames_rx PACKED; + unsigned short DISC_frames_rx PACKED; + unsigned short DM_frames_rx PACKED; + unsigned short FRMR_frames_rx PACKED; + unsigned short SABM_frames_tx PACKED; + unsigned short DISC_frames_tx PACKED; + unsigned short DM_frames_tx PACKED; + unsigned short FRMR_frames_tx PACKED; +} read_hdlc_stat_t; + +typedef struct read_comms_err_stats{ + unsigned char overrun_err_rx PACKED; + unsigned char CRC_err PACKED; + unsigned char abort_frames_rx PACKED; + unsigned char frames_dropped_buf_full PACKED; + unsigned char abort_frames_tx PACKED; + unsigned char transmit_underruns PACKED; + unsigned char missed_tx_underruns_intr PACKED; + unsigned char reserved PACKED; + unsigned char DCD_drop PACKED; + unsigned char CTS_drop PACKED; +} read_comms_err_stats_t; + +typedef struct trace_data { + unsigned short length PACKED; + unsigned char type PACKED; + unsigned char trace_dropped PACKED; + unsigned char reserved[5] PACKED; + unsigned short timestamp PACKED; + unsigned char data PACKED; +} trace_data_t; + +enum {UDP_XPIPE_TYPE}; + +#define XPIPE_ENABLE_TRACING 0x14 +#define XPIPE_DISABLE_TRACING 0x14 +#define XPIPE_GET_TRACE_INFO 0x16 +#define XPIPE_FT1_READ_STATUS 0x74 +#define XPIPE_DRIVER_STAT_IFSEND 0x75 +#define XPIPE_DRIVER_STAT_INTR 0x76 +#define XPIPE_DRIVER_STAT_GEN 0x77 +#define XPIPE_FLUSH_DRIVER_STATS 0x78 +#define XPIPE_ROUTER_UP_TIME 0x79 +#define XPIPE_SET_FT1_MODE 0x81 +#define XPIPE_FT1_STATUS_CTRL 0x80 + + +/* error messages */ +#define NO_BUFFS_OR_CLOSED_WIN 0x33 +#define DATA_LENGTH_TOO_BIG 0x32 +#define NO_DATA_AVAILABLE 0x33 +#define Z80_TIMEOUT_ERROR 0x0a +#define NO_BUFFS 0x08 + + +/* Trace options */ +#define TRACE_DEFAULT 0x03 +#define TRACE_SUPERVISOR_FRMS 0x10 +#define TRACE_ASYNC_FRMS 0x20 +#define TRACE_ALL_HDLC_FRMS 0x40 +#define TRACE_DATA_FRMS 0x08 + + +#endif /* _SDLA_X25_H */ diff -Nur linux.org/include/linux/sdla_adsl.h linux-2.6.17/include/linux/sdla_adsl.h --- linux.org/include/linux/sdla_adsl.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/sdla_adsl.h 2006-08-30 10:07:15.000000000 +0000 @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2002 + * Alex Feldman . All rights reserved. + * + * $Id$ + */ + +/************************************************************************* + * sdla_adsl.h WANPIPE(tm) + * + * Author: Alex Feldman + * + * + * ======================================================================== + * Jun 17, 2002 Alex Feldman Initial version. + * ======================================================================== + * + ************************************************************************** + */ + +#ifndef __SDLA_ADSL_H +# define __SDLA_ADSL_H + + +#if defined(__FreeBSD__) || defined(__OpenBSD__) +# include +#elif defined(__LINUX__) || defined(__KERNEL__) +# include +#elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) +# include +#else +# error "Unsuported OS!" +#endif + +#define ADSL_TEST_DRIVER_RESPONSE 0x01 +#define ADSL_READ_DRIVER_VERSION 0x02 +#define ADSL_ROUTER_UP_TIME 0x03 + +#define ADSL_ENABLE_TRACING 0x06 +#define ADSL_DISABLE_TRACING 0x07 +#define ADSL_GET_TRACE_INFO 0x08 + +#define MAX_TRACE_TIMEOUT (HZ*10) + + +typedef struct adsl_cfg { + unsigned char adsl_framing; + unsigned char adsl_trellis; + unsigned char adsl_as0; + unsigned char adsl_as0_latency; + unsigned char adsl_as1; + unsigned char adsl_as1_latency; + unsigned char adsl_ls0; + unsigned char adsl_ls0_latency; + unsigned char adsl_ls1; + unsigned char adsl_ls1_latency; + unsigned char adsl_redundant_bytes; + unsigned char adsl_interleave_s_up; + unsigned char adsl_interleave_d_up; + unsigned char adsl_interleave_r_up; + unsigned char adsl_fast_r_up; + unsigned char adsl_interleave_s_down; + unsigned char adsl_interleave_d_down; + unsigned char adsl_interleave_r_down; + unsigned char adsl_selected_standard; +} adsl_cfg_t; + +#undef wan_udphdr_data +#define wan_udphdr_data wan_udphdr_adsl_data +#undef wan_udp_data +#define wan_udp_data wan_udp_hdr.wan_udphdr_adsl_data + +#ifdef WAN_KERNEL + +typedef struct adsl_private_area +{ + wanpipe_common_t common; + void* pAdapter; + char if_name[IFNAMSIZ]; + u_char macAddr[6]; + atomic_t udp_pkt_len; + unsigned char udp_pkt_data[sizeof(wan_udp_pkt_t)]; + unsigned char udp_pkt_src; + unsigned char remote_eth_addr[6]; + unsigned long router_start_time; + unsigned long router_up_time; + unsigned int trace_timeout; +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) + struct ifmedia media; /* media information */ +#endif +} adsl_private_area_t; + + +typedef struct adsl_trace_info +{ + unsigned long tracing_enabled; + wan_skb_queue_t trace_queue; + unsigned int trace_timeout; + unsigned int max_trace_queue; +} adsl_trace_info_t; + + +#endif /* WAN_KERNEL */ + +/*extern void* adsl_create(void* dsl_cfg, void* card, void* virt_addr, char* devname); +extern void* adsl_new_if(void*, u_char*, void*); +extern int adsl_del_if(void*); +extern int adsl_can_tx(void*); +extern int adsl_send(void*, void* tx_skb,unsigned int); +extern void adsl_timeout(void*); +extern void adsl_isr(void*); +extern void adsl_udp_cmd(void*, unsigned char, unsigned char*, unsigned short*); +extern void adsl_disable_comm(void*); +*/ +extern void adsl_lan_multicast(void*, short,char*,int); +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) +extern void adsl_atm_tasklet(void*, int); +#else +extern void adsl_atm_tasklet(unsigned long); +#endif +/* +extern void adsl_task_schedule(void*); +extern void adsl_task_kill(void*); +extern void adsl_lan_rx(void*,void*,u_int32_t,unsigned char*, int); +extern int adsl_tracing_enabled(void*); +extern void adsl_tx_complete(void*, int, int); +extern void adsl_rx_complete(void*); +extern int GpWanWriteRoom(void *pChan_ptr); +extern int GpWanOpen(void *pAdapter_ptr, unsigned char line, void *tty, void **data); +extern void GpWanClose(void *pAdapter_ptr, void *pChan_ptr); +extern int GpWanTx(void *pChan_ptr, int fromUser, const unsigned char *buffer, int bufferLen); + +extern void* adsl_get_trace_ptr(void *pAdapter_ptr); +extern int adsl_wan_interface_type(void *); +*/ +extern int adsl_queue_trace(void*, void*); + +#endif /* __SDLA_ADSL_H_ */ + diff -Nur linux.org/include/linux/sdla_adsl_iface.h linux-2.6.17/include/linux/sdla_adsl_iface.h --- linux.org/include/linux/sdla_adsl_iface.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/sdla_adsl_iface.h 2006-08-30 10:07:15.000000000 +0000 @@ -0,0 +1,97 @@ +#ifndef _ADSL_OS_ABSTR_H_ +#define _ADSL_OS_ABSTR_H_ + +/* +** DEFINED/MACROS +*/ +#ifdef __ADSL_IFACE +# define EXTERN_ADSL extern +# define EXTERN_WAN +#else +# define EXTERN_ADSL +# define EXTERN_WAN extern +#endif + +#define TRC_INCOMING_FRM 0x00 +#define TRC_OUTGOING_FRM 0x01 + +#define ADSL_BAUD_RATE 0x04 +#define ADSL_ATM_CONF 0x05 +#define ADSL_OP_STATE 0x09 +#define ADSL_COUNTERS 0x0A +#define ADSL_LAST_FAILED_STATUS 0x0B +#define ADSL_LCL_SNR_MARGIN 0x0C +#define ADSL_UPSTREAM_MARGIN_STATUS 0x0D +#define ADSL_FAILURES 0x0E +#define ADSL_ATTENUATION_STATUS 0x0F +#define ADSL_RMT_VENDOR_ID_STATUS 0x10 +#define ADSL_GET_MODULATION 0x11 +#define ADSL_START_PROGRESS 0x12 +#define ADSL_LCL_XMIT_POWER_STATUS 0x13 +#define ADSL_RMT_TX_POWER_STATUS 0x14 +#define ADSL_ACTUAL_CONFIGURATION 0x15 +#define ADSL_ACTUAL_INTERLEAVE_STATUS 0x16 +#define ADSL_ATM_CELL_COUNTER 0x17 + + +typedef struct adsl_failures +{ + unsigned long CrcErrorsPerMin; + unsigned long ExcessiveConsecutiveCrcErrorsPerTickCount; + unsigned long ExcessiveConsecutiveCrcErrorsPerMinCount; + unsigned long ExcessiveConsecutiveOverallFailureCount; +}adsl_failures_t; + +/* +** FUNCTION PROTOTYPES +*/ + +EXTERN_WAN int adsl_can_tx(void*); +EXTERN_WAN int adsl_send(void* adapter_id, void* tx_skb, unsigned int Flag); +EXTERN_ADSL void adsl_lan_rx(void*,void*,unsigned long,unsigned char*, int); + +EXTERN_ADSL void adsl_tx_complete(void*, int, int); +EXTERN_WAN void adsl_rx_complete(void*); + +EXTERN_ADSL void adsl_tty_receive(void *, unsigned char *, + unsigned char *,unsigned int); + +EXTERN_ADSL void adsl_wan_soft_intr(void *, unsigned int, unsigned long*); +EXTERN_ADSL void* adsl_ttydriver_alloc(void); +EXTERN_ADSL void adsl_ttydriver_free(void*); +EXTERN_ADSL void* adsl_termios_alloc(void); + +EXTERN_ADSL int adsl_wan_register(void *, + char *, + unsigned char); + +EXTERN_ADSL void adsl_wan_unregister(unsigned char); + + +EXTERN_ADSL int adsl_tracing_enabled(void*); +EXTERN_ADSL int adsl_trace_enqueue(void*, void*); +EXTERN_ADSL int adsl_trace_purge(void*); +EXTERN_ADSL void* adsl_trace_info_alloc(void); +EXTERN_ADSL void adsl_trace_info_init(void *trace_ptr); + + +EXTERN_WAN void* adsl_create(void*, void*, char*); +EXTERN_WAN void* adsl_new_if(void*, unsigned char*, void*); +EXTERN_WAN int adsl_wan_init(void*); +EXTERN_WAN int adsl_del_if(void*); +EXTERN_WAN void adsl_timeout(void*); +EXTERN_WAN void adsl_disable_comm(void*); +EXTERN_WAN void adsl_isr(void*); +EXTERN_WAN void adsl_udp_cmd(void*, unsigned char, unsigned char*, unsigned short*); +EXTERN_WAN void* adsl_get_trace_ptr(void *pAdapter_ptr); +EXTERN_WAN int adsl_wan_interface_type(void *); + +EXTERN_WAN int GpWanOpen(void *pAdapter_ptr, unsigned char line, void *tty, void **data); +EXTERN_WAN int GpWanClose(void *pAdapter_ptr, void *pChan_ptr); +EXTERN_WAN int GpWanTx(void *pChan_ptr, int fromUser, const unsigned char *buffer, int bufferLen); +EXTERN_WAN int GpWanWriteRoom(void *pChan_ptr); + +EXTERN_ADSL int adsl_detect_prot_header(unsigned char*,int,char*); +EXTERN_ADSL void adsl_tty_hangup(void*); + +#endif diff -Nur linux.org/include/linux/sdla_aft_te1.h linux-2.6.17/include/linux/sdla_aft_te1.h --- linux.org/include/linux/sdla_aft_te1.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/sdla_aft_te1.h 2006-08-30 10:07:15.000000000 +0000 @@ -0,0 +1,1484 @@ +/***************************************************************************** +* sdla_aft_te1.h +* +* WANPIPE(tm) AFT Hardware Support +* +* Authors: Nenad Corbic +* +* Copyright: (c) 2003-2005 Sangoma Technologies Inc. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version +* 2 of the License, or (at your option) any later version. +* ============================================================================ +* Jan 07, 2003 Nenad Corbic Initial version. +*****************************************************************************/ + + +#ifndef _SDLA_AFT_TE1_H +#define _SDLA_AFT_TE1_H + + +#ifdef WAN_KERNEL + +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) +# include +# include +#else +# include +# include +# include +#endif + +#define AFT_PORT0_OFFSET 0x00000 +#define AFT_PORT1_OFFSET 0x04000 +#define AFT_PORT2_OFFSET 0x08000 +#define AFT_PORT3_OFFSET 0x0C000 + +#define AFT_PORT4_OFFSET 0x10000 +#define AFT_PORT5_OFFSET 0x14000 +#define AFT_PORT6_OFFSET 0x18000 +#define AFT_PORT7_OFFSET 0x1C000 + +#define AFT_PORT_REG(card,reg) (reg+(0x4000*card->wandev.comm_port)) + +/*====================================================== + * GLOBAL (All Ports) + * + * AFT Chip PCI Registers + * + * Global Configuration Area for All Ports + * + *=====================================================*/ + +#define AFT_CHIP_CFG_REG 0x40 + +#define AFT_ANALOG_MCPU_IFACE_RW 0x44 + +#define AFT_WDT_CTRL_REG 0x48 +#define AFT_WDT_1TO4_CTRL_REG AFT_WDT_CTRL_REG + +#define AFT_DATA_MUX_REG 0x4C + +#define AFT_FIFO_MARK_REG 0x50 + +#define AFT_MCPU_INTERFACE_RW 0x54 + +#define AFT_ANALOG_SPI_IFACE_RW 0x54 + +#define AFT_CHIP_STAT_REG 0x58 + +#define AFT_WDT_4TO8_CTRL_REG 0x5C + + +/*================================================= + A104 CHIP CFG REGISTERS +*/ + +# define AFT_CHIPCFG_TE1_CFG_BIT 0 +# define AFT_CHIPCFG_SFR_EX_BIT 1 +# define AFT_CHIPCFG_SFR_IN_BIT 2 +# define AFT_CHIPCFG_FE_INTR_CFG_BIT 3 + +# define AFT_CHIPCFG_A104D_EC_SEC_KEY_MASK 0x7 +# define AFT_CHIPCFG_A104D_EC_SEC_KEY_SHIFT 4 + +# define AFT_CHIPCFG_A200_EC_SEC_KEY_MASK 0x3 +# define AFT_CHIPCFG_A200_EC_SEC_KEY_SHIFT 16 + +# define AFT_CHIPCFG_SPI_SLOW_BIT 5 /* Slow down SPI */ +#if 0 +# define AFT_CHIPCFG_EC_INTR_CFG_BIT 4 /* Shark or Analog */ +# define AFT_CHIPCFG_SECURITY_CFG_BIT 6 +#endif + +# define AFT_CHIPCFG_RAM_READY_BIT 7 +# define AFT_CHIPCFG_HDLC_CTRL_RDY_BIT 8 + +# define AFT_CHIPCFG_ANALOG_INTR_MASK 0x0F /* Analog */ +# define AFT_CHIPCFG_ANALOG_INTR_SHIFT 9 + +# define AFT_CHIPCFG_A108_EC_CLOCK_SRC_MASK 0x07 /* A108 */ +# define AFT_CHIPCFG_A108_EC_CLOCK_SRC_SHIFT 9 + +# define AFT_CHIPCFG_A104D_EC_SECURITY_BIT 12 +# define AFT_CHIPCFG_A108_EC_INTR_ENABLE_BIT 12 /* A108 */ + +# define AFT_CHIPCFG_EC_INTR_STAT_BIT 13 + + +/* A104 A200 A108 Differ Here + * By default any register without device name is + * common to all all. + */ + +# define AFT_CHIPCFG_P1_TDMV_INTR_BIT 14 + +# define AFT_CHIPCFG_P2_TDMV_INTR_BIT 15 +# define AFT_CHIPCFG_A200_EC_SECURITY_BIT 15 /* Analog */ +# define AFT_CHIPCFG_A108_EC_SECURITY_BIT 15 /* A108 */ + +# define AFT_CHIPCFG_P3_TDMV_INTR_BIT 16 +# define AFT_CHIPCFG_P4_TDMV_INTR_BIT 17 + +# define AFT_CHIPCFG_P1_WDT_INTR_BIT 18 +# define AFT_CHIPCFG_P2_WDT_INTR_BIT 19 +# define AFT_CHIPCFG_P3_WDT_INTR_BIT 20 +# define AFT_CHIPCFG_P4_WDT_INTR_BIT 21 + +# define AFT_CHIPCFG_A108_EC_INTER_STAT_BIT 21 /* A108 */ + +# define AFT_CHIPCFG_FE_INTR_STAT_BIT 22 +# define AFT_CHIPCFG_SECURITY_STAT_BIT 23 + + +/* A104 & A104D IRQ Status Bits */ + +# define AFT_CHIPCFG_HDLC_INTR_MASK 0x0F +# define AFT_CHIPCFG_HDLC_INTR_SHIFT 24 + +# define AFT_CHIPCFG_DMA_INTR_MASK 0x0F +# define AFT_CHIPCFG_DMA_INTR_SHIFT 28 + +# define AFT_CHIPCFG_WDT_INTR_MASK 0x0F +# define AFT_CHIPCFG_WDT_INTR_SHIFT 18 + +# define AFT_CHIPCFG_TDMV_INTR_MASK 0x0F +# define AFT_CHIPCFG_TDMV_INTR_SHIFT 14 + +# define AFT_CHIPCFG_WDT_FE_INTR_STAT 0 +# define AFT_CHIPCFG_WDT_TX_INTR_STAT 1 +# define AFT_CHIPCFG_WDT_RX_INTR_STAT 2 + + + +/* A104 & A104D Interrupt Status Funcitons */ + +static __inline u32 +aft_chipcfg_get_hdlc_intr_stats(u32 reg) +{ + reg=reg>>AFT_CHIPCFG_HDLC_INTR_SHIFT; + reg&=AFT_CHIPCFG_HDLC_INTR_MASK; + return reg; +} + +static __inline u32 +aft_chipcfg_get_analog_intr_stats(u32 reg) +{ + reg=reg>>AFT_CHIPCFG_ANALOG_INTR_SHIFT; + reg&=AFT_CHIPCFG_ANALOG_INTR_MASK; + return reg; +} + +static __inline void +aft_chipcfg_set_oct_clk_src(u32 *reg, u32 src) +{ + *reg&=~(AFT_CHIPCFG_A108_EC_CLOCK_SRC_MASK<>AFT_CHIPCFG_DMA_INTR_SHIFT; + reg&=AFT_CHIPCFG_DMA_INTR_MASK; + return reg; +} + +static __inline u32 +aft_chipcfg_get_wdt_intr_stats(u32 reg) +{ + reg=reg>>AFT_CHIPCFG_WDT_INTR_SHIFT; + reg&=AFT_CHIPCFG_WDT_INTR_MASK; + return reg; +} + +static __inline u32 +aft_chipcfg_get_tdmv_intr_stats(u32 reg) +{ + reg=reg>>AFT_CHIPCFG_TDMV_INTR_SHIFT; + reg&=AFT_CHIPCFG_TDMV_INTR_MASK; + return reg; +} + + + + +/* A108 IRQ Status Bits on CHIP_STAT_REG */ + +# define AFT_CHIPCFG_A108_WDT_INTR_MASK 0xFF +# define AFT_CHIPCFG_A108_WDT_INTR_SHIFT 0 + +# define AFT_CHIPCFG_A108_TDMV_INTR_MASK 0xFF +# define AFT_CHIPCFG_A108_TDMV_INTR_SHIFT 8 + +# define AFT_CHIPCFG_A108_FIFO_INTR_MASK 0xFF +# define AFT_CHIPCFG_A108_FIFO_INTR_SHIFT 16 + +# define AFT_CHIPCFG_A108_DMA_INTR_MASK 0xFF +# define AFT_CHIPCFG_A108_DMA_INTR_SHIFT 24 + +/* A108 Interrupt Status Functions */ + +static __inline u32 +aft_chipcfg_a108_get_fifo_intr_stats(u32 reg) +{ + reg=reg>>AFT_CHIPCFG_A108_FIFO_INTR_SHIFT; + reg&=AFT_CHIPCFG_A108_FIFO_INTR_MASK; + return reg; +} + +static __inline u32 +aft_chipcfg_a108_get_dma_intr_stats(u32 reg) +{ + reg=reg>>AFT_CHIPCFG_A108_DMA_INTR_SHIFT; + reg&=AFT_CHIPCFG_A108_DMA_INTR_MASK; + return reg; +} + +static __inline u32 +aft_chipcfg_a108_get_wdt_intr_stats(u32 reg) +{ + reg=reg>>AFT_CHIPCFG_A108_WDT_INTR_SHIFT; + reg&=AFT_CHIPCFG_A108_WDT_INTR_MASK; + return reg; +} + +static __inline u32 +aft_chipcfg_a108_get_tdmv_intr_stats(u32 reg) +{ + reg=reg>>AFT_CHIPCFG_A108_TDMV_INTR_SHIFT; + reg&=AFT_CHIPCFG_A108_TDMV_INTR_MASK; + return reg; +} + + + +static __inline u32 +aft_chipcfg_get_ec_channels(u32 reg) +{ + switch ((reg>>AFT_CHIPCFG_A104D_EC_SEC_KEY_SHIFT)&AFT_CHIPCFG_A104D_EC_SEC_KEY_MASK){ + + case 0x00: + return 0; + case 0x01: + return 32; + case 0x02: + return 64; + case 0x03: + return 96; + case 0x04: + return 128; + case 0x05: + return 256; + default: + return 0; + } + + return 0; +} + + +static __inline u32 +aft_chipcfg_get_a200_ec_channels(u32 reg) +{ + switch ((reg>>AFT_CHIPCFG_A200_EC_SEC_KEY_SHIFT)&AFT_CHIPCFG_A200_EC_SEC_KEY_MASK){ + + case 0x00: + return 0; + case 0x01: + return 16; + case 0x02: + return 32; + default: + return 0; + } + + return 0; +} + +# define AFT_WDTCTRL_MASK 0xFF +# define AFT_WDTCTRL_TIMEOUT 75 /* ms */ + +static __inline void +aft_wdt_ctrl_reset(u8 *reg) +{ + *reg=0xFF; +} +static __inline void +aft_wdt_ctrl_set(u8 *reg, u8 timeout) +{ + timeout&=AFT_WDTCTRL_MASK; + *reg=timeout; +} + + +#define AFT_FIFO_MARK_32_MASK 0x3F +#define AFT_FIFO_MARK_32_SHIFT 0 + +#define AFT_FIFO_MARK_64_MASK 0x3F +#define AFT_FIFO_MARK_64_SHIFT 6 + +#define AFT_FIFO_MARK_128_MASK 0x3F +#define AFT_FIFO_MARK_128_SHIFT 12 + +#define AFT_FIFO_MARK_256_MASK 0x3F +#define AFT_FIFO_MARK_256_SHIFT 18 + +#define AFT_FIFO_MARK_512_MASK 0x3F +#define AFT_FIFO_MARK_512_SHIFT 24 + +static __inline void +aft_fifo_mark_gset(u32 *reg, u8 mark) +{ + mark&=AFT_FIFO_MARK_32_MASK; + + *reg=0; + *reg=(mark<>AFT_LCFG_TDMV_CH_NUM_SHIFT)&AFT_LCFG_TDMV_CH_NUM_MASK; + if (cnt < 32){ + cnt++; + } + *reg&=~(AFT_LCFG_TDMV_CH_NUM_MASK<>AFT_LCFG_TDMV_CH_NUM_SHIFT)&AFT_LCFG_TDMV_CH_NUM_MASK; + if (cnt > 0){ + cnt--; + } + *reg&=~(AFT_LCFG_TDMV_CH_NUM_MASK<>AFT_DMACHAIN_TX_ADDR_CNT_SHIFT; + reg&=AFT_DMACHAIN_TX_ADDR_CNT_MASK; + return reg; +} +static __inline void +aft_dmachain_set_tx_dma_addr(u32 *reg, int addr) +{ + *reg&=~(AFT_DMACHAIN_TX_ADDR_CNT_MASK<>AFT_DMACHAIN_RX_ADDR_CNT_SHIFT; + reg&=AFT_DMACHAIN_RX_ADDR_CNT_MASK; + return reg; +} + + +static __inline void +aft_dmachain_set_rx_dma_addr(u32 *reg, int addr) +{ + *reg&=~(AFT_DMACHAIN_RX_ADDR_CNT_MASK<>AFT_TXDMA_LO_ALIGN_SHIFT; + reg&=AFT_TXDMA_LO_ALIGN_MASK; + return reg; +} + +static __inline void +aft_txdma_hi_set_dma_length(u32 *reg, int len, int align) +{ + *reg&=~(AFT_TXDMA_HI_DMA_LENGTH_MASK<>2)+align; + len&=AFT_TXDMA_HI_DMA_LENGTH_MASK; + *reg|=(len<>AFT_TXDMA_HI_DMA_LENGTH_SHIFT; + reg&=AFT_TXDMA_HI_DMA_LENGTH_MASK; + reg=reg<<2; + return reg; +} + +static __inline u32 +aft_txdma_hi_get_dma_status(u32 reg) +{ + reg=reg>>AFT_TXDMA_HI_DMA_STATUS_SHIFT; + reg&=AFT_TXDMA_HI_DMA_STATUS_MASK; + return reg; +} + +static __inline void +aft_rxdma_lo_set_alignment(u32 *reg, int align) +{ + *reg&=~(AFT_RXDMA_LO_ALIGN_MASK<>AFT_RXDMA_LO_ALIGN_SHIFT; + reg&=AFT_RXDMA_LO_ALIGN_MASK; + return reg; +} + +static __inline void +aft_rxdma_hi_set_dma_length(u32 *reg, int len, int align) +{ + *reg&=~(AFT_RXDMA_HI_DMA_LENGTH_MASK<>2)-align; + len&=AFT_RXDMA_HI_DMA_LENGTH_MASK; + *reg|=(len<>AFT_RXDMA_HI_DMA_LENGTH_SHIFT; + reg&=AFT_RXDMA_HI_DMA_LENGTH_MASK; + reg=reg<<2; + return reg; +} + +static __inline u32 +aft_rxdma_hi_get_dma_status(u32 reg) +{ + reg=reg>>AFT_RXDMA_HI_DMA_STATUS_SHIFT; + reg&=AFT_RXDMA_HI_DMA_STATUS_MASK; + return reg; +} + + +#define FIFO_32B 0x00 +#define FIFO_64B 0x01 +#define FIFO_128B 0x03 +#define FIFO_256B 0x07 +#define FIFO_512B 0x0F +#define FIFO_1024B 0x1F + + + +/*=============================================== + +*/ + +/* Default Active DMA channel used by the + * DMA Engine */ +#define AFT_DEFLT_ACTIVE_CH 0 + +#define MAX_AFT_TX_DMA_SIZE 0xFFFF + +#define MIN_WP_PRI_MTU 8 +#define DEFAULT_WP_PRI_MTU 1500 + +/* Maximum MTU for AFT card + * 8192-4=8188. This is a hardware + * limitation. + */ +#define MAX_WP_PRI_MTU 8188 + +#define MAX_DMA_PER_CH 20 +#define MIN_DMA_PER_CH 2 + +#define WP_MAX_FIFO_FRAMES 7 + +#define AFT_DEFAULT_DATA_MUX_MAP 0x01234567 +enum { + WAN_AFT_RED, + WAN_AFT_GREEN +}; + +enum { + WAN_AFT_OFF, + WAN_AFT_ON +}; + + +/*========================================== + * Board CPLD Interface Section + * + *=========================================*/ + + +#define PMC_CONTROL_REG 0x00 + +/* Used to reset the pcm + * front end + * 0: Reset Enable + * 1: Normal Operation + */ +#define PMC_RESET_BIT 0 + +/* Used to set the pmc clock + * source: + * 0 = E1 + * 1 = T1 + */ +#define PMC_CLOCK_SELECT 1 + +#define LED_CONTROL_REG 0x01 + +#define JP8_VALUE 0x02 +#define JP7_VALUE 0x01 +#define SW0_VALUE 0x04 +#define SW1_VALUE 0x08 + +/* -------------------------------------- */ + +#define WRITE_DEF_SECTOR_DSBL 0x01 +#define FRONT_END_TYPE_MASK 0x38 + +/* Moved to sdlasfm.h +#define AFT_BIT_DEV_ADDR_CLEAR 0x600 +#define AFT_BIT_DEV_ADDR_CPLD 0x200 + +#define AFT4_BIT_DEV_ADDR_CLEAR 0x800 +#define AFT4_BIT_DEV_ADDR_CPLD 0x800 +*/ + +#define MEMORY_TYPE_SRAM 0x00 +#define MEMORY_TYPE_FLASH 0x01 +#define MASK_MEMORY_TYPE_SRAM 0x10 +#define MASK_MEMORY_TYPE_FLASH 0x20 + +#define BIT_A18_SECTOR_SA4_SA7 0x20 +#define USER_SECTOR_START_ADDR 0x40000 + +#define MAX_TRACE_QUEUE 100 + +#define HDLC_FREE_LOGIC_CH 0x1F +#define AFT_DEFLT_ACTIVE_CH 0 + +static __inline unsigned short aft_valid_mtu(unsigned short mtu) +{ + if (mtu <= 128){ + return 128; + }else if (mtu <= 256){ + return 256; + }else if (mtu <= 512){ + return 512; + }else if (mtu <= 1024){ + return 1024; + }else if (mtu <= 2048){ + return 2048; + }else if (mtu <= 4096){ + return 4096; + }else if (mtu <= 8188){ + return 8188; + }else{ + return 0; + } +} + +static __inline unsigned short aft_dma_buf_bits(unsigned short dma_bufs) +{ + if (dma_bufs < 2){ + return 0; + }else if (dma_bufs < 3){ + return 1; + }else if (dma_bufs < 5){ + return 2; + }else if (dma_bufs < 9){ + return 3; + }else if (dma_bufs < 17){ + return 4; + }else{ + return 0; + } +} + + +static __inline void +aft_set_led(unsigned int color, int led_pos, int on, u32 *reg) +{ + if (color == WAN_AFT_RED){ + if (on == WAN_AFT_OFF){ + wan_clear_bit(AFT_LCFG_RED_LED_BIT,reg); + }else{ + wan_set_bit(AFT_LCFG_RED_LED_BIT,reg); + } + }else{ + if (on == WAN_AFT_OFF){ + wan_clear_bit(AFT_LCFG_GREEN_LED_BIT,reg); + }else{ + wan_set_bit(AFT_LCFG_GREEN_LED_BIT,reg); + } + } +} + +static __inline int +aft_get_num_of_slots(u32 total_slots, u32 chan_slots) +{ + int num_of_slots=0; + int i; + for (i=0;i= MAX_AFT_HW_DEV){ \ + DEBUG_EVENT("%s:%d: Critical Invalid AFT HW DEV Type %d\n", \ + __FUNCTION__,__LINE__,type); \ + return -EINVAL; \ + }\ + if (!wan_test_bit(0,&aft_hwdev[type].init)) { \ + DEBUG_EVENT("%s:%d: Critical AFT HW DEV Type %d not initialized\n", \ + __FUNCTION__,__LINE__,type); \ + return -EINVAL; \ + } + +#define ASSERT_AFT_HWDEV_VOID(type) \ + if (type >= MAX_AFT_HW_DEV){ \ + DEBUG_EVENT("%s:%d: Critical Invalid AFT HW DEV Type %d\n", \ + __FUNCTION__,__LINE__,type); \ + return; \ + }\ + if (!aft_hwdev[type] || !wan_test_bit(0,&aft_hwdev[type].init)) { \ + DEBUG_EVENT("%s:%d: Critical AFT HW DEV Type %d not initialized\n", \ + __FUNCTION__,__LINE__,type); \ + return; \ + } + + +#endif /* WAN_KERNEL */ + +/*================================================================ + * DRIVER SPECIFIC DEFINES + * + *================================================================*/ + + +#undef wan_udphdr_data +#define wan_udphdr_data wan_udphdr_u.aft.data + + +#define MAX_TRACE_BUFFER (MAX_LGTH_UDP_MGNT_PKT - \ + sizeof(iphdr_t) - \ + sizeof(udphdr_t) - \ + sizeof(wan_mgmt_t) - \ + sizeof(wan_trace_info_t) - \ + sizeof(wan_cmd_t)) + +enum { + TX_DMA_BUF_INIT =0, + TX_DMA_BUF_USED +}; + +enum { + ROUTER_UP_TIME = 0x50, + ENABLE_TRACING, + DISABLE_TRACING, + GET_TRACE_INFO, + READ_CODE_VERSION, + FLUSH_OPERATIONAL_STATS, + OPERATIONAL_STATS, + READ_OPERATIONAL_STATS, + READ_CONFIGURATION, + READ_COMMS_ERROR_STATS, + FLUSH_COMMS_ERROR_STATS, + AFT_LINK_STATUS, + AFT_MODEM_STATUS, + AFT_HWEC_STATUS +}; + +#define UDPMGMT_SIGNATURE "AFTPIPEA" + + +/* the line trace status element presented by the frame relay code */ +typedef struct { + unsigned char flag ; /* ready flag */ + unsigned short length ; /* trace length */ + unsigned char rsrv0[2] ; /* reserved */ + unsigned char attr ; /* trace attributes */ + unsigned short tmstamp ; /* time stamp */ + unsigned char rsrv1[4] ; /* reserved */ + unsigned int offset ; /* buffer absolute address */ +}aft_trc_el_t; + +typedef struct wp_rx_element +{ + unsigned int dma_addr; + unsigned int reg; + unsigned int align; + unsigned char pkt_error; +}wp_rx_element_t; + + +typedef struct aft_config +{ + unsigned int aft_chip_cfg_reg; + unsigned int aft_dma_control_reg; +}aft_config_t; + + + +#if defined(__LINUX__) +enum { + SIOC_AFT_CUSTOMER_ID = SIOC_WANPIPE_DEVPRIVATE, + SIOC_AFT_SS7_FORCE_RX, + SIOC_WANPIPE_API +}; +#endif + +#pragma pack(1) + +/* the operational statistics structure */ +typedef struct { + + /* Data frame transmission statistics */ + unsigned long Data_frames_Tx_count ; + /* # of frames transmitted */ + unsigned long Data_bytes_Tx_count ; + /* # of bytes transmitted */ + unsigned long Data_Tx_throughput ; + /* transmit throughput */ + unsigned long no_ms_for_Data_Tx_thruput_comp ; + /* millisecond time used for the Tx throughput computation */ + unsigned long Tx_Data_discard_lgth_err_count ; + + /* Data frame reception statistics */ + unsigned long Data_frames_Rx_count ; + /* number of frames received */ + unsigned long Data_bytes_Rx_count ; + /* number of bytes received */ + unsigned long Data_Rx_throughput ; + /* receive throughput */ + unsigned long no_ms_for_Data_Rx_thruput_comp ; + /* millisecond time used for the Rx throughput computation */ + unsigned long Rx_Data_discard_short_count ; + /* received Data frames discarded (too short) */ + unsigned long Rx_Data_discard_long_count ; + /* received Data frames discarded (too long) */ + unsigned long Rx_Data_discard_inactive_count ; + /* received Data frames discarded (link inactive) */ + + /* Incomming frames with a format error statistics */ + unsigned short Rx_frm_incomp_CHDLC_hdr_count ; + /* frames received of with incomplete Cisco HDLC header */ + unsigned short Rx_frms_too_long_count ; + /* frames received of excessive length count */ + + /* CHDLC link active/inactive and loopback statistics */ + unsigned short link_active_count ; + /* number of times that the link went active */ + unsigned short link_inactive_modem_count ; + /* number of times that the link went inactive (modem failure) */ + unsigned short link_inactive_keepalive_count ; + /* number of times that the link went inactive (keepalive failure) */ + unsigned short link_looped_count ; + /* link looped count */ + + unsigned long Data_frames_Tx_realign_count; + +} aft_op_stats_t; + +typedef struct { + unsigned short Rx_overrun_err_count; + unsigned short Rx_crc_err_count ; /* receiver CRC error count */ + unsigned short Rx_abort_count ; /* abort frames recvd count */ + unsigned short Rx_hdlc_corrupiton; /* receiver disabled */ + unsigned short Rx_pci_errors; /* missed tx underrun interrupt count */ + unsigned short Rx_dma_descr_err; /*secondary-abort frames tx count */ + unsigned short DCD_state_change_count ; /* DCD state change */ + unsigned short CTS_state_change_count ; /* CTS state change */ + + unsigned short Tx_pci_errors; /* missed tx underrun interrupt count */ + unsigned short Tx_dma_errors; /* missed tx underrun interrupt count */ + + unsigned int Tx_pci_latency; /* missed tx underrun interrupt count */ + unsigned int Tx_dma_len_nonzero; /* Tx dma descriptor len not zero */ + +} aft_comm_err_stats_t; + +enum wanpipe_aft_api_events { + WP_API_EVENT_NONE, + WP_API_EVENT_DTMF, + WP_API_EVENT_RXHOOK, + WP_API_EVENT_RING +}; + +#define WP_API_EVENT_ENABLE 0x01 +#define WP_API_EVENT_DISABLE 0x02 + +#define WP_API_EVENT_RXHOOK_OFF 0x01 +#define WP_API_EVENT_RXHOOK_ON 0x02 + +#define WP_API_EVENT_RING_PRESENT 0x01 +#define WP_API_EVENT_RING_STOP 0x02 + +typedef struct { + unsigned char error_flag; + unsigned short time_stamp; + unsigned char event_type; + union { + struct { + u_int16_t channel; + union { + struct { + unsigned char rbs_bits; + } rbs; + struct { + unsigned char state; + } rxhook; + struct { + unsigned char state; + } ring; + struct { + unsigned char digit; /* DTMF: digit */ + unsigned char port; /* DTMF: SOUT/ROUT */ + unsigned char type; /* DTMF: PRESET/STOP */ + } dtmf; + } u_event; + } wp_api_event; + unsigned char reserved[12]; + }hdr_u; +#define wp_api_rx_hdr_event_channel hdr_u.wp_api_event.channel +#define wp_api_rx_hdr_event_rxhook_state hdr_u.wp_api_event.u_event.rxhook.state +#define wp_api_rx_hdr_event_ring_state hdr_u.wp_api_event.u_event.ring.state +#define wp_api_rx_hdr_event_dtmf_digit hdr_u.wp_api_event.u_event.dtmf.digit +#define wp_api_rx_hdr_event_dtmf_type hdr_u.wp_api_event.u_event.dtmf.type +#define wp_api_rx_hdr_event_dtmf_port hdr_u.wp_api_event.u_event.dtmf.port +} api_rx_hdr_t; + +typedef struct { + api_rx_hdr_t api_rx_hdr; + unsigned char data[1]; +} api_rx_element_t; + +typedef struct { + unsigned char type; + unsigned char force_tx; + unsigned char data[8]; +} api_tx_ss7_hdr_t; + +typedef struct { + u_int8_t type; + u_int8_t mode; +} api_tdm_event_hdr_t; + +typedef struct { + union { + api_tx_ss7_hdr_t ss7; + api_tdm_event_hdr_t event; + unsigned char reserved[16]; + }u; +#define api_tx_hdr_event_type u.event.type +#define api_tx_hdr_event_mode u.event.mode +} api_tx_hdr_t; + +typedef struct { + api_tx_hdr_t api_tx_hdr; + unsigned char data[1]; +} api_tx_element_t; + + + + +#pragma pack() + +/* Possible RX packet errors */ +enum { + WP_FIFO_ERROR_BIT, + WP_CRC_ERROR_BIT, + WP_ABORT_ERROR_BIT, +}; + + +#ifdef WAN_KERNEL + +#define AFT_MIN_FRMW_VER 0x11 +#define AFT_TDMV_FRM_VER 0x11 +#define AFT_TDMV_FRM_CLK_SYNC_VER 0x14 +#define AFT_TDMV_SHARK_FRM_CLK_SYNC_VER 0x17 +#define AFT_TDMV_SHARK_A108_FRM_CLK_SYNC_VER 0x25 + +#define AFT_MIN_ANALOG_FRMW_VER 0x05 + +typedef struct aft_dma_chain +{ + unsigned long init; + sdla_dma_addr_t dma_addr; + u32 dma_len; + netskb_t *skb; + u32 index; + + u32 dma_descr; + u32 len_align; + u32 reg; + + u8 pkt_error; +}aft_dma_chain_t; + +typedef struct dma_history{ + u8 end; + u8 cur; + u8 begin; + u8 status; + u8 loc; +}dma_history_t; + +#define MAX_DMA_HIST_SIZE 10 +#define MAX_AFT_DMA_CHAINS 16 +#define MAX_TX_BUF MAX_AFT_DMA_CHAINS*2+1 +#define MAX_RX_BUF MAX_AFT_DMA_CHAINS*4+1 +#define AFT_DMA_INDEX_OFFSET 0x200 + + +typedef struct private_area +{ + wanpipe_common_t common; + sdla_t *card; + + wan_xilinx_conf_if_t cfg; + + wan_skb_queue_t wp_tx_pending_list; + wan_skb_queue_t wp_tx_complete_list; + netskb_t *tx_dma_skb; + u8 tx_dma_cnt; + + wan_skb_queue_t wp_rx_free_list; + wan_skb_queue_t wp_rx_complete_list; + + wan_skb_queue_t wp_rx_stack_complete_list; + wan_skb_queue_t wp_rx_zap_complete_list; + + unsigned long time_slot_map; + unsigned char num_of_time_slots; + long logic_ch_num; + + unsigned char hdlc_eng; + unsigned long dma_status; + unsigned char protocol; + + struct net_device_stats if_stats; + + int tracing_enabled; /* For enabling Tracing */ + unsigned long router_start_time; + unsigned long trace_timeout; + + unsigned long tick_counter; /* For 5s timeout counter */ + unsigned long router_up_time; + + unsigned char mc; /* Mulitcast support on/off */ + + unsigned char interface_down; + + /* Polling task queue. Each interface + * has its own task queue, which is used + * to defer events from the interrupt */ + wan_taskq_t poll_task; + wan_timer_info_t poll_delay_timer; + + u8 gateway; + u8 true_if_encoding; + +#if defined(__LINUX__) + /* Entry in proc fs per each interface */ + struct proc_dir_entry *dent; +#endif + unsigned char udp_pkt_data[sizeof(wan_udp_pkt_t)+10]; + atomic_t udp_pkt_len; + + char if_name[WAN_IFNAME_SZ+1]; + + u8 idle_flag; + u16 max_idle_size; + u8 idle_start; + + u8 pkt_error; + u8 rx_fifo_err_cnt; + + int first_time_slot; + int last_time_slot; + + netskb_t *tx_idle_skb; + unsigned char rx_dma; + unsigned char pci_retry; + + unsigned char fifo_size_code; + unsigned char fifo_base_addr; + unsigned char fifo_size; + + int dma_mru; + int mru,mtu; + + void * prot_ch; + int prot_state; + + wan_trace_t trace_info; + + /* TE1 Specific Dma Chains */ + unsigned char tx_chain_indx,tx_pending_chain_indx; + aft_dma_chain_t tx_dma_chain_table[MAX_AFT_DMA_CHAINS]; + + unsigned char rx_chain_indx,rx_pending_chain_indx; + aft_dma_chain_t rx_dma_chain_table[MAX_AFT_DMA_CHAINS]; + int rx_no_data_cnt; + + unsigned long dma_chain_status; + unsigned long up; + int tx_attempts; + + aft_op_stats_t opstats; + aft_comm_err_stats_t errstats; + + unsigned char *tx_realign_buf; + unsigned char single_dma_chain; + unsigned char tslot_sync; + + dma_history_t dma_history[MAX_DMA_HIST_SIZE]; + unsigned int dma_index; + + /* Used by ss7 mangle code */ + api_tx_hdr_t tx_api_hdr; + unsigned char *tx_ss7_realign_buf; + + int tdmv_chan; + unsigned int tdmv_irq_cfg; + + unsigned char channelized_cfg; + unsigned char tdmv_zaptel_cfg; + + unsigned int tdmv_rx_delay; + unsigned char tdmv_rx_delay_cfg; + unsigned short max_tx_bufs; + + unsigned int ss7_force_rx; + + unsigned char lip_atm; + +#if defined(__LINUX__) + wanpipe_tdm_api_dev_t wp_tdm_api_dev; +#endif + int rx_api_crc_bytes; + + struct private_area *next; + +}private_area_t; + + +void aft_free_logical_channel_num (sdla_t *card, int logic_ch); +void aft_dma_max_logic_ch(sdla_t *card); +void aft_fe_intr_ctrl(sdla_t *card, int status); +void aft_wdt_set(sdla_t *card, unsigned char val); +void aft_wdt_reset(sdla_t *card); + + +#endif + + +#endif diff -Nur linux.org/include/linux/sdla_aft_te1_iface.h linux-2.6.17/include/linux/sdla_aft_te1_iface.h --- linux.org/include/linux/sdla_aft_te1_iface.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/sdla_aft_te1_iface.h 2006-08-30 10:07:15.000000000 +0000 @@ -0,0 +1,30 @@ +/***************************************************************************** +* sdla_aft_te1_iface.h WANPIPE(tm) AFT Hardware Support +* +* Authors: Nenad Corbic +* +* Copyright: (c) 2003 Sangoma Technologies Inc. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version +* 2 of the License, or (at your option) any later version. +* ============================================================================ +* Sep 27, 2005 Nenad Corbic Initial version. +*****************************************************************************/ + + +typedef struct { + + u32 init; + + int (*hw_global_cfg) (sdla_t *card, wandev_conf_t* conf); + int (*hw_cfg) (sdla_t *card, wandev_conf_t* conf); + int (*hw_chan_cfg) (sdla_t *card, wandev_conf_t* conf); + + int (*hw_global_uncfg) (sdla_t *card); + int (*hw_uncfg) (sdla_t *card); + int (*hw_chan_uncfg) (sdla_t *card, private_area_t *chan); + +} aft_hw_iface_t; + diff -Nur linux.org/include/linux/sdla_aft_te1_ss7.h linux-2.6.17/include/linux/sdla_aft_te1_ss7.h --- linux.org/include/linux/sdla_aft_te1_ss7.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/sdla_aft_te1_ss7.h 2006-08-30 10:07:15.000000000 +0000 @@ -0,0 +1,1057 @@ +/***************************************************************************** +* sdla_xilinx.h WANPIPE(tm) S51XX Xilinx Hardware Support +* +* Authors: Nenad Corbic +* +* Copyright: (c) 2003 Sangoma Technologies Inc. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version +* 2 of the License, or (at your option) any later version. +* ============================================================================ +* Jan 07, 2003 Nenad Corbic Initial version. +*****************************************************************************/ + + +#ifndef _SDLA_AFT_TE1_SS7_H +#define _SDLA_AFT_TE1_SS7_H + + +/*====================================================== + * + * XILINX Chip PCI Registers + * + *=====================================================*/ + +/* Main configuration and status register */ +#define XILINX_CHIP_CFG_REG 0x40 + +/* Interface registers used to program + * board framer i.e. front end + * (PCM,Level1...) */ +#define XILINX_MCPU_INTERFACE 0x44 +#define XILINX_MCPU_INTERFACE_ADDR 0x46 + +#define XILINX_GLOBAL_INTER_MASK 0x4C + +/* HDLC interrupt pending registers used + * in case of an HDLC tx or rx abort condition */ +#define XILINX_HDLC_TX_INTR_PENDING_REG 0x50 +#define XILINX_HDLC_RX_INTR_PENDING_REG 0x54 + + +/* Possible RX packet errors */ +enum { + WP_FIFO_ERROR_BIT, + WP_CRC_ERROR_BIT, + WP_ABORT_ERROR_BIT, +}; + +/* Maximum number of frames in a fifo + * where frame lengths vary from 1 to 4 bytes */ +#define WP_MAX_FIFO_FRAMES 7 + + +/* DMA interrupt pending reg, used to + * signal dma tx/rx complete event on a + * specific channel */ +#define XILINX_DMA_TX_INTR_PENDING_REG 0x58 +#define XILINX_DMA_RX_INTR_PENDING_REG 0x5C + + +/* Timeslot addr reg (bits: 16-20) is used to access + * control memory in order to setup + * (physical) T1/E1 timeslot channels + * + * Logic (HDLC) Channel addr reg (bits: 0-4) is used to + * access HDLC Core internal registers. + * Used to access and configure each + * HDCL channel (tx and rx), + * in HDCL core.*/ +#define XILINX_TIMESLOT_HDLC_CHAN_REG 0x60 + +/* T3 Tx/Rx Channel Select + * + * 0=Tx Channel + * 1=Rx Channel */ +#define AFT_T3_RXTX_ADDR_SELECT_REG 0x60 + +#define XILINX_CURRENT_TIMESLOT_MASK 0x00001F00 +#define XILINX_CURRENT_TIMESLOT_SHIFT 8 + +/* HDLC data register used to + * access and configure HDLC core + * control status registers */ +#define XILINX_HDLC_CONTROL_REG 0x64 + +/* HDLC data register used to + * access and configure HDLC core + * address registers */ +#define XILINX_HDLC_ADDR_REG 0x68 + + +/* Control RAM data buffer, used to + * write/read data to/from control + * (chip) memory. + * + * The address of the memory access + * must be specified in XILINX_TIMESLOT_HDLC_CHAN_REG. + */ +#define XILINX_CONTROL_RAM_ACCESS_BUF 0x6C + + +/* Global DMA control register used to + * setup DMA engine */ +#define XILINX_DMA_CONTROL_REG 0x70 + +/* DMA tx status register is a bitmap + * status of each logical tx (HDLC) channel. + * + * Bit 0: Fifo full + * Bit 1: Fifo is ready to dma tx data from + * pci memory to tx fifo. + */ +#define XILINX_DMA_TX_STATUS_REG 0x74 + +/* TX Watchdog Timer Register + * + * Delay constant for watchdog + * timer. From 1 to 255. + * + * Minimum Interval = 1ms + * + * 0 =Reset/Disable Timer + * Ack Interrupt pending flag + * + * 1-255=Timer enabled 1ms intervals + * + * */ +#define AFT_TE3_TX_WDT_CTRL_REG 0x74 + +/* DMA rx status register is a bitmap + * status of each logical rx (HDLC) channel. + * + * Bit 0: Fifo is empty or not ready to + * dma data to pci memory. + * Bit 1: Fifo is ready to dma rx data + * into pci memory. + */ +#define XILINX_DMA_RX_STATUS_REG 0x78 + +/* RX Watchdog Timer Register + * + * Delay constant for watchdog + * timer. From 1 to 255. + * + * Minimum Interval = 1ms + * + * 0 =Reset/Disable Timer + * Ack Interrupt pending flag + * + * 1-255=Timer enabled 1ms intervals + * + * */ +#define AFT_TE3_RX_WDT_CTRL_REG 0x78 + +/* Useful in debug mode + */ +#define XILINX_DMA_DATA_REG 0x7C + + +/* AFT TE3 Current DMA descriptor address + * + * Bit 0-3: Current Tx Dma Descr + * Bit 4-7: Current Rx Dma Descr + */ +#define AFT_TE3_CRNT_DMA_DESC_ADDR_REG 0x80 + + +/* DMA descritors, RAM 128x32 + * + * To be used as offsets to the TX/RX DMA + * Descriptor, based on the channel number. + * + * Addr = Channel_Number*0xF + Tx/Rx_DMA_DESCRIPTOR_LO/HI + * + * */ +#define XILINX_TxDMA_DESCRIPTOR_LO 0x100 +#define XILINX_TxDMA_DESCRIPTOR_HI 0x104 +#define XILINX_RxDMA_DESCRIPTOR_LO 0x108 +#define XILINX_RxDMA_DESCRIPTOR_HI 0x10C + + + + + +/*====================================================== + * XILINX_CHIP_CFG_REG Bit Map + * + * Main configuration and status register + *=====================================================*/ + +/* Select between T1/T3 or E1/E3 front end + * Bit=0 : T1/T3 Bit=1 : E1/E3 */ +#define INTERFACE_TYPE_T1_E1_BIT 0 +#define INTERFACE_TYPE_T3_E3_BIT 0 + +/* Enable onboard led + * 0= On + * 1= Off */ +#define XILINX_RED_LED 1 + +/* T3 HDLC Controller Bit + * 0= HDLC mode + * 1= Transparent mode */ +#define AFT_T3_HDLC_TRANS_MODE 1 + +/* Enable frame flag generation on + * front end framers (T1/E1...) */ +#define FRONT_END_FRAME_FLAG_ENABLE_BIT 2 + +/* Select T3/E3 clock source + * 0=External/Normal + * 1=Internal/Master */ +#define AFT_T3_CLOCK_MODE 2 + + +/* Not implemented must be set to 0 */ +#define SIGNALLING_ENABLE_BIT 3 + +/* Reset front end framer (T1/E1 ...) + * Bit=1: Rest Active */ +#define FRONT_END_RESET_BIT 4 + +/* Reset the whole chip logic except + * HDLC Core: Bit=1*/ +#define CHIP_RESET_BIT 5 + +/* Reset HDLC Core: Bit=1 */ +#define HDLC_CORE_RESET_BIT 6 + +/* HDLC core ready flag + * Bit=1: HDLC Core ready for operation + * Bit=0: HDLC Core in reset state */ +#define HDLC_CORE_READY_FLAG_BIT 7 + +/* Enable or Disable all chip interrupts + * Bit=1: Enable Bit=0: Disable */ +#define GLOBAL_INTR_ENABLE_BIT 8 + +/* Enable chip interrupt on any error event. + * Bit=1: Enable Bit=0: Disable */ +#define ERROR_INTR_ENABLE_BIT 9 + +/* Reload Xilinx firmware + * Used to re-configure xilinx hardware */ +#define FRONT_END_INTR_ENABLE_BIT 10 + +/* 8bit error type, used to check for + * chip error conditions. + * Value=0: Normal Value=non zero: Error */ +#define CHIP_ERROR_MASK 0x00FF0000 + +/* This bit indicates that Tx + * Watchdog timer interrupt pending + * flag is asserted. */ +#define AFT_TE3_TX_WDT_INTR_PND 26 + + +/* This bit indicates that Rx + * Watchdog timer interrupt pending + * flag is asserted. */ +#define AFT_TE3_RX_WDT_INTR_PND 27 + + +/* Front end interrupt status bit + * Bit=1: Interrupt requested */ +#define FRONT_END_INTR_FLAG 28 + +/* Security Status Flag + * Bit=1: Security compromised and + * chip will stop operation */ +#define SECURITY_STATUS_FLAG 29 + +/* Error interrupt status bit + * Bit=1: Error occured on chip */ +#define ERROR_INTR_FLAG 30 + + +/* DMA interrupt status bit + * Bit=1: DMA inter pending register + * not equal to 0. + * + * i.e. one of DMA channels has + * generated an interrupt */ +#define DMA_INTR_FLAG 31 + + +#define XILINX_GLOBAL_INTER_STATUS 0xD0000000 + + +/*====================================================== + * XILINX_TIMESLOT_HDLC_CHAN_REG Bit Map + * + * Timeslot addr reg (bits: 16-20) is used to access + * control memory in order to setup + * (physical) T1/E1 timeslot channels + * + * Logic (HDLC) Channel addr reg (bits: 0-4) is used to + * access HDLC Core internal registers. + * Used to access and configure each + * HDCL channel (tx and rx), + * in HDCL core. + *=====================================================*/ + +/* Bit shift timeslot value (0-31) to the + * appropriate register location + * Bits: 16-20 */ +#define TIMESLOT_BIT_SHIFT 16 +#define TIMESLOT_BIT_MASK 0x001F0000 +#define HDLC_LOGIC_CH_BIT_MASK 0x0000001F + +#define HDLC_LCH_TIMESLOT_MASK 0x001F001F + +/*====================================================== + * XILINX_HDLC_CONTROL_REG + * + *=====================================================*/ + +/*======================================= + * HDLC RX Channel Status bits: 0-4 + * Indicate status of single, specified + * HDLC channel */ + +/* Status of rx channel: 1=inactive 0=active */ +#define HDLC_RX_CHAN_ENABLE_BIT 0 + +/* Rx status of a channel: + * 1=frame receiving 0=not receiving*/ +#define HDLC_RX_FRAME_DATA_BIT 1 + +/* Indicates data on HDLC channel + * 1=data present 0=idle (all 1) */ +#define HDLC_RC_CHAN_ACTIVE_BIT 2 + +/* Indicates that last frame contained an error. + * 1=frame error 0=no frame error */ +#define HDLC_RX_FRAME_ERROR_BIT 3 + +/* Indicates that last frame was aborted + * 1=frame aborted 0=frame not aborted */ +#define HDLC_RX_FRAME_ABORT_BIT 4 + + + +/*======================================= + * HDLC RX Channel Control bits: 16-21 + * Used to configure a single, specified + * rx HDLC channel */ + +/* Enable or disable HDLC protocol on + * specified channel. + * 1: Transpared Mode 0: HDLC enabled */ +#define HDLC_RX_PROT_DISABLE_BIT 16 + +/* HDLC Address recognition disable bit + * 1: No address matching (default) + * 0: normal address matching */ +#define HDLC_RX_ADDR_RECOGN_DIS_BIT 17 + +/* HDLC Address filed discard + * 1: addr filed in rx frame discarded + * 0: addr filed in rx frame passed up (dflt) */ +#define HDLC_RX_ADDR_FIELD_DISC_BIT 18 + +/* HDLC Address size + * 1: 16 bit 0: 8 bit */ +#define HDLC_RX_ADDR_SIZE_BIT 19 + +/* HDLC broadcast address matching + * 1: disable (does not match all 1's brdcst) + * 0: enable (dflt) */ +#define HDLC_RX_BRD_ADDR_MATCH_BIT 20 + +/* FCS Size + * 1: CRC-32 0: CRC-16 (default) */ +#define HDLC_RX_FCS_SIZE_BIT 21 + + +/* Idle flags are present on rx line + * 1: Idle present 0: no idle flags */ +#define HDLC_CORE_RX_IDLE_LINE_BIT 22 + +/* Abort flags are present on rx line + * 1: Abort present 0: no aborts */ +#define HDLC_CODE_RX_ABORT_LINE_BIT 23 + + + +/*======================================= + * HDLC TX Channel Control bits: 24-31 + * Used to configure a single, specified + * tx HDLC channel */ + +/* Enable or disable a specified + * HDLC tx channel. + * 1: Channel Enabled + * 0: Channel Disabled + * (tx idle all 1's in transparent mode + * (tx idle 7E in hdlc mode) */ +#define HDLC_TX_CHAN_ENABLE_BIT 24 + +/* Enable or disable HDLC protocol on + * specified tx channel. + * 1: Transpared Mode 0: HDLC enabled */ +#define HDLC_TX_PROT_DISABLE_BIT 25 + + +/* HDLC address insertion + * 1: enable 0: disable (default) */ +#define HDLC_TX_ADDR_INSERTION_BIT 26 + + +/* HDLC Tx Address size + * 1: 16 bit 0: 8 bit */ +#define HDLC_TX_ADDR_SIZE_BIT 27 + + +/* FCS Size + * 1: CRC-32 0: CRC-16 (default) */ +#define HDLC_TX_FCS_SIZE_BIT 28 + +/* Frame abort in progres or force it + * 1: frame abort 0: normal + * Set to 1 to FORCE tx frame abort */ +#define HDLC_TX_FRAME_ABORT_BIT 29 + +/* Stop tx operation on frame abort + * 1: enable 0: disable (default)*/ +#define HDLC_TX_STOP_TX_ON_ABORT_BIT 30 + +/* 1: transmit channel enabled + * 0: tx frame started */ +#define HDLC_TX_CHANNEL_ACTIVE_BIT 31 + + + +/*======================================= + * XILINX_CONTROL_RAM_ACCESS_BUF bit map + * + * Control RAM data buffer, used to + * write/read data to/from control + * (chip) memory. + * + * The address of the memory access + * must be specified in + * XILINX_TIMESLOT_HDLC_CHAN_REG. + *======================================*/ + +#define CONTROL_RAM_DATA_MASK 0x0000001F + +/* Used to define the start address of + * the fifo, per logic channel */ +#define HDLC_FIFO_BASE_ADDR_SHIFT 16 +#define HDLC_FIFO_BASE_ADDR_MASK 0x1F + +/* Used to define the size of the + * channel fifo */ +#define HDLC_FIFO_SIZE_SHIFT 8 +#define HDLC_FIFO_SIZE_MASK 0x1F + +/* Controls SS7 Operation mode + * 0 : SS7 disabled + * 1 : SS7 enabled */ +#define ENABLE_SS7_MODE 30 + +#define HDLC_FREE_LOGIC_CH 31 +#define TRANSPARENT_MODE_BIT 31 + +/*======================================= + * XILINX_DMA_CONTROL_REG bit map + * + * Global DMA control register used to + * setup DMA engine + *======================================*/ + +#define DMA_SIZE_BIT_SHIFT 0 + +/* Limit used by rx dma engine + * to trigger rx dma */ +#define DMA_FIFO_HI_MARK_BIT_SHIFT 4 + +/* Limit used by tx dma engine + * to trigger tx dma */ +#define DMA_FIFO_LO_MARK_BIT_SHIFT 8 +#define DMA_FIFO_T3_MARK_BIT_SHIFT 8 + +/* Number of active DMA channel + * pars tx/rx used: i.e. 1=1tx+1rx */ +#define DMA_ACTIVE_CHANNEL_BIT_SHIFT 16 +#define DMA_ACTIVE_CHANNEL_BIT_MASK 0xFFE0FFFF + +/* Enable or Disable DMA engine + * 1: enable 0: disable */ +#define DMA_ENGINE_ENABLE_BIT 31 + +/* Maximum size of DMA chain for + * Tx and Rx TE3 adapter + * + * 0=1 + * 1=2 + * ... + * Current maximumx 15= 16 descriptors + * per chain. + */ +#define DMA_CHAIN_TE3_MASK 0x0000000F + +/*======================================== + * XILINX_TxDMA_DESCRIPTOR_LO + * XILINX_TxDMA_DESCRIPTOR_HI + * + * TX DMA descritors Bit Map + *=======================================*/ + +/* Pointer to PC memory, i.e. pointer to + * start of a tx data frame in PC. + * Note: Pointer address must end with binary 00. + * i.e. 32 bit alignment */ +#define TxDMA_LO_PC_ADDR_PTR_BIT_MASK 0xFFFFFFFC + + +/* The tx data frame length must defined + * in increments of 32bits words. The + * alignment is used to specify real lenght + * of frames. Offset from the 32bit boundary + * + * Eg: Alignment 0x10 defines the on last + * word of tx data frame only two + * bytes are valid, and the rest is padding. + * + * N * 32 bit + * ---------------------------- + * | | + * | | + * | | | | | Last 32bit word of data + * ---------------------------- + * 11 10 01 00 : Memory Byte offset (binary) + * + * Alignment Value (binary) + * v v v v : 00 + * p p p v : 01 + * p p v v : 10 + * p v v v : 11 + * + * v=valid data byte + * p=pad value + */ +#define TxDMA_LO_ALIGNMENT_BIT_MASK 0x00000003 + + +/* Length of tx data dma block + * defined in 32bit words increments */ +#define TxDMA_HI_DMA_DATA_LENGTH_MASK 0x000007FF + +/* DMA status bits: 11-14 + * 0: Normal Operation */ +#define TxDMA_HI_DMA_PCI_ERROR_MASK 0x00007800 +#define TxDMA_HI_DMA_PCI_ERROR_M_ABRT 0x00000800 +#define TxDMA_HI_DMA_PCI_ERROR_T_ABRT 0x00001000 +#define TxDMA_HI_DMA_PCI_ERROR_DS_TOUT 0x00002000 +#define TxDMA_HI_DMA_PCI_ERROR_RETRY_TOUT 0x00004000 + + +/* SS7 Protocol Frame Length: Bits 11-14 + * + * Bits 11-12 are used for Length Alignmet + * Same as above + * + * Bits 13-14 are used for number of + * 32 bit transactions. + * + * Thus, Maximum lenght is 4*4bytes=16bytes. + * + */ +#define TxDMA_HI_DMA_SS7_FRAME_LEN_SHIFT 11 +#define TxDMA_HI_DMA_SS7_FRAME_LEN_MASK 0x0000000F + + + +/* SS7 Protocol Frame type associated + * with ENABLE_SS7_PORT_TX: + * + * 0: FISU SS7 Frame + * 1: LSSU SS7 Frame + * + */ +#define SS7_PROT_FRAME_TYPE 25 + +/* Enable SS7 Protocol in DMA TX + * 1: Enabled + * TxDMA will take the SS7 + * prot frame, after data frame. + * Save it into fifo for + * retransmission. + * + * 0: Disabled + * Only the data frame will + * be transmitted by the TxDMA. + */ +#define ENABLE_SS7_PORT_TX 27 + + +/* DMA cmd used to initialize fifo */ +#define INIT_DMA_FIFO_CMD_BIT 28 + + +/* Used to indicate that the first byte + * of tx DMA frame should trigger an + * HDLC frame start flag. + * 1: Enable */ +#define TxDMA_HI_DMA_FRAME_START_BIT 30 + + +/* Used to indicate that the last byte + * of tx DMA frame should trigger an + * HDLC frame end flag. + * 1: Enable */ +#define TxDMA_HI_DMA_FRAME_END_BIT 29 + +/* Used to trigger DMA operation for + * this channel + * Write bit Read bit + * 1: Start dma or dma active + * 0: Stop dma or dma stopped */ +#define TxDMA_HI_DMA_GO_READY_BIT 31 + + +/* Used to define the start address of + * the fifo, per logic channel */ +#define DMA_FIFO_BASE_ADDR_SHIFT 20 +#define DMA_FIFO_BASE_ADDR_MASK 0x1F + +/* Used to define the size of the + * channel fifo */ +#define DMA_FIFO_SIZE_SHIFT 15 +#define DMA_FIFO_SIZE_MASK 0x1F + +/* This mask us used to clear both + * base addres and fifo size from + * the DMA descriptor */ +#define DMA_FIFO_PARAM_CLEAR_MASK 0xFE007FFF + +#define FIFO_32B 0x00 +#define FIFO_64B 0x01 +#define FIFO_128B 0x03 +#define FIFO_256B 0x07 +#define FIFO_512B 0x0F +#define FIFO_1024B 0x1F + + +/*======================================== + * XILINX_RxDMA_DESCRIPTOR_LO + * XILINX_RxDMA_DESCRIPTOR_HI + * + * RX DMA descritors Bit Map + *=======================================*/ + +/* Pointer to PC memory, i.e. pointer to + * start of a rx data buffer in PC. + * Note: Pointer address must end with binary 00. + * i.e. 32 bit alignment */ +#define RxDMA_LO_PC_ADDR_PTR_BIT_MASK 0xFFFFFFFC + + +/* The alignment is used to specify real lenght + * of a rx data frame. Offset from the 32bit boundary. + * + * Eg: Alignment 10 (binary) indicates that last + * word of rx data frame only two + * bytes are valid, and the rest is padding. + * + * N * 32 bit + * ---------------------------- + * | | + * | | + * | | | | | Last 32bit word of data + * ---------------------------- + * 11 10 01 00 : Memory Byte offset (binary) + * + * Alignment Value (binary) + * v v v v : 11 + * p v v v : 01 + * p p v v : 10 + * p p p v : 00 + * + * v=valid data byte + * p=pad value + * + * MaxLength=User specifed maximum rx + * buffer size + * + * Length =After DMA rx interrupt, length + * will indicate number of bytes + * left in user buffer + * + * Alignment=After DMA rx interrupt, indicates + * number of padded bytes to 32bit + * boundary. + * + * Real Frame Len (in bytes)= + * (MaxLength-Length)*4 - ~(Alignment); + */ +#define RxDMA_LO_ALIGNMENT_BIT_MASK 0x00000003 + + +/* Length of rx data dma block + * defined in 32bit words increments */ +#define RxDMA_HI_DMA_DATA_LENGTH_MASK 0x000007FF + +/* DMA status bits: 16-21 + * 0: Normal Operation */ +#define RxDMA_HI_DMA_PCI_ERROR_MASK 0x00007800 +#define RxDMA_HI_DMA_PCI_ERROR_M_ABRT 0x00000800 +#define RxDMA_HI_DMA_PCI_ERROR_T_ABRT 0x00001000 +#define RxDMA_HI_DMA_PCI_ERROR_DS_TOUT 0x00002000 +#define RxDMA_HI_DMA_PCI_ERROR_RETRY_TOUT 0x00004000 + + +/* Not used */ +#define RxDMA_HI_DMA_COMMAND_BIT_SHIFT 28 + + +/* Used to indicate that the frame + * start flags exists, this is the + * first DMA transfer of an HDLC frame. + * 1: Frame start event 0: No frame start */ +#define RxDMA_HI_DMA_FRAME_START_BIT 30 + + +/* Indicates that crc error occured + * on the last frame + * 1: crc error 0: no error */ +#define RxDMA_HI_DMA_CRC_ERROR_BIT 25 + + +/* Indicates that HDLC rx abort flag + * from the line + * 1: abort occured 0: normal */ +#define RxDMA_HI_DMA_FRAME_ABORT_BIT 26 + + +/* Used to indicate that the frame + * end flags exists, this is the + * last DMA transfer of an HDLC frame. + * + * 1: Frame end event 0: No frame end */ +#define RxDMA_HI_DMA_FRAME_END_BIT 29 + +/* Used to trigger DMA operation for + * this channel + * Write bit Read bit + * 1: Start dma or dma active + * 0: Stop dma or dma stopped */ +#define RxDMA_HI_DMA_GO_READY_BIT 31 + + +/* TE3 Only bit maps for TX and RX + * Descriptors + * + * Interrupt Disable Bit + * + * 1: Interrpupt doesn't get generated + * after the end of dma descriptor. + * + * 0: Generate interrupt after + * dma descriptor + */ +#define DMA_HI_TE3_INTR_DISABLE_BIT 27 + +/* Last Frame Bit + * + * 1: This dma descr is not last thus + * proceed to the next dma chain + * + * 0: This dma descr is last in the + * dma chain. Do not go to the + * next dma desc. + * + */ +#define DMA_HI_TE3_NOT_LAST_FRAME_BIT 24 + + +/*======================================= + * AFT_TE3_CRNT_DMA_DESC_ADDR_REG + * + */ + +#define AFT_TE3_CRNT_TX_DMA_MASK 0x0000000F + +#define AFT_TE3_CRNT_RX_DMA_MASK 0x000000F0 +#define AFT_TE3_CRNT_RX_DMA_SHIFT 4 + + + + +/*=============================================== + */ + + +typedef struct xilinx_config +{ + unsigned long xilinx_chip_cfg_reg; + unsigned long xilinx_dma_control_reg; + +}xilinx_config_t; + + +/* Default length of the DMA burst + * Value indicates the maximum number + * of DMA transactions per burst */ +#define XILINX_DMA_SIZE 10 + +/* Used by DMA engine to transfer data from Fifo to PC. + * DMA engine start rx when fifo level becomes greater + * than the DMA FIFI UP value */ +#define XILINX_DMA_FIFO_UP 8 + +/* Used by DMA engine to transfer data from PC to Fifo. + * DMA engine start tx when free space in the fifo + * becomes greater than DMA FIFO LO value */ +#define XILINX_DMA_FIFO_LO 8 + +/* Used by DMA engine to transfer data from PC to Fifo. + * DMA engine start tx/rx when fifo is greater/lower + * than the DMA FIFO MARK value */ +#define AFT_T3_DMA_FIFO_MARK 8 + +/* Default Active DMA channel used by the + * DMA Engine */ +#define XILINX_DEFLT_ACTIVE_CH 0 + +#define MAX_XILINX_TX_DMA_SIZE 0xFFFF + +#define MIN_WP_PRI_MTU 10 +#define DEFAULT_WP_PRI_MTU 1500 + +/* Maximum MTU for AFT card + * 8192-4=8188. This is a hardware + * limitation. + */ +#define MAX_WP_PRI_MTU 8188 + + +enum { + SDLA_HDLC_READ_REG = SIOC_ANNEXG_PLACE_CALL, + SDLA_HDLC_WRITE_REG, + SDLA_HDLC_SET_PCI_BIOS +}; + +#define MAX_DATA_SIZE 2000 +struct sdla_hdlc_api{ + unsigned int cmd; + unsigned short len; + unsigned char bar; + unsigned short offset; + unsigned char data[MAX_DATA_SIZE]; +}; + +#pragma pack(1) +typedef struct { + unsigned char error_flag; + unsigned short time_stamp; + unsigned char reserved[13]; +} api_rx_hdr_t; + +typedef struct { + api_rx_hdr_t api_rx_hdr; + unsigned char data[1]; +} api_rx_element_t; + +typedef struct { + unsigned char ss7_prot_len; + unsigned char misc_Tx_bits; + unsigned char reserved[14]; +} api_tx_hdr_t; + +typedef struct { + api_tx_hdr_t api_tx_hdr; + unsigned char data[1]; +} api_tx_element_t; +#pragma pack() + +#undef wan_udphdr_data +#define wan_udphdr_data wan_udphdr_u.aft.data + +/*========================================== + * Board CPLD Interface Section + * + *=========================================*/ + + +#define PMC_CONTROL_REG 0x00 + +/* Used to reset the pcm + * front end + * 0: Reset Enable + * 1: Normal Operation + */ +#define PMC_RESET_BIT 0 + +/* Used to set the pmc clock + * source: + * 0 = E1 + * 1 = T1 + */ +#define PMC_CLOCK_SELECT 1 + +#define LED_CONTROL_REG 0x01 + +#define JP8_VALUE 0x02 +#define JP7_VALUE 0x01 +#define SW0_VALUE 0x04 +#define SW1_VALUE 0x08 + + +#define SECURITY_CPLD_REG 0x09 + +#define SECURITY_CPLD_MASK 0x03 +#define SECURITY_CPLD_SHIFT 0x02 + +#define SECURITY_1LINE_UNCH 0x00 +#define SECURITY_1LINE_CH 0x01 +#define SECURITY_2LINE_UNCH 0x02 +#define SECURITY_2LINE_CH 0x03 + +/* -------------------------------------- */ + +#define WRITE_DEF_SECTOR_DSBL 0x01 +#define FRONT_END_TYPE_MASK 0x38 + +#define BIT_DEV_ADDR_CLEAR 0x600 +#define BIT_DEV_ADDR_CPLD 0x200 + +#define MEMORY_TYPE_SRAM 0x00 +#define MEMORY_TYPE_FLASH 0x01 +#define MASK_MEMORY_TYPE_SRAM 0x10 +#define MASK_MEMORY_TYPE_FLASH 0x20 + +#define BIT_A18_SECTOR_SA4_SA7 0x20 +#define USER_SECTOR_START_ADDR 0x40000 + +#define MAX_TRACE_QUEUE 100 + +#define MAX_TRACE_BUFFER (MAX_LGTH_UDP_MGNT_PKT - \ + sizeof(iphdr_t) - \ + sizeof(udphdr_t) - \ + sizeof(wan_mgmt_t) - \ + sizeof(wan_trace_info_t) - \ + sizeof(wan_cmd_t)) + + +enum { + ROUTER_UP_TIME = 0x50, + ENABLE_TRACING, + DISABLE_TRACING, + GET_TRACE_INFO, + READ_CODE_VERSION, + FLUSH_OPERATIONAL_STATS, + OPERATIONAL_STATS, + READ_OPERATIONAL_STATS, + READ_CONFIGURATION, + COMMS_ERROR_STATS_STRUCT, + AFT_LINK_STATUS +}; + +#define UDPMGMT_SIGNATURE "AFTPIPEA" + +/* the line trace status element presented by the frame relay code */ +typedef struct { + unsigned char flag ; /* ready flag */ + unsigned short length ; /* trace length */ + unsigned char rsrv0[2] ; /* reserved */ + unsigned char attr ; /* trace attributes */ + unsigned short tmstamp ; /* time stamp */ + unsigned char rsrv1[4] ; /* reserved */ + unsigned long offset ; /* buffer absolute address */ +}aft_trc_el_t; + + +typedef struct wp_rx_element +{ + unsigned long dma_addr; + unsigned int reg; + unsigned int align; + unsigned char pkt_error; +}wp_rx_element_t; + + +#if defined(WAN_KERNEL) + +static inline unsigned short xilinx_valid_mtu(unsigned short mtu) +{ + if (mtu <= 128){ + return 128; + }else if (mtu <= 256){ + return 256; + }else if (mtu <= 512){ + return 512; + }else if (mtu <= 1024){ + return 1024; + }else if (mtu <= 2048){ + return 2048; + }else if (mtu <= 4096){ + return 4096; + }else if (mtu <= 8188){ + return 8188; + }else{ + return 0; + } +} + +static inline unsigned short xilinx_dma_buf_bits(unsigned short dma_bufs) +{ + if (dma_bufs < 2){ + return 0; + }else if (dma_bufs < 3){ + return 1; + }else if (dma_bufs < 5){ + return 2; + }else if (dma_bufs < 9){ + return 3; + }else if (dma_bufs < 17){ + return 4; + }else{ + return 0; + } +} + +#define AFT_TX_TIMEOUT 25 +#define AFT_RX_TIMEOUT 10 +#define AFT_MAX_WTD_TIMEOUT 250 + +static inline void aft_reset_rx_watchdog(sdla_t *card) +{ + card->hw_iface.bus_write_4(card->hw,AFT_TE3_RX_WDT_CTRL_REG,0); +} + +static inline void aft_enable_rx_watchdog(sdla_t *card, unsigned char timeout) +{ + aft_reset_rx_watchdog(card); + card->hw_iface.bus_write_4(card->hw,AFT_TE3_RX_WDT_CTRL_REG,timeout); +} + +static inline void aft_reset_tx_watchdog(sdla_t *card) +{ + card->hw_iface.bus_write_4(card->hw,AFT_TE3_TX_WDT_CTRL_REG,0); +} + +static inline void aft_enable_tx_watchdog(sdla_t *card, unsigned char timeout) +{ + aft_reset_tx_watchdog(card); + card->hw_iface.bus_write_4(card->hw,AFT_TE3_TX_WDT_CTRL_REG,timeout); +} + +#endif /* WAN_KERNEL */ + +#endif diff -Nur linux.org/include/linux/sdla_aft_te3.h linux-2.6.17/include/linux/sdla_aft_te3.h --- linux.org/include/linux/sdla_aft_te3.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/sdla_aft_te3.h 2006-08-30 10:07:15.000000000 +0000 @@ -0,0 +1,1273 @@ +/***************************************************************************** +* sdla_xilinx.h WANPIPE(tm) S51XX Xilinx Hardware Support +* +* Authors: Nenad Corbic +* +* Copyright: (c) 2003 Sangoma Technologies Inc. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version +* 2 of the License, or (at your option) any later version. +* ============================================================================ +* Jan 07, 2003 Nenad Corbic Initial version. +*****************************************************************************/ + + +#ifndef _SDLA_XILINX_H +#define _SDLA_XILINX_H + + +/*====================================================== + * + * XILINX Chip PCI Registers + * + *=====================================================*/ + +/* Main configuration and status register */ +#define XILINX_CHIP_CFG_REG 0x40 + +/* Interface registers used to program + * board framer i.e. front end + * (PCM,Level1...) */ +#define XILINX_MCPU_INTERFACE 0x44 +#define XILINX_MCPU_INTERFACE_ADDR 0x46 + +#define TE3_LOCAL_CONTROL_STATUS_REG 0x48 + +#define XILINX_GLOBAL_INTER_MASK 0x4C + +/* HDLC interrupt pending registers used + * in case of an HDLC tx or rx abort condition */ +#define XILINX_HDLC_TX_INTR_PENDING_REG 0x50 +#define XILINX_HDLC_RX_INTR_PENDING_REG 0x54 + + +/* Possible RX packet errors */ +enum { + WP_FIFO_ERROR_BIT, + WP_CRC_ERROR_BIT, + WP_ABORT_ERROR_BIT, +}; + +/* Maximum number of frames in a fifo + * where frame lengths vary from 1 to 4 bytes */ +#define WP_MAX_FIFO_FRAMES 7 + + +/* DMA interrupt pending reg, used to + * signal dma tx/rx complete event on a + * specific channel */ +#define XILINX_DMA_TX_INTR_PENDING_REG 0x58 +#define XILINX_DMA_RX_INTR_PENDING_REG 0x5C + + +/* Timeslot addr reg (bits: 16-20) is used to access + * control memory in order to setup + * (physical) T1/E1 timeslot channels + * + * Logic (HDLC) Channel addr reg (bits: 0-4) is used to + * access HDLC Core internal registers. + * Used to access and configure each + * HDCL channel (tx and rx), + * in HDCL core.*/ +#define XILINX_TIMESLOT_HDLC_CHAN_REG 0x60 + +/* T3 Tx/Rx Channel Select + * + * 0=Tx Channel + * 1=Rx Channel */ +#define AFT_T3_RXTX_ADDR_SELECT_REG 0x60 + +#define XILINX_CURRENT_TIMESLOT_MASK 0x00001F00 +#define XILINX_CURRENT_TIMESLOT_SHIFT 8 + +/* HDLC data register used to + * access and configure HDLC core + * control status registers */ +#define XILINX_HDLC_CONTROL_REG 0x64 + +/* HDLC data register used to + * access and configure HDLC core + * address registers */ +#define XILINX_HDLC_ADDR_REG 0x68 + + +/* Control RAM data buffer, used to + * write/read data to/from control + * (chip) memory. + * + * The address of the memory access + * must be specified in XILINX_TIMESLOT_HDLC_CHAN_REG. + */ +#define XILINX_CONTROL_RAM_ACCESS_BUF 0x6C + + +/* Global DMA control register used to + * setup DMA engine */ +#define XILINX_DMA_CONTROL_REG 0x70 + +/* DMA tx status register is a bitmap + * status of each logical tx (HDLC) channel. + * + * Bit 0: Fifo full + * Bit 1: Fifo is ready to dma tx data from + * pci memory to tx fifo. + */ +#define XILINX_DMA_TX_STATUS_REG 0x74 + +/* TX Watchdog Timer Register + * + * Delay constant for watchdog + * timer. From 1 to 255. + * + * Minimum Interval = 1ms + * + * 0 =Reset/Disable Timer + * Ack Interrupt pending flag + * + * 1-255=Timer enabled 1ms intervals + * + * */ +#define AFT_TE3_TX_WDT_CTRL_REG 0x74 + +/* DMA rx status register is a bitmap + * status of each logical rx (HDLC) channel. + * + * Bit 0: Fifo is empty or not ready to + * dma data to pci memory. + * Bit 1: Fifo is ready to dma rx data + * into pci memory. + */ +#define XILINX_DMA_RX_STATUS_REG 0x78 + +/* RX Watchdog Timer Register + * + * Delay constant for watchdog + * timer. From 1 to 255. + * + * Minimum Interval = 1ms + * + * 0 =Reset/Disable Timer + * Ack Interrupt pending flag + * + * 1-255=Timer enabled 1ms intervals + * + * */ +#define AFT_TE3_RX_WDT_CTRL_REG 0x78 + + +/* TE3 Fractional Encapsulation Control + * Status Register + * + */ +#define TE3_FRACT_ENCAPSULATION_REG 0x7C + + +/* AFT TE3 Current DMA descriptor address + * + * Bit 0-3: Current Tx Dma Descr + * Bit 4-7: Current Rx Dma Descr + */ +#define AFT_TE3_CRNT_DMA_DESC_ADDR_REG 0x80 + + +/* DMA descritors, RAM 128x32 + * + * To be used as offsets to the TX/RX DMA + * Descriptor, based on the channel number. + * + * Addr = Channel_Number*0xF + Tx/Rx_DMA_DESCRIPTOR_LO/HI + * + * */ +#define XILINX_TxDMA_DESCRIPTOR_LO 0x100 +#define XILINX_TxDMA_DESCRIPTOR_HI 0x104 +#define XILINX_RxDMA_DESCRIPTOR_LO 0x108 +#define XILINX_RxDMA_DESCRIPTOR_HI 0x10C + + + + + +/*====================================================== + * XILINX_CHIP_CFG_REG Bit Map + * + * Main configuration and status register + *=====================================================*/ + +/* Select between T1/T3 or E1/E3 front end + * Bit=0 : T1/T3 Bit=1 : E1/E3 */ +#define INTERFACE_TYPE_T1_E1_BIT 0 +#define INTERFACE_TYPE_T3_E3_BIT 0 + +/* Enable onboard led + * 0= On + * 1= Off */ +#define XILINX_RED_LED 1 + +/* T3 HDLC Controller Bit + * 0= HDLC mode + * 1= Transparent mode */ +#define AFT_T3_HDLC_TRANS_MODE 1 + +/* Enable frame flag generation on + * front end framers (T1/E1...) */ +#define FRONT_END_FRAME_FLAG_ENABLE_BIT 2 + +/* Select T3/E3 clock source + * 0=External/Normal + * 1=Internal/Master */ +#define AFT_T3_CLOCK_MODE 2 + +/* Interface mode: + * DS3 '0' - M13, "1" - C-Bit + * E3 '0' - G.751, "1" - G.832 */ +#define INTERFACE_MODE_DS3_C_BIT 3 +#define INTERFACE_MODE_E3_G832 3 + +/* Reset front end framer (T1/E1 ...) + * Bit=1: Rest Active */ +#define FRONT_END_RESET_BIT 4 + +/* Reset the whole chip logic except + * HDLC Core: Bit=1*/ +#define CHIP_RESET_BIT 5 + +/* Reset HDLC Core: Bit=1 */ +#define HDLC_CORE_RESET_BIT 6 + +/* HDLC core ready flag + * Bit=1: HDLC Core ready for operation + * Bit=0: HDLC Core in reset state */ +#define HDLC_CORE_READY_FLAG_BIT 7 + +/* Enable or Disable all chip interrupts + * Bit=1: Enable Bit=0: Disable */ +#define GLOBAL_INTR_ENABLE_BIT 8 + +/* Enable chip interrupt on any error event. + * Bit=1: Enable Bit=0: Disable */ +#define ERROR_INTR_ENABLE_BIT 9 + +/* Reload Xilinx firmware + * Used to re-configure xilinx hardware */ +#define FRONT_END_INTR_ENABLE_BIT 10 + +/* Enable HDLC decapsualtion + * on the TE3 Rx fractional + * data stream. + */ +#define ENABLE_TE3_FRACTIONAL 12 + + + +/* TE3 Remote Fractional Equipment + * + * This option, indicates the remote + * TE3 Fractional Device, since each + * device might have custom data endcoding. + */ +#define TE3_FRACT_REMOTE_VENDOR_SHIFT 16 +#define TE3_FRACT_REMOTE_VENDOR_MASK 0xFFF8FFFF + +#define TE3_FRACT_VENDOR_KENTROX 0 +#define TE3_FRACT_VENDOR_ADTRAN 1 +#define TE3_FRACT_VENDOR_DIGITAL 2 +#define TE3_FRACT_VENDOR_LARSCOM 3 +#define TE3_FRACT_VENDOR_VERILINK 4 + +#ifdef WAN_KERNEL +static __inline void +te3_enable_fractional(unsigned int *reg, unsigned int vendor) +{ + *reg&=TE3_FRACT_REMOTE_VENDOR_MASK; + *reg|=(vendor<>TE3_RX_FRACT_CRC_ERR_CNT_SHIFT); +} +#endif + +/* TX Section */ + +/* Tx Fractional baud rate + * + * This is a 14 bit counter, used to + * specify the period of tx buffers. + * + * The period is used to thorttle the + * tx speed from 1 to 35Mhz. + */ +#define TE3_TX_FRACT_BAUD_RATE_SHIFT 16 +#define TE3_TX_FRACT_BAUD_RATE_MASK 0xFF80FFFF + +#ifdef WAN_KERNEL +static __inline void +set_te3_tx_fract_baud_rate(unsigned int *reg, + unsigned long bitrate_khz, + unsigned int buffer_size, + unsigned char e3) +{ + /* Period for T3 and E3 clock in ns */ + unsigned long period_ns=e3?29:22; + unsigned long data_period_ns=0; + unsigned long counter=0; + + /* Get the number of bits */ + buffer_size*=8; + + data_period_ns=(buffer_size*1000000)/bitrate_khz; + + counter=data_period_ns/period_ns; + + counter=(counter>>7)&0x7F; + + *reg&=TE3_TX_FRACT_BAUD_RATE_MASK; + *reg|=(counter<> AFT_TE3_CRNT_RX_DMA_SHIFT); +} + +static __inline unsigned int +get_current_tx_dma_ptr(u32 reg) +{ + return ((reg & AFT_TE3_CRNT_TX_DMA_MASK)); +} + +static __inline void +set_current_rx_dma_ptr(u32 *reg, u32 val) +{ + *reg &= ~AFT_TE3_CRNT_RX_DMA_MASK; + *reg |= (val << AFT_TE3_CRNT_RX_DMA_SHIFT) & AFT_TE3_CRNT_RX_DMA_MASK; +} + +static __inline void +set_current_tx_dma_ptr(u32 *reg, u32 val) +{ + *reg &= ~AFT_TE3_CRNT_TX_DMA_MASK; + *reg |= val & AFT_TE3_CRNT_TX_DMA_MASK; +} + +#endif + +/*======================================= + * TE3_LOCAL_CONTROL_STATUS_REG + * + */ + +enum { + WAN_AFT_RED, + WAN_AFT_GREEN +}; + +enum { + WAN_AFT_OFF, + WAN_AFT_ON +}; + +#define TE3_D5_RED 0 +#define TE3_D5_GREEN 1 +#define TE3_D6_RED 2 +#define TE3_D6_GREEN 3 + +#ifdef WAN_KERNEL +static __inline void +aft_te3_set_led(unsigned int color, int led_pos, int on, u32 *reg) +{ + if (led_pos == 0){ + if (color == WAN_AFT_RED){ + if (on == WAN_AFT_OFF){ + wan_set_bit(TE3_D5_RED,reg); + }else{ + wan_clear_bit(TE3_D5_RED,reg); + } + }else{ + if (on == WAN_AFT_OFF){ + wan_set_bit(TE3_D5_GREEN,reg); + }else{ + wan_clear_bit(TE3_D5_GREEN,reg); + } + } + }else{ + if (color == WAN_AFT_RED){ + if (on == WAN_AFT_OFF){ + wan_set_bit(TE3_D6_RED,reg); + }else{ + wan_clear_bit(TE3_D6_RED,reg); + } + }else{ + if (on == WAN_AFT_OFF){ + wan_set_bit(TE3_D6_GREEN,reg); + }else{ + wan_clear_bit(TE3_D6_GREEN,reg); + } + } + } +} +#endif + + + + + +/*=============================================== + */ + + +typedef struct xilinx_config +{ + unsigned long xilinx_chip_cfg_reg; + unsigned long xilinx_dma_control_reg; + +}xilinx_config_t; + + +/* Default length of the DMA burst + * Value indicates the maximum number + * of DMA transactions per burst */ +#define XILINX_DMA_SIZE 10 + +/* Used by DMA engine to transfer data from Fifo to PC. + * DMA engine start rx when fifo level becomes greater + * than the DMA FIFI UP value */ +#define XILINX_DMA_FIFO_UP 8 + +/* Used by DMA engine to transfer data from PC to Fifo. + * DMA engine start tx when free space in the fifo + * becomes greater than DMA FIFO LO value */ +#define XILINX_DMA_FIFO_LO 8 + +/* Used by DMA engine to transfer data from PC to Fifo. + * DMA engine start tx/rx when fifo is greater/lower + * than the DMA FIFO MARK value */ +#define AFT_T3_DMA_FIFO_MARK 8 + +/* Default Active DMA channel used by the + * DMA Engine */ +#define XILINX_DEFLT_ACTIVE_CH 0 + +#define MAX_XILINX_TX_DMA_SIZE 0xFFFF + +#define MIN_WP_PRI_MTU 10 +#define DEFAULT_WP_PRI_MTU 1500 + +/* Maximum MTU for AFT card + * 8192-4=8188. This is a hardware + * limitation. + */ +#define MAX_WP_PRI_MTU 8188 + + +enum { +#if defined(__LINUX__) + SDLA_HDLC_READ_REG = SIOC_ANNEXG_PLACE_CALL, +#else + SDLA_HDLC_READ_REG = 0, /* FIXME !!!*/ +#endif + SDLA_HDLC_WRITE_REG, + SDLA_HDLC_SET_PCI_BIOS +}; + +#define MAX_DATA_SIZE 2000 +struct sdla_hdlc_api{ + unsigned int cmd; + unsigned short len; + unsigned char bar; + unsigned short offset; + unsigned char data[MAX_DATA_SIZE]; +}; + +struct wan_aften_api{ + unsigned int cmd; + unsigned short len; + unsigned char bar; + unsigned short offset; + unsigned char data[MAX_DATA_SIZE]; +}; + +#pragma pack(1) +typedef struct { + unsigned char error_flag; + unsigned short time_stamp; + unsigned char reserved[13]; +} api_rx_hdr_t; + +typedef struct { + api_rx_hdr_t api_rx_hdr; + unsigned char data[1]; +} api_rx_element_t; + +typedef struct { + unsigned char attr; + unsigned char misc_Tx_bits; + unsigned char reserved[14]; +} api_tx_hdr_t; + +typedef struct { + api_tx_hdr_t api_tx_hdr; + unsigned char data[1]; +} api_tx_element_t; +#pragma pack() + +#undef wan_udphdr_data +#define wan_udphdr_data wan_udphdr_u.aft.data + +/*========================================== + * Board CPLD Interface Section + * + *=========================================*/ + + +#define PMC_CONTROL_REG 0x00 + +/* Used to reset the pcm + * front end + * 0: Reset Enable + * 1: Normal Operation + */ +#define PMC_RESET_BIT 0 + +/* Used to set the pmc clock + * source: + * 0 = E1 + * 1 = T1 + */ +#define PMC_CLOCK_SELECT 1 + +#define LED_CONTROL_REG 0x01 + +#define JP8_VALUE 0x02 +#define JP7_VALUE 0x01 +#define SW0_VALUE 0x04 +#define SW1_VALUE 0x08 + + +#define SECURITY_CPLD_REG 0x09 +#define CUSTOMER_CPLD_ID_REG 0x0A + +#define SECURITY_CPLD_MASK 0x03 +#define SECURITY_CPLD_SHIFT 0x02 + +#define SECURITY_1LINE_UNCH 0x00 +#define SECURITY_1LINE_CH 0x01 +#define SECURITY_2LINE_UNCH 0x02 +#define SECURITY_2LINE_CH 0x03 + +/* -------------------------------------- */ + +#define WRITE_DEF_SECTOR_DSBL 0x01 +#define FRONT_END_TYPE_MASK 0x38 + +#define BIT_DEV_ADDR_CLEAR 0x600 +#define BIT_DEV_ADDR_CPLD 0x200 + +#define MEMORY_TYPE_SRAM 0x00 +#define MEMORY_TYPE_FLASH 0x01 +#define MASK_MEMORY_TYPE_SRAM 0x10 +#define MASK_MEMORY_TYPE_FLASH 0x20 + +#define BIT_A18_SECTOR_SA4_SA7 0x20 +#define USER_SECTOR_START_ADDR 0x40000 + +#define MAX_TRACE_QUEUE 100 + +#define MAX_TRACE_BUFFER (MAX_LGTH_UDP_MGNT_PKT - \ + sizeof(iphdr_t) - \ + sizeof(udphdr_t) - \ + sizeof(wan_mgmt_t) - \ + sizeof(wan_trace_info_t) - \ + sizeof(wan_cmd_t)) + + +enum { + ROUTER_UP_TIME = 0x50, + ENABLE_TRACING, + DISABLE_TRACING, + GET_TRACE_INFO, + READ_CODE_VERSION, + FLUSH_OPERATIONAL_STATS, + OPERATIONAL_STATS, + READ_OPERATIONAL_STATS, + READ_CONFIGURATION, + COMMS_ERROR_STATS_STRUCT, + AFT_LINK_STATUS +}; + +#define UDPMGMT_SIGNATURE "AFTPIPEA" + +/* the line trace status element presented by the frame relay code */ +typedef struct { + unsigned char flag ; /* ready flag */ + unsigned short length ; /* trace length */ + unsigned char rsrv0[2] ; /* reserved */ + unsigned char attr ; /* trace attributes */ + unsigned short tmstamp ; /* time stamp */ + unsigned char rsrv1[4] ; /* reserved */ + unsigned long offset ; /* buffer absolute address */ +}aft_trc_el_t; + + +typedef struct wp_rx_element +{ + unsigned int dma_addr; + unsigned int reg; + unsigned int align; + unsigned char pkt_error; +}wp_rx_element_t; + + +#if defined(WAN_KERNEL) + +static __inline unsigned short xilinx_valid_mtu(unsigned short mtu) +{ + if (mtu <= 128){ + return 128; + }else if (mtu <= 256){ + return 256; + }else if (mtu <= 512){ + return 512; + }else if (mtu <= 1024){ + return 1024; + }else if (mtu <= 2048){ + return 2048; + }else if (mtu <= 4096){ + return 4096; + }else if (mtu <= 8188){ + return 8188; + }else{ + return 0; + } +} + +static __inline unsigned short xilinx_dma_buf_bits(unsigned short dma_bufs) +{ + if (dma_bufs < 2){ + return 0; + }else if (dma_bufs < 3){ + return 1; + }else if (dma_bufs < 5){ + return 2; + }else if (dma_bufs < 9){ + return 3; + }else if (dma_bufs < 17){ + return 4; + }else{ + return 0; + } +} + +#define AFT_TX_TIMEOUT 5 +#define AFT_RX_TIMEOUT 2 +#define AFT_MAX_WTD_TIMEOUT 2 + +static __inline void aft_reset_rx_watchdog(sdla_t *card) +{ + card->hw_iface.bus_write_1(card->hw,AFT_TE3_RX_WDT_CTRL_REG,0); +} + +static __inline void aft_enable_rx_watchdog(sdla_t *card, unsigned char timeout) +{ + aft_reset_rx_watchdog(card); + card->hw_iface.bus_write_1(card->hw,AFT_TE3_RX_WDT_CTRL_REG,timeout); +} + +static __inline void aft_reset_tx_watchdog(sdla_t *card) +{ + card->hw_iface.bus_write_1(card->hw,AFT_TE3_TX_WDT_CTRL_REG,0); +} + +static __inline void aft_enable_tx_watchdog(sdla_t *card, unsigned char timeout) +{ + aft_reset_tx_watchdog(card); + card->hw_iface.bus_write_1(card->hw,AFT_TE3_TX_WDT_CTRL_REG,timeout); +} + + +#endif /* WAN_KERNEL */ + + +#if defined(__LINUX__) +enum { + SIOC_AFT_CUSTOMER_ID = SIOC_WANPIPE_DEVPRIVATE +}; +#endif + +#endif diff -Nur linux.org/include/linux/sdla_asy.h linux-2.6.17/include/linux/sdla_asy.h --- linux.org/include/linux/sdla_asy.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/sdla_asy.h 2006-08-30 10:07:15.000000000 +0000 @@ -0,0 +1,226 @@ +/***************************************************************************** +* sdla_asy.h Header file for the Sangoma S508/S514 asynchronous code API +* +* Author: Gideon Hack +* +* Copyright: (c) 2000 Sangoma Technologies Inc. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version +* 2 of the License, or (at your option) any later version. +* ============================================================================ +* +* Jan 28, 2000 Gideon Hack Initial Version +* +*****************************************************************************/ + + +#ifndef _WANPIPE_ASYNC_H +#define _WANPIPE_ASYNC_H + +/* ---------------------------------------------------------------------------- + * Interface commands + * --------------------------------------------------------------------------*/ + +#define SET_ASY_CONFIGURATION 0xE2 /* set the asychronous operational configuration */ +#define READ_ASY_CONFIGURATION 0xE3 /* read the current asychronous operational configuration */ +#define ENABLE_ASY_COMMUNICATIONS 0xE4 /* enable asychronous communications */ +#define DISABLE_ASY_COMMUNICATIONS 0xE5 /* disable asychronous communications */ +#define READ_ASY_OPERATIONAL_STATS 0xE7 /* retrieve the asychronous operational statistics */ +#define FLUSH_ASY_OPERATIONAL_STATS 0xE8 /* flush the asychronous operational statistics */ +#define TRANSMIT_ASY_BREAK_SIGNAL 0xEC /* transmit an asychronous break signal */ + + + +/* ---------------------------------------------------------------------------- + * Return codes from interface commands + * --------------------------------------------------------------------------*/ + +#define COMMAND_INVALID_FOR_PORT 0x50 /* the command is invalid for the selected port */ +#define DISABLE_ASY_COMMS_BEFORE_CFG 0xE1 /* communications must be disabled before setting the configuration */ +#define ASY_COMMS_ENABLED 0xE1 /* communications are currently enabled */ +#define ASY_COMMS_DISABLED 0xE1 /* communications are currently disabled */ +#define ASY_CFG_BEFORE_COMMS_ENABLED 0xE2 /* perform a SET_ASY_CONFIGURATION before enabling comms */ +#define LGTH_ASY_CFG_DATA_INVALID 0xE2 /* the length of the passed configuration data is invalid */ +#define INVALID_ASY_CFG_DATA 0xE3 /* the passed configuration data is invalid */ +#define ASY_BREAK_SIGNAL_BUSY 0xEC /* a break signal is being transmitted */ + + + +/* ---------------------------------------------------------------------------- + * Constants for the SET_ASY_CONFIGURATION/READ_ASY_CONFIGURATION command + * --------------------------------------------------------------------------*/ + +/* the asynchronous configuration structure */ +typedef struct { + unsigned long baud_rate PACKED; /* the baud rate */ + unsigned short line_config_options PACKED; /* line configuration options */ + unsigned short modem_config_options PACKED; /* modem configuration options */ + unsigned short asy_API_options PACKED; /* asynchronous API options */ + unsigned short asy_protocol_options PACKED; /* asynchronous protocol options */ + unsigned short Tx_bits_per_char PACKED; /* number of bits per tx character */ + unsigned short Rx_bits_per_char PACKED; /* number of bits per received character */ + unsigned short stop_bits PACKED; /* number of stop bits per character */ + unsigned short parity PACKED; /* parity definition */ + unsigned short break_timer PACKED; /* the break signal timer */ + unsigned short asy_Rx_inter_char_timer PACKED; /* the receive inter-character timer */ + unsigned short asy_Rx_complete_length PACKED; /* the receive 'buffer complete' length */ + unsigned short XON_char PACKED; /* the XON character */ + unsigned short XOFF_char PACKED; /* the XOFF character */ + unsigned short asy_statistics_options PACKED; /* async operational stat options */ + unsigned long ptr_shared_mem_info_struct PACKED;/* ptr to the shared memory area information structure */ + unsigned long ptr_asy_Tx_stat_el_cfg_struct PACKED;/* ptr to the transmit status element configuration structure */ + unsigned long ptr_asy_Rx_stat_el_cfg_struct PACKED;/* ptr to the receive status element configuration structure */ +} ASY_CONFIGURATION_STRUCT; + +/* permitted minimum and maximum values for setting the asynchronous configuration */ +#define MIN_ASY_BAUD_RATE 50 /* maximum baud rate */ +#define MAX_ASY_BAUD_RATE 250000 /* minimum baud rate */ +#define MIN_ASY_BITS_PER_CHAR 5 /* minimum number of bits per character */ +#define MAX_ASY_BITS_PER_CHAR 8 /* maximum number of bits per character */ +#define MIN_BREAK_TMR_VAL 0 /* minimum break signal timer */ +#define MAX_BREAK_TMR_VAL 5000 /* maximum break signal timer */ +#define MIN_ASY_RX_INTER_CHAR_TMR 0 /* minimum receive inter-character timer */ +#define MAX_ASY_RX_INTER_CHAR_TMR 30000 /* maximum receive inter-character timer */ +#define MIN_ASY_RX_CPLT_LENGTH 0 /* minimum receive 'length complete' value */ +#define MAX_ASY_RX_CPLT_LENGTH 2000 /* maximum receive 'length complete' value */ + +/* bit settings for the 'asy_API_options' */ +#define ASY_RX_DATA_TRANSPARENT 0x0001 /* do not strip parity and unused bits from received characters */ + +/* bit settings for the 'asy_protocol_options' */ +#define ASY_RTS_HS_FOR_RX 0x0001 /* RTS handshaking is used for reception control */ +#define ASY_XON_XOFF_HS_FOR_RX 0x0002 /* XON/XOFF handshaking is used for reception control */ +#define ASY_XON_XOFF_HS_FOR_TX 0x0004 /* XON/XOFF handshaking is used for transmission control */ +#define ASY_DCD_HS_FOR_TX 0x0008 /* DCD handshaking is used for transmission control */ +#define ASY_CTS_HS_FOR_TX 0x0020 /* CTS handshaking is used for transmission control */ + +/* bit settings for the 'stop_bits' definition */ +#define ONE_STOP_BIT 1 /* representation for 1 stop bit */ +#define TWO_STOP_BITS 2 /* representation for 2 stop bits */ +#define ONE_AND_A_HALF_STOP_BITS 3 /* representation for 1.5 stop bits */ + +/* bit settings for the 'parity' definition */ +#define NO_PARITY 0 /* representation for no parity */ +#define ODD_PARITY 1 /* representation for odd parity */ +#define EVEN_PARITY 2 /* representation for even parity */ + + + +/* ---------------------------------------------------------------------------- + * Constants for the READ_COMMS_ERROR_STATS command (asynchronous mode) + * --------------------------------------------------------------------------*/ + +/* the communications error statistics structure */ +typedef struct { + unsigned short Rx_overrun_err_count PACKED; /* receiver overrun error count */ + unsigned short Rx_parity_err_count PACKED; /* parity errors received count */ + unsigned short Rx_framing_err_count PACKED; /* framing errors received count */ + unsigned short comms_err_stat_reserved_1 PACKED;/* reserved for later use */ + unsigned short comms_err_stat_reserved_2 PACKED;/* reserved for later use */ + unsigned short comms_err_stat_reserved_3 PACKED;/* reserved for later use */ + unsigned short comms_err_stat_reserved_4 PACKED;/* reserved for later use */ + unsigned short comms_err_stat_reserved_5 PACKED;/* reserved for later use */ + unsigned short DCD_state_change_count PACKED; /* DCD state change count */ + unsigned short CTS_state_change_count PACKED; /* CTS state change count */ +} ASY_COMMS_ERROR_STATS_STRUCT; + + + +/* ---------------------------------------------------------------------------- + * Constants for the READ_ASY_OPERATIONAL_STATS command + * --------------------------------------------------------------------------*/ + +/* the asynchronous operational statistics structure */ +typedef struct { + + /* Data transmission statistics */ + unsigned long Data_blocks_Tx_count PACKED;/* number of blocks transmitted */ + unsigned long Data_bytes_Tx_count PACKED;/* number of bytes transmitted */ + unsigned long Data_Tx_throughput PACKED;/* transmit throughput */ + unsigned long no_ms_for_Data_Tx_thruput_comp PACKED;/* millisecond time used for the Tx throughput computation */ + unsigned long Tx_Data_discard_lgth_err_count PACKED;/* number of Data blocks discarded (length error) */ + unsigned long reserved_Data_frm_Tx_stat1 PACKED;/* reserved for later use */ + unsigned long reserved_Data_frm_Tx_stat2 PACKED;/* reserved for later use */ + unsigned long reserved_Data_frm_Tx_stat3 PACKED;/* reserved for later use */ + + /* Data reception statistics */ + unsigned long Data_blocks_Rx_count PACKED;/* number of blocks received */ + unsigned long Data_bytes_Rx_count PACKED;/* number of bytes received */ + unsigned long Data_Rx_throughput PACKED;/* receive throughput */ + unsigned long no_ms_for_Data_Rx_thruput_comp PACKED;/* millisecond time used for the Rx throughput computation */ + unsigned long Rx_Data_bytes_discard_count PACKED;/* received Data bytes discarded */ + unsigned long reserved_Data_frm_Rx_stat1 PACKED;/* reserved for later use */ + + /* handshaking protocol statistics */ + unsigned short XON_chars_Tx_count PACKED; /* number of XON characters transmitted */ + unsigned short XOFF_chars_Tx_count PACKED; /* number of XOFF characters transmitted */ + unsigned short XON_chars_Rx_count PACKED; /* number of XON characters received */ + unsigned short XOFF_chars_Rx_count PACKED; /* number of XOFF characters received */ + unsigned short Tx_halt_modem_low_count PACKED; /* number of times Tx halted (modem line low) */ + unsigned short Rx_halt_RTS_low_count PACKED; /* number of times Rx halted by setting RTS low */ + unsigned long reserved_handshaking_stat1 PACKED;/* reserved for later use */ + + /* break statistics */ + unsigned short break_Tx_count PACKED; /* number of break sequences transmitted */ + unsigned short break_Rx_count PACKED; /* number of break sequences received */ + unsigned long reserved_break_stat1 PACKED;/* reserved for later use */ + + /* miscellaneous statistics */ + unsigned long reserved_misc_stat1 PACKED; /* reserved for later use */ + unsigned long reserved_misc_stat2 PACKED; /* reserved for later use */ + +} ASY_OPERATIONAL_STATS_STRUCT; + + + +/* ---------------------------------------------------------------------------- + * Constants for Data transmission + * --------------------------------------------------------------------------*/ + +/* the Data block transmit status element configuration structure */ +typedef struct { + unsigned short number_Tx_status_elements PACKED; /* number of transmit status elements */ + unsigned long base_addr_Tx_status_elements PACKED; /* base address of the transmit element list */ + unsigned long next_Tx_status_element_to_use PACKED; /* pointer to the next transmit element to be used */ +} ASY_TX_STATUS_EL_CFG_STRUCT; + + +/* the Data block transmit status element structure */ +typedef struct { + unsigned char opp_flag PACKED; /* opp flag */ + unsigned short data_length PACKED; /* length of the block to be transmitted */ + unsigned char reserved_1 PACKED; /* reserved for internal use */ + unsigned long reserved_2 PACKED; /* reserved for internal use */ + unsigned long reserved_3 PACKED; /* reserved for internal use */ + unsigned long ptr_data_bfr PACKED; /* pointer to the data area */ +} ASY_DATA_TX_STATUS_EL_STRUCT; + + + +/* ---------------------------------------------------------------------------- + * Constants for Data reception + * --------------------------------------------------------------------------*/ + +/* the Data block receive status element configuration structure */ +typedef struct { + unsigned short number_Rx_status_elements PACKED;/* number of receive status elements */ + unsigned long base_addr_Rx_status_elements PACKED;/* base address of the receive element list */ + unsigned long next_Rx_status_element_to_use PACKED;/* pointer to the next receive element to be used */ + unsigned long base_addr_Rx_buffer PACKED;/* base address of the receive data buffer */ + unsigned long end_addr_Rx_buffer PACKED;/* end address of the receive data buffer */ +} ASY_RX_STATUS_EL_CFG_STRUCT; + +/* the Data block receive status element structure */ +typedef struct { + unsigned char opp_flag PACKED; /* opp flag */ + unsigned short data_length PACKED; /* length of the received data block */ + unsigned char reserved_1 PACKED; /* reserved for internal use */ + unsigned short time_stamp PACKED; /* receive time stamp (HDLC_STREAMING_MODE) */ + unsigned short data_buffered PACKED; /* the number of data bytes still buffered */ + unsigned long reserved_2 PACKED; /* reserved for internal use */ + unsigned long ptr_data_bfr PACKED; /* pointer to the data area */ +} ASY_DATA_RX_STATUS_EL_STRUCT; + +#endif diff -Nur linux.org/include/linux/sdla_asyhdlc.h linux-2.6.17/include/linux/sdla_asyhdlc.h --- linux.org/include/linux/sdla_asyhdlc.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/sdla_asyhdlc.h 2006-08-30 10:07:15.000000000 +0000 @@ -0,0 +1,579 @@ +/* + *********************************************************************************** + * * + * ASYAPI.H - the 'C' header file for the Sangoma S508/S514 asynchronous code API. * + * * + *********************************************************************************** +*/ + +#ifndef _SDLA_ASYHDLC_H_ +#define _SDLA_ASYHDLC_H_ + +#pragma pack(1) + +/* ---------------------------------------------------------------------------- + * Constants defining the shared memory control block (mailbox) + * --------------------------------------------------------------------------*/ + +#define PRI_BASE_ADDR_MB_STRUCT 0xE000 /* the base address of the mailbox structure (primary port) */ +#define SEC_BASE_ADDR_MB_STRUCT 0xE800 /* the base address of the mailbox structure (secondary port) */ +#define NUMBER_MB_RESERVED_BYTES 0x0B /* the number of reserved bytes in the mailbox header area */ +#define SIZEOF_MB_DATA_BFR 2032 /* the size of the actual mailbox data area */ + +/* the control block mailbox structure */ +typedef struct { + unsigned char opp_flag; /* the opp flag */ + unsigned char command; /* the user command */ + unsigned short buffer_length; /* the data length */ + unsigned char return_code; /* the return code */ + char MB_reserved[NUMBER_MB_RESERVED_BYTES]; /* reserved for later use */ + char data[SIZEOF_MB_DATA_BFR]; /* the data area */ +} ASY_MAILBOX_STRUCT; + + + +/* ---------------------------------------------------------------------------- + * Interface commands + * --------------------------------------------------------------------------*/ + +/* interface commands */ +#define READ_GLOBAL_EXCEPTION_CONDITION 0x01 /* read a global exception condition from the adapter */ +#define SET_GLOBAL_CONFIGURATION 0x02 /* set the global operational configuration */ +#define READ_GLOBAL_CONFIGURATION 0x03 /* read the global configuration */ +#define READ_GLOBAL_STATISTICS 0x04 /* retrieve the global statistics */ +#define FLUSH_GLOBAL_STATISTICS 0x05 /* flush the global statistics */ +#define SET_MODEM_STATUS 0x06 /* set the status of DTR and/or RTS */ +#define READ_MODEM_STATUS 0x07 /* read the current status of CTS and DCD */ +#define READ_COMMS_ERROR_STATS 0x08 /* read the communication error statistics */ +#define FLUSH_COMMS_ERROR_STATS 0x09 /* flush the communication error statistics */ +#define READ_ASY_CODE_VERSION 0x20 /* read the code version */ +#define SET_ASY_INTERRUPT_TRIGGERS 0x30 /* set the application interrupt triggers */ +#define READ_ASY_INTERRUPT_TRIGGERS 0x31 /* read the application interrupt trigger configuration */ +#define SET_ASY_CONFIGURATION 0xE2 /* set the asychronous operational configuration */ +#define READ_ASY_CONFIGURATION 0xE3 /* read the current asychronous operational configuration */ +#define ENABLE_ASY_COMMUNICATIONS 0xE4 /* enable asychronous communications */ +#define DISABLE_ASY_COMMUNICATIONS 0xE5 /* disable asychronous communications */ +#define READ_ASY_OPERATIONAL_STATS 0xE7 /* retrieve the asychronous operational statistics */ +#define FLUSH_ASY_OPERATIONAL_STATS 0xE8 /* flush the asychronous operational statistics */ +#define TRANSMIT_ASY_BREAK_SIGNAL 0xEC /* transmit an asychronous break signal */ + + +/* ---------------------------------------------------------------------------- + * Return codes from interface commands + * --------------------------------------------------------------------------*/ + +#define OK 0x00 /* the interface command was successful */ +#define COMMAND_OK 0x00 /* the interface command was successful */ + +/* return codes from global interface commands */ +#define NO_GLOBAL_EXCEP_COND_TO_REPORT 0x01 /* there is no global exception condition to report */ +#define LGTH_GLOBAL_CFG_DATA_INVALID 0x01 /* the length of the passed global configuration data is invalid */ +#define IRQ_TIMEOUT_VALUE_INVALID 0x02 /* an invalid application IRQ timeout value was selected */ +#define ADAPTER_OPERATING_FREQ_INVALID 0x03 /* an invalid adapter operating frequency was selected */ +#define TRANSMIT_TIMEOUT_INVALID 0x04 /* the frame transmit timeout is invalid */ + + +/* return codes from command READ_GLOBAL_EXCEPTION_CONDITION */ +#define EXCEP_MODEM_STATUS_CHANGE 0x10 /* a modem status change occurred */ +#define EXCEP_APP_IRQ_TIMEOUT 0x12 /* an application IRQ timeout has occurred */ +#define EXCEP_ASY_BREAK_RECEIVED 0x17 /* a break sequence has been received (asynchronous mode only) */ + +/* return codes from interface commands */ +#define xxxCOMMS_DISABLED 0x21 /* communications are not currently enabled */ +#define xxxCOMMS_ENABLED 0x21 /* communications are currently enabled */ +#define LGTH_INT_TRIGGERS_DATA_INVALID 0x22 /* the length of the passed interrupt trigger data is invalid */ +#define INVALID_IRQ_SELECTED 0x23 /* an invalid IRQ was selected in the SET_ASY_INTERRUPT_TRIGGERS */ +#define IRQ_TMR_VALUE_INVALID 0x24 /* an invalid application IRQ timer value was selected */ +#define DISABLE_ASY_COMMS_BEFORE_CFG 0xE1 /* communications must be disabled before setting the configuration */ +#define ASY_COMMS_ENABLED 0xE1 /* communications are currently enabled */ +#define ASY_COMMS_DISABLED 0xE1 /* communications are currently disabled */ +#define ASY_CFG_BEFORE_COMMS_ENABLED 0xE2 /* perform a SET_ASY_CONFIGURATION before enabling comms */ +#define LGTH_ASY_CFG_DATA_INVALID 0xE2 /* the length of the passed configuration data is invalid */ +#define INVALID_ASY_CFG_DATA 0xE3 /* the passed configuration data is invalid */ +#define ASY_BREAK_SIGNAL_BUSY 0xEC /* a break signal is being transmitted */ +#define INVALID_COMMAND 0xFF /* the defined interface command is invalid */ + + + +/* ---------------------------------------------------------------------------- + * Constants for the READ_GLOBAL_EXCEPTION_CONDITION command + * --------------------------------------------------------------------------*/ + +/* the global exception condition structure for handling a modem status change */ +typedef struct { + unsigned char modem_status_change; /* the modem status change */ +} GLOBAL_EX_MODEM_STRUCT; + +/* settings for the 'modem_status_change' */ +#define CHANGE_IN_DCD 0x04 /* a change in DCD occured */ +#define CHANGE_IN_CTS 0x10 /* a change in CTS occured */ + + + +/* ---------------------------------------------------------------------------- + * Constants for the SET_GLOBAL_CONFIGURATION/READ_GLOBAL_CONFIGURATION commands + * --------------------------------------------------------------------------*/ + +/* the global configuration structure */ +typedef struct { + unsigned short adapter_config_options; /* adapter configuration options */ + unsigned short app_IRQ_timeout; /* application IRQ timeout */ + unsigned long adapter_operating_frequency; /* adapter operating frequency */ + unsigned short frame_transmit_timeout; /* frame transmission timeout */ +} GLOBAL_CONFIGURATION_STRUCT; + +/* settings for the 'adapter_config_options' */ +#define ADPTR_CFG_S514 0x0001 /* S514 adapter */ + +/* settings for the 'app_IRQ_timeout' */ +#define MAX_APP_IRQ_TIMEOUT_VALUE 5000 /* the maximum permitted IRQ timeout */ + + + +/* ---------------------------------------------------------------------------- + * Constants for the READ_GLOBAL_STATISTICS command + * --------------------------------------------------------------------------*/ + +/* the global statistics structure */ +typedef struct { + unsigned short app_IRQ_timeout_count; /* application IRQ timeout count */ + unsigned short FT1_INS_alarm_count; /* FT1 in-service/alarm condition count */ +} GLOBAL_STATS_STRUCT; + + + +/* ---------------------------------------------------------------------------- + * Constants for the SET_MODEM_STATUS command + * --------------------------------------------------------------------------*/ + +/* the set modem status structure */ +typedef struct { + unsigned char output_modem_status; /* the output modem status */ +} SET_MODEM_STATUS_STRUCT; + +/* settings for the 'output_modem_status' */ +#define SET_DTR_HIGH 0x01 /* set DTR high */ +#define SET_RTS_HIGH 0x02 /* set RTS high */ + + + +/* ---------------------------------------------------------------------------- + * Constants for the READ_MODEM_STATUS command + * --------------------------------------------------------------------------*/ + +/* the read modem status structure */ +typedef struct { + unsigned char input_modem_status; /* the input modem status */ +} READ_MODEM_STATUS_STRUCT; + +/* settings for the 'input_modem_status' */ +#define DCD_HIGH 0x08 /* DCD is high */ +#define CTS_HIGH 0x20 /* CTS is high */ + + + +/* ---------------------------------------------------------------------------- + * Constants for the READ_COMMS_ERROR_STATS command + * --------------------------------------------------------------------------*/ + +/* the communications error statistics structure */ +typedef struct { + unsigned short Rx_overrun_err_count; /* receiver overrun error count */ + unsigned short Rx_parity_err_count; /* receiver parity error count */ + unsigned short Rx_framing_err_count; /* framing errors received count */ + unsigned short DCD_state_change_count; /* DCD state change count */ + unsigned short CTS_state_change_count; /* CTS state change count */ +} COMMS_ERROR_STATS_STRUCT; + + + + +/* ---------------------------------------------------------------------------- + * Constants for using application interrupts + * --------------------------------------------------------------------------*/ + +/* the structure used for the SET_ASY_INTERRUPT_TRIGGERS/READ_ASY_INTERRUPT_TRIGGERS command */ +typedef struct { + unsigned char interrupt_triggers; /* interrupt trigger configuration */ + unsigned char IRQ; /* IRQ to be used */ + unsigned short interrupt_timer; /* interrupt timer */ + unsigned short misc_interrupt_bits; /* miscellaneous interrupt bits */ +} ASY_INT_TRIGGERS_STRUCT; + +/* 'interrupt_triggers' bit settings */ +#define APP_INT_ON_RX 0x01 /* interrupt on reception */ +#define APP_INT_ON_RX_FRAME APP_INT_ON_RX +#define APP_INT_ON_TX 0x02 /* interrupt when data may be transmitted */ +#define APP_INT_ON_COMMAND_COMPLETE 0x04 /* interrupt when an interface command is complete */ +#define APP_INT_ON_TIMER 0x08 /* interrupt on a defined millisecond timeout */ +#define APP_INT_ON_GLOBAL_EXCEP_COND 0x10 /* interrupt on a global exception condition */ + +/* 'interrupt_timer' limitation */ +#define MAX_INTERRUPT_TIMER_VALUE 60000 /* the maximum permitted timer interrupt value */ + +/* interrupt types indicated at 'interrupt_type' byte of the INTERRUPT_INFORMATION_STRUCT */ +#define NO_APP_INTS_PEND 0x00 /* no interrups are pending */ +#define RX_APP_INT_PEND 0x01 /* a receive interrupt is pending */ +#define TX_APP_INT_PEND 0x02 /* a transmit interrupt is pending */ +#define COMMAND_COMPLETE_APP_INT_PEND 0x04 /* a 'command complete' interrupt is pending */ +#define TIMER_APP_INT_PEND 0x08 /* a timer interrupt is pending */ +#define GLOBAL_EXCEP_COND_APP_INT_PEND 0x10 /* a global exception condition interrupt is pending */ + + + +/* ---------------------------------------------------------------------------- + * Constants for the SET_ASY_CONFIGURATION/READ_ASY_CONFIGURATION command + * --------------------------------------------------------------------------*/ + +/* the asynchronous configuration structure */ +typedef struct { + unsigned long baud_rate; /* the baud rate */ + unsigned short line_config_options; /* line configuration options */ + unsigned short modem_config_options; /* modem configuration options */ + unsigned short API_options; /* asynchronous API options */ + unsigned short protocol_options; /* asynchronous protocol options */ + unsigned short Tx_bits_per_char; /* number of bits per transmitted character */ + unsigned short Rx_bits_per_char; /* number of bits per received character */ + unsigned short stop_bits; /* number of stop bits per character */ + unsigned short parity; /* parity definition */ + unsigned short break_timer; /* the break signal timer */ + unsigned short Rx_inter_char_timer; /* the receive inter-character timer */ + unsigned short Rx_complete_length; /* the receive 'buffer complete' length */ + unsigned short XON_char; /* the XON character */ + unsigned short XOFF_char; /* the XOFF character */ + unsigned short statistics_options; /* operational statistics options */ + unsigned long ptr_shared_mem_info_struct; /* a pointer to the shared memory area information structure */ + unsigned long ptr_asy_Tx_stat_el_cfg_struct; /* a pointer to the transmit status element configuration structure */ + unsigned long ptr_asy_Rx_stat_el_cfg_struct; /* a pointer to the receive status element configuration structure */ +} ASY_CONFIGURATION_STRUCT; + +/* settings for the 'line_config_options' */ +#define INTERFACE_LEVEL_V35 0x0000 /* V.35 interface level */ +#define INTERFACE_LEVEL_RS232 0x0001 /* RS-232 interface level */ + +/* settings for the 'modem_config_options' */ +#define DONT_RAISE_DTR_RTS_ON_EN_COMMS 0x0001 /* don't automatically raise DTR and RTS when performing an */ + /* ENABLE_ASY_COMMUNICATIONS command */ +#define DONT_REPORT_CHG_IN_MODEM_STAT 0x0002 /* don't report changes in modem status to the application */ + +/* settings for the 'asy_statistics_options' */ +#define ASY_TX_THROUGHPUT_STAT 0x0004 /* compute the transmit throughput */ +#define ASY_RX_THROUGHPUT_STAT 0x0008 /* compute the receive throughput */ + +/* permitted minimum and maximum values for setting the asynchronous configuration */ +#define MIN_ASY_BAUD_RATE 50 /* maximum baud rate */ +#define MAX_ASY_BAUD_RATE 250000 /* minimum baud rate */ +#define MIN_ASY_BITS_PER_CHAR 5 /* minimum number of bits per character */ +#define MAX_ASY_BITS_PER_CHAR 8 /* maximum number of bits per character */ +#define MAX_BREAK_TMR_VAL 5000 /* maximum break signal timer */ +#define MAX_ASY_RX_INTER_CHAR_TMR 30000 /* maximum receive inter-character timer */ +#define MAX_ASY_RX_CPLT_LENGTH 2000 /* maximum receive 'length complete' value */ + +/* bit settings for the 'asy_API_options' */ +#define ASY_RX_DATA_TRANSPARENT 0x0001 /* do not strip parity and unused bits from received characters */ + +/* bit settings for the 'asy_protocol_options' */ +#define ASY_RTS_HS_FOR_RX 0x0001 /* RTS handshaking is used for reception control */ +#define ASY_XON_XOFF_HS_FOR_RX 0x0002 /* XON/XOFF handshaking is used for reception control */ +#define ASY_XON_XOFF_HS_FOR_TX 0x0004 /* XON/XOFF handshaking is used for transmission control */ +#define ASY_DCD_HS_FOR_TX 0x0008 /* DCD handshaking is used for transmission control */ +#define ASY_CTS_HS_FOR_TX 0x0020 /* CTS handshaking is used for transmission control */ +#define ASY_HDLC_FRAMING 0x0100 /* use HDLC framing */ +#define ASY_HDLC_PASS_RX_CRC_TO_APP 0x0200 /* pass received HDLC CRC bytes to the application */ +#define ASY_HDLC_PASS_RX_BAD_TO_APP 0x0400 /* pass received bad frames to the application */ +#define ASY_DIS_RX_WHEN_TX 0x1000 /* disable the receiver when transmitting */ + +/* bit settings for the 'stop_bits' definition */ +#define ONE_STOP_BIT 1 /* representation for 1 stop bit */ +#define TWO_STOP_BITS 2 /* representation for 2 stop bits */ +#define ONE_AND_A_HALF_STOP_BITS 3 /* representation for 1.5 stop bits */ + +/* bit settings for the 'parity' definition */ +#define NO_PARITY 0 /* representation for no parity */ +#define ODD_PARITY 1 /* representation for odd parity */ +#define EVEN_PARITY 2 /* representation for even parity */ + + + +/* ---------------------------------------------------------------------------- + * Constants for the READ_COMMS_ERROR_STATS command (asynchronous mode) + * --------------------------------------------------------------------------*/ + +/* the communications error statistics structure */ +typedef struct { + unsigned short Rx_overrun_err_count; /* receiver overrun error count */ + unsigned short Rx_parity_err_count; /* parity errors received count */ + unsigned short Rx_framing_err_count; /* framing errors received count */ + unsigned short DCD_state_change_count; /* DCD state change count */ + unsigned short CTS_state_change_count; /* CTS state change count */ +} ASY_COMMS_ERROR_STATS_STRUCT; + + + +/* ---------------------------------------------------------------------------- + * Constants for the READ_ASY_OPERATIONAL_STATS command + * --------------------------------------------------------------------------*/ + +/* the asynchronous operational statistics structure */ +typedef struct { + + /* transmission statistics */ + unsigned long blocks_Tx_count; /* number of blocks transmitted */ + unsigned long bytes_Tx_count; /* number of bytes transmitted */ + unsigned long Tx_throughput; /* transmit throughput */ + unsigned long no_ms_for_Tx_thruput_comp; /* millisecond time used for the Tx throughput computation */ + unsigned long Tx_block_discard_lgth_err_count;/* number of blocks discarded (length error) */ + + /* reception statistics */ + unsigned long blocks_Rx_count; /* number of blocks received */ + unsigned long bytes_Rx_count; /* number of bytes received */ + unsigned long Rx_throughput; /* receive throughput */ + unsigned long no_ms_for_Rx_thruput_comp; /* millisecond time used for the Rx throughput computation */ + unsigned long Rx_bytes_discard_count; /* received Data bytes discarded */ + + /* handshaking protocol statistics */ + unsigned short XON_chars_Tx_count; /* number of XON characters transmitted */ + unsigned short XOFF_chars_Tx_count; /* number of XOFF characters transmitted */ + unsigned short XON_chars_Rx_count; /* number of XON characters received */ + unsigned short XOFF_chars_Rx_count; /* number of XOFF characters received */ + unsigned short Tx_halt_modem_low_count; /* number of times Tx halted (modem line low) */ + unsigned short Rx_halt_RTS_low_count; /* number of times Rx halted by setting RTS low */ + + /* break statistics */ + unsigned short break_Tx_count; /* number of break sequences transmitted */ + unsigned short break_Rx_count; /* number of break sequences received */ + +} ASY_OPERATIONAL_STATS_STRUCT; + + + +/* ---------------------------------------------------------------------------- + * Constants for data transmission + * --------------------------------------------------------------------------*/ + +/* the data block transmit status element configuration structure */ +typedef struct { + unsigned short number_Tx_status_elements; /* number of transmit status elements */ + unsigned long base_addr_Tx_status_elements; /* base address of the transmit element list */ + unsigned long next_Tx_status_element_to_use; /* pointer to the next transmit element to be used */ +} ASY_TX_STATUS_EL_CFG_STRUCT; + + +/* the data block transmit status element structure */ +typedef struct { + unsigned char opp_flag; /* opp flag */ + unsigned short data_length; /* length of the block to be transmitted */ + unsigned char misc_bits; /* miscellaneous transmit bits */ + unsigned char reserved[8]; /* reserved for internal use */ + unsigned long ptr_data_bfr; /* pointer to the data area */ +} ASY_DATA_TX_STATUS_EL_STRUCT; + + + +/* ---------------------------------------------------------------------------- + * Constants for data reception + * --------------------------------------------------------------------------*/ + +/* the data block receive status element configuration structure */ +typedef struct { + unsigned short number_Rx_status_elements; /* number of receive status elements */ + unsigned long base_addr_Rx_status_elements; /* base address of the receive element list */ + unsigned long next_Rx_status_element_to_use; /* pointer to the next receive element to be used */ + unsigned long base_addr_Rx_buffer; /* base address of the receive data buffer */ + unsigned long end_addr_Rx_buffer; /* end address of the receive data buffer */ +} ASY_RX_STATUS_EL_CFG_STRUCT; + +/* the data block receive status element structure */ +typedef struct { + unsigned char opp_flag; /* opp flag */ + unsigned short data_length; /* length of the received data block */ + unsigned char misc_bits; /* miscellaneous receive bits */ + unsigned short time_stamp; /* receive time stamp (HDLC_STREAMING_MODE) */ + unsigned short data_buffered; /* the number of data bytes still buffered */ + unsigned char reserved[4]; /* reserved for internal use */ + unsigned long ptr_data_bfr; /* pointer to the data area */ +} ASY_DATA_RX_STATUS_EL_STRUCT; + +/* settings for the 'misc_bits' */ +#define RX_HDLC_FRM_ABORT 0x01 /* the incoming frame was aborted */ +#define RX_HDLC_FRM_CRC_ERROR 0x02 /* the incoming frame has a CRC error */ +#define RX_FRM_OVERRUN_ERROR 0x04 /* the incoming frame has an overrun error */ +#define RX_HDLC_FRM_SHORT_ERROR 0x10 /* the incoming frame was too short */ +#define RX_HDLC_FRM_LONG_ERROR 0x20 /* the incoming frame was too long */ + + +/* ---------------------------------------------------------------------------- + * Constants defining the shared memory information area + * --------------------------------------------------------------------------*/ + +/* the global information structure */ +typedef struct { + unsigned char global_status; /* global status */ + unsigned char modem_status; /* current modem status */ + unsigned char global_excep_conditions; /* global exception conditions */ + unsigned char glob_info_reserved[5]; /* reserved */ + unsigned char code_name[4]; /* code name */ + unsigned char code_version[4]; /* code version */ +} GLOBAL_INFORMATION_STRUCT; + +/* the ASY information structure */ +typedef struct { + unsigned char asy_rx_avail; + unsigned char asy_info_reserved[15]; /* reserved */ +} ASY_INFORMATION_STRUCT; + +/* the interrupt information structure */ +typedef struct { + unsigned char interrupt_type; /* type of interrupt triggered */ + unsigned char interrupt_permission; /* interrupt permission mask */ + unsigned char int_info_reserved[14]; /* reserved */ +} INTERRUPT_INFORMATION_STRUCT; + +/* the FT1 information structure */ +typedef struct { + unsigned char parallel_port_A_input; /* input - parallel port A */ + unsigned char parallel_port_B_input; /* input - parallel port B */ + unsigned char FT1_INS_alarm_condition; /* the current FT1 in-service/alarm condition */ + unsigned char FT1_info_reserved[13]; /* reserved */ +} FT1_INFORMATION_STRUCT; + + +/* the shared memory area information structure */ +typedef struct { + GLOBAL_INFORMATION_STRUCT global_info_struct; /* the global information structure */ + ASY_INFORMATION_STRUCT async_info_struct; /* the asynchronous information structure */ + INTERRUPT_INFORMATION_STRUCT interrupt_info_struct;/* the interrupt information structure */ + FT1_INFORMATION_STRUCT FT1_info_struct; /* the FT1 information structure */ +} SHARED_MEMORY_INFO_STRUCT; + + +#define MAX_LGTH_HDLC_FRAME 2048 /* the maximum permitted length of an HDLC frame */ + + +/* ---------------------------------------------------------------------------- + * HDLC Interface commands + * --------------------------------------------------------------------------*/ + +#define READ_HDLC_OPERATIONAL_STATS 0xF0 /* retrieve the HDLC operational statistics */ +#define FLUSH_HDLC_OPERATIONAL_STATS 0xF1 /* flush the HDLC operational statistics */ + +/* the HDLC operational statistics structure (returned on READ_HDLC_OPERATIONAL_STATS command) */ +typedef struct { + /* frame transmission statistics */ + unsigned long frames_Tx_count; /* number of frames transmitted */ + unsigned long bytes_Tx_count; /* number of bytes transmitted */ + unsigned long Tx_frame_discard_lgth_err_count;/* number of frames discarded (length error) */ + + /* frame reception statistics */ + unsigned long frames_Rx_count; /* number of frames received */ + unsigned long bytes_Rx_count; /* number of bytes received */ + unsigned long Rx_frame_short_count; /* received frames too short */ + unsigned long Rx_frame_long_count; /* received frames too long */ + unsigned long Rx_frame_discard_full_count; /* received frames discarded (buffer full) */ + unsigned long CRC_error_count; /* receiver CRC error count */ + unsigned long Rx_abort_count; /* abort frames received count */ +} HDLC_OPERATIONAL_STATS_STRUCT; + +#pragma pack() + + + + +#define UDPMGMT_SIGNATURE "CTPIPEAB" +#define UDPMGMT_SIGNATURE_LEN 8 + + +/* UDP/IP packet (for UDP management) layout */ +/* +typedef struct { + unsigned char reserved[2] PACKED; + unsigned short ip_length PACKED; + unsigned char reserved2[4] PACKED; + unsigned char ip_ttl PACKED; + unsigned char ip_protocol PACKED; + unsigned short ip_checksum PACKED; + unsigned long ip_src_address PACKED; + unsigned long ip_dst_address PACKED; + unsigned short udp_src_port PACKED; + unsigned short udp_dst_port PACKED; + unsigned short udp_length PACKED; + unsigned short udp_checksum PACKED; + udp_management_packet_t um_packet PACKED; +} ip_packet_t; +*/ + +/* valid ip_protocol for UDP management */ +#define UDPMGMT_UDP_PROTOCOL 0x11 + +#if 0 +typedef struct { + unsigned char status PACKED; + unsigned char data_avail PACKED; + unsigned short real_length PACKED; + unsigned short time_stamp PACKED; + unsigned char data[1] PACKED; +} trace_pkt_t; +#endif + +typedef struct { + unsigned char error_flag PACKED; + unsigned short time_stamp PACKED; + unsigned char reserved[13] PACKED; +} api_rx_hdr_t; + +typedef struct { + api_rx_hdr_t api_rx_hdr PACKED; + unsigned char data[1] PACKED; +} api_rx_element_t; + +typedef struct { + unsigned char attr PACKED; + unsigned char misc_Tx_bits PACKED; + unsigned char reserved[14] PACKED; +} api_tx_hdr_t; + +typedef struct { + api_tx_hdr_t api_tx_hdr PACKED; + unsigned char data[1] PACKED; +} api_tx_element_t; + +/* Special UDP drivers management commands */ +#define CPIPE_ENABLE_TRACING 0x50 +#define CPIPE_DISABLE_TRACING 0x51 +#define CPIPE_GET_TRACE_INFO 0x52 +#define CPIPE_GET_IBA_DATA 0x53 +#define CPIPE_FT1_READ_STATUS 0x54 +#define CPIPE_DRIVER_STAT_IFSEND 0x55 +#define CPIPE_DRIVER_STAT_INTR 0x56 +#define CPIPE_DRIVER_STAT_GEN 0x57 +#define CPIPE_FLUSH_DRIVER_STATS 0x58 +#define CPIPE_ROUTER_UP_TIME 0x59 + +#if 0 +#define CPIPE_MPPP_TRACE_ENABLE 0x60 +#define CPIPE_MPPP_TRACE_DISABLE 0x61 +#define CPIPE_TE1_56K_STAT 0x62 /* TE1_56K */ +#define CPIPE_GET_MEDIA_TYPE 0x63 /* TE1_56K */ +#define CPIPE_FLUSH_TE1_PMON 0x64 /* TE1 */ +#define CPIPE_READ_REGISTER 0x65 /* TE1_56K */ +#define CPIPE_TE1_CFG 0x66 /* TE1 */ +#endif + +/* Driver specific commands for API */ +#define CHDLC_READ_TRACE_DATA 0xE4 /* read trace data */ +#define TRACE_ALL 0x00 +#define TRACE_PROT 0x01 +#define TRACE_DATA 0x02 + +#define SIOC_ASYHDLC_RX_AVAIL_CMD SIOC_WANPIPE_DEVPRIVATE +#define SIOC_GET_HDLC_RECEIVER_STATUS SIOC_ASYHDLC_RX_AVAIL_CMD + +/* Return codes for SIOC_GET_HDLC_RECEIVER_STATUS cmd */ +enum { + HDLC_RX_IN_PROCESS, + NO_HDLC_RX_IN_PROCESS +}; + +#endif + + diff -Nur linux.org/include/linux/sdla_atm.h linux-2.6.17/include/linux/sdla_atm.h --- linux.org/include/linux/sdla_atm.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/sdla_atm.h 2006-08-30 10:07:15.000000000 +0000 @@ -0,0 +1,752 @@ +/************************************************************************************ + * * + * PHYAPI.H - the 'C' header file for the Sangoma S508/S514 PHY-level ATM code API. * + * * + ************************************************************************************ +*/ + +#ifndef __SDLA_ATM_H_ +#define __SDLA_ATM_H_ + + +#pragma pack(1) + +/* ---------------------------------------------------------------------------- + * Constants defining the shared memory control block (mailbox) + * --------------------------------------------------------------------------*/ + +#define BASE_ADDR_MB_STRUCT 0xE000 /* the base address of the mailbox structure */ +#define NUMBER_MB_RESERVED_BYTES 0x0B /* the number of reserved bytes in the mailbox header area */ +#define SIZEOF_MB_DATA_BFR 240 /* the size of the actual mailbox data area */ + +/* the control block mailbox structure */ +typedef struct { + unsigned char opp_flag; /* the opp flag */ + unsigned char command; /* the user command */ + unsigned short buffer_length; /* the data length */ + unsigned char return_code; /* the return code */ + char MB_reserved[NUMBER_MB_RESERVED_BYTES]; /* reserved for later use */ + char data[SIZEOF_MB_DATA_BFR]; /* the data area */ +} ATM_MAILBOX_STRUCT; + + + +/* ---------------------------------------------------------------------------- + * Interface commands + * --------------------------------------------------------------------------*/ + +/* global interface commands */ +#define READ_GLOBAL_EXCEPTION_CONDITION 0x01 /* read a global exception condition from the adapter */ +#define SET_GLOBAL_CONFIGURATION 0x02 /* set the global operational configuration */ +#define READ_GLOBAL_CONFIGURATION 0x03 /* read the global configuration */ +#define READ_GLOBAL_STATISTICS 0x04 /* retrieve the global statistics */ +#define FLUSH_GLOBAL_STATISTICS 0x05 /* flush the global statistics */ +#define SET_MODEM_STATUS 0x06 /* set the status of DTR and/or RTS */ +#define READ_MODEM_STATUS 0x07 /* read the current status of CTS and DCD */ +#define READ_COMMS_ERROR_STATS 0x08 /* read the communication error statistics */ +#define FLUSH_COMMS_ERROR_STATS 0x09 /* flush the communication error statistics */ +#define SET_TRACE_CONFIGURATION 0x0A /* set the line trace configuration */ +#define READ_TRACE_CONFIGURATION 0x0B /* read the line trace configuration */ +#define READ_TRACE_STATISTICS 0x0C /* read the trace statistics */ +#define FLUSH_TRACE_STATISTICS 0x0D /* flush the trace statistics */ + +/* PHY-level interface commands */ +#define PHY_READ_CODE_VERSION 0x20 /* read the ATM code version */ +#define PHY_READ_EXCEPTION_CONDITION 0x21 /* read a PHY-level exception condition from the adapter */ +#define PHY_SET_CONFIGURATION 0x22 /* set the PHY-level configuration */ +#define PHY_READ_CONFIGURATION 0x23 /* read the PHY-level configuration */ +#define PHY_ENABLE_COMMUNICATIONS 0x24 /* enable PHY-level communications */ +#define PHY_DISABLE_COMMUNICATIONS 0x25 /* disable PHY-level communications */ +#define PHY_READ_STATUS 0x26 /* read the PHY-level status */ +#define PHY_READ_OPERATIONAL_STATS 0x27 /* retrieve the PHY-level operational statistics */ +#define PHY_FLUSH_OPERATIONAL_STATS 0x28 /* flush the PHY-level operational statistics */ +#define PHY_RESYNCHRONIZE_RECEIVER 0x29 /* resynchronize the receiver */ +#define PHY_SET_TX_UNDERRUN_CONFIG 0x2A /* set the transmit underrun cell configuration */ +#define PHY_READ_TX_UNDERRUN_CONFIG 0x2B /* read the transmit underrun cell configuration */ +#define PHY_SET_INTERRUPT_TRIGGERS 0x30 /* set the PHY-level application interrupt triggers */ +#define PHY_READ_INTERRUPT_TRIGGERS 0x31 /* read the PHY-level application interrupt trigger configuration */ + + + +/* ---------------------------------------------------------------------------- + * Return codes from interface commands + * --------------------------------------------------------------------------*/ + +#define OK 0x00 /* the interface command was successful */ + +/* return codes from global interface commands */ +#define NO_GLOBAL_EXCEP_COND_TO_REPORT 0x01 /* there is no global exception condition to report */ +#define LGTH_GLOBAL_CFG_DATA_INVALID 0x01 /* the length of the passed global configuration data is invalid */ +#define LGTH_TRACE_CFG_DATA_INVALID 0x01 /* the length of the passed trace configuration data is invalid */ +#define IRQ_TIMEOUT_VALUE_INVALID 0x02 /* an invalid application IRQ timeout value was selected */ +#define TRACE_CONFIG_INVALID 0x02 /* the passed line trace configuration is invalid */ +#define ADAPTER_OPERATING_FREQ_INVALID 0x03 /* an invalid adapter operating frequency was selected */ + +/* return codes from command READ_GLOBAL_EXCEPTION_CONDITION */ +#define EXCEP_MODEM_STATUS_CHANGE 0x10 /* a modem status change occurred */ +#define EXCEP_APP_IRQ_TIMEOUT 0x12 /* an application IRQ timeout has occurred */ + +/* return codes from PHY-level interface commands */ +#define PHY_NO_EXCEP_COND_TO_REPORT 0x21 /* there is no PHY-level exception condition to report */ +#define PHY_COMMS_DISABLED 0x21 /* communications are not currently enabled */ +#define PHY_COMMS_ENABLED 0x21 /* communications are currently enabled */ +#define PHY_DISABLE_COMMS_BEFORE_CFG 0x21 /* communications must be disabled before setting the configuration */ +#define PHY_CFG_BEFORE_COMMS_ENABLED 0x22 /* perform a PHY_SET_CONFIGURATION before enabling comms */ +#define PHY_LGTH_CFG_DATA_INVALID 0x22 /* the length of the passed configuration data is invalid */ +#define PHY_LGTH_INT_TRIG_DATA_INVALID 0x22 /* the length of the passed interrupt trigger data is invalid */ +#define PHY_LGTH_TX_UND_DATA_INVALID 0x22 /* the length of the passed transmit underrun data is invalid */ +#define PHY_RX_NOT_SYNCHRONIZED 0x22 /* the receiver is not synchronized */ +#define PHY_INVALID_IRQ_SELECTED 0x23 /* an invalid IRQ was selected in the PHY_SET_INTERRUPT_TRIGGERS */ +#define PHY_INVALID_CFG_DATA 0x23 /* the passed configuration data is invalid */ +#define PHY_IRQ_TMR_VALUE_INVALID 0x24 /* an invalid application IRQ timer value was selected */ +#define PHY_INVALID_COMMAND 0x2F /* the defined interface command is invalid */ + +/* return codes from command PHY_READ_EXCEPTION_CONDITION */ +#define PHY_EXCEP_RX_SYNC_STATE_CHANGE 0x30 /* the PHY receiver has changed state */ +#define PHY_EXCEP_INVALID_HEC 0x32 /* the Rx consecutive incorrect HEC counter has expired */ +#define PHY_EXCEP_RECEP_LOSS 0x33 /* the cell reception sync loss timer has expired */ +#define PHY_EXCEP_RX_DISCARD 0x36 /* incoming cells were discarded */ +#define PHY_EXCEP_TX_LENGTH_ERROR 0x37 /* a transmit buffer of invalid length was detected */ + + + +/* ---------------------------------------------------------------------------- + * Constants for the READ_GLOBAL_EXCEPTION_CONDITION command + * --------------------------------------------------------------------------*/ + +/* the global exception condition structure for handling a modem status change */ +typedef struct { + unsigned char modem_status_change; /* the modem status change */ +} GLOBAL_EX_MODEM_STRUCT; + +/* settings for the 'modem_status_change' */ +#define CHANGE_IN_DCD 0x04 /* a change in DCD occured */ +#define CHANGE_IN_CTS 0x10 /* a change in CTS occured */ + + + +/* ---------------------------------------------------------------------------- + * Constants for the SET_GLOBAL_CONFIGURATION/READ_GLOBAL_CONFIGURATION commands + * --------------------------------------------------------------------------*/ + +/* the global configuration structure */ +typedef struct { + unsigned short adapter_config_options; /* adapter configuration options */ + unsigned short app_IRQ_timeout; /* application IRQ timeout */ + unsigned long adapter_operating_frequency; /* adapter operating frequency */ +} GLOBAL_CONFIGURATION_STRUCT; + +/* settings for the 'adapter_config_options' */ +#define ADPTR_CFG_S514 0x0001 /* S514 adapter */ + +/* settings for the 'app_IRQ_timeout' */ +#define MAX_APP_IRQ_TIMEOUT_VALUE 5000 /* the maximum permitted IRQ timeout */ + + + +/* ---------------------------------------------------------------------------- + * Constants for the READ_GLOBAL_STATISTICS command + * --------------------------------------------------------------------------*/ + +/* the global statistics structure */ +typedef struct { + unsigned short app_IRQ_timeout_count; /* application IRQ timeout count */ +} GLOBAL_STATS_STRUCT; + + + +/* ---------------------------------------------------------------------------- + * Constants for the SET_MODEM_STATUS command + * --------------------------------------------------------------------------*/ + +/* the set modem status structure */ +typedef struct { + unsigned char output_modem_status; /* the output modem status */ +} SET_MODEM_STATUS_STRUCT; + +/* settings for the 'output_modem_status' */ +#define SET_DTR_HIGH 0x01 /* set DTR high */ +#define SET_RTS_HIGH 0x02 /* set RTS high */ + + + +/* ---------------------------------------------------------------------------- + * Constants for the READ_MODEM_STATUS command + * --------------------------------------------------------------------------*/ + +/* the read modem status structure */ +typedef struct { + unsigned char input_modem_status; /* the input modem status */ +} READ_MODEM_STATUS_STRUCT; + +/* settings for the 'input_modem_status' */ +#define DCD_HIGH 0x08 /* DCD is high */ +#define CTS_HIGH 0x20 /* CTS is high */ + + + +/* ---------------------------------------------------------------------------- + * Constants for the READ_COMMS_ERROR_STATS command + * --------------------------------------------------------------------------*/ + +/* the communications error statistics structure */ +typedef struct { + unsigned short Rx_overrun_err_count; /* receiver overrun error count */ + unsigned short reserved_0; /* reserved for later use */ + unsigned short reserved_1; /* reserved for later use */ + unsigned short DCD_state_change_count; /* DCD state change count */ + unsigned short CTS_state_change_count; /* CTS state change count */ +} COMMS_ERROR_STATS_STRUCT; + + + +/* ---------------------------------------------------------------------------- + * Constants used for line tracing + * --------------------------------------------------------------------------*/ + +/* the trace configuration structure (SET_TRACE_CONFIGURATION/READ_TRACE_CONFIGURATION commands) */ +typedef struct { + unsigned char trace_config; /* trace configuration */ + unsigned long ptr_trace_stat_el_cfg_struct; /* a pointer to the line trace element configuration structure */ +} LINE_TRACE_CONFIG_STRUCT; + +/* 'trace_config' bit settings */ +#define TRACE_INACTIVE 0x00 /* trace is inactive */ +#define TRACE_ACTIVE 0x01 /* trace is active */ +#define TRACE_LIMIT_REPEAT_CELLS 0x08 /* limit the tracing of repeated Physical Layer and Idle Cells */ +#define TRACE_PHY_UNASSIGNED_CELLS 0x10 /* trace Unassigned Cells */ +#define TRACE_PHY_IDLE_CELLS 0x20 /* trace Idle Cells */ +#define TRACE_PHY_PHYS_LAYER_CELLS 0x40 /* trace Physical Layer Cells */ +#define TRACE_PHY_NON_UNAS_PHYS_CELLS 0x80 /* trace cells other than Physical Layer and Idle Cells */ + +/* the line trace status element configuration structure */ +typedef struct { + unsigned short number_trace_status_els; /* number of line trace elements */ + unsigned long base_addr_trace_status_els; /* base address of the trace element list */ + unsigned long next_trace_el_to_use; /* pointer to the next trace element to be used */ +} TRACE_STATUS_EL_CFG_STRUCT; + +/* the line trace status element structure */ +typedef struct { + unsigned char opp_flag; /* opp flag */ + unsigned short trace_length; /* trace length */ + unsigned char trace_type; /* trace type */ + unsigned short trace_time_stamp; /* time stamp */ + unsigned short trace_reserved_1; /* reserved for later use */ + unsigned long trace_reserved_2; /* reserved for later use */ + unsigned long ptr_data_bfr; /* pointer to the trace data buffer */ +} TRACE_STATUS_ELEMENT_STRUCT; + +/* settings for the 'trace_type' */ +#define TRACE_INCOMING 0x00 /* an incoming block/cell has been traced */ +#define TRACE_OUTGOING 0x01 /* an outgoing block/cell has been traced */ +#define TRACE_HEC_ERROR 0x80 /* the traced cell has a HEC error */ + +/* the line trace statistics structure */ +typedef struct { + unsigned long blocks_traced_count; /* number of blocks traced */ + unsigned long trc_blocks_discarded_count; /* number of trace blocks discarded */ +} LINE_TRACE_STATS_STRUCT; + + + +/* ---------------------------------------------------------------------------- + * Constants for the PHY_READ_EXCEPTION_CONDITION command + * --------------------------------------------------------------------------*/ + +/* the structure returned on a return code PHY_EXCEP_RX_SYNC_STATE_CHANGE */ +/* Note that the definitions for the 'Rx_sync_status' are as per the PHY_READ_STATUS command */ +typedef struct { + unsigned char Rx_sync_status; /* receiver synchronization status */ +} PHY_RX_SYNC_EXCEP_STRUCT; + +/* the structure returned on a return code PHY_EXCEP_RX_DISCARD */ +typedef struct { + unsigned long Rx_discard_count; /* number of incoming blocks discarded */ +} PHY_RX_DISC_EXCEP_STRUCT; + + + +/* ---------------------------------------------------------------------------- + * Constants for the PHY_SET_CONFIGURATION/PHY_READ_CONFIGURATION command + * --------------------------------------------------------------------------*/ + +/* the PHY-level configuration structure */ +typedef struct { + unsigned long baud_rate; /* the baud rate */ + unsigned short line_config_options; /* line configuration options */ + unsigned short modem_config_options; /* modem configuration options */ + unsigned short modem_status_timer; /* timer for monitoring modem status changes */ + unsigned short API_options; /* API options */ + unsigned short protocol_options; /* protocol options */ + unsigned short HEC_options; /* HEC options */ + unsigned char custom_Rx_COSET; /* the custom COSET value used when checking the HEC value in received cells */ + unsigned char custom_Tx_COSET; /* the custom COSET value used when setting the HEC value in transmitted cells */ + unsigned short buffer_options; /* Tx/Rx buffer options */ + unsigned short max_cells_in_Tx_block; /* the maximum number of cells in an outgoing block */ + unsigned char Tx_underrun_cell_GFC; /* the GFC value in a Tx underrun cell */ + unsigned char Tx_underrun_cell_PT; /* the PT value in a Tx underrun cell */ + unsigned char Tx_underrun_cell_CLP; /* the CLP value in a Tx underrun cell */ + unsigned char Tx_underrun_cell_payload; /* the payload character in a Tx underrun cell */ + unsigned short number_cells_Tx_underrun; /* the number of cells to be transmitted in an underrun condition */ + unsigned short max_cells_in_Rx_block; /* the maximum number of cells in an incoming block */ + unsigned short Rx_hunt_timer; /* receiver hunt timer */ + unsigned short Rx_sync_bytes; /* receiver synchronization bytes */ + unsigned short Rx_sync_offset; /* offset of the receiver synchronization bytes */ + unsigned short cell_Rx_sync_loss_timer; /* cell reception synchronization loss timer */ + unsigned short Rx_HEC_check_timer; /* the Rx HEC check timer */ + unsigned short Rx_bad_HEC_timer; /* the time period for monitoring cells with bad HEC values */ + unsigned short Rx_max_bad_HEC_count; /* the maximum number of bad HEC count */ + unsigned short number_cells_Rx_discard; /* the number of cells to be discarded in a buffer overrun condition */ + unsigned short statistics_options; /* operational statistics options */ + unsigned long ptr_shared_mem_info_struct; /* a pointer to the shared memory area information structure */ + unsigned long ptr_Tx_stat_el_cfg_struct; /* a pointer to the transmit status element configuration structure */ + unsigned long ptr_Rx_stat_el_cfg_struct; /* a pointer to the receive status element configuration structure */ +} PHY_CONFIGURATION_STRUCT; + +/* settings for the 'line_config_options' */ +#define PHY_INTERFACE_LEVEL_V35 0x0001 /* V.35 interface level */ +#define PHY_INTERFACE_LEVEL_RS232 0x0002 /* RS-232 interface level */ + +/* settings for the 'modem_config_options' */ +#define PHY_MANUAL_DTR_RTS 0x0001 /* don't automatically raise DTR and RTS when performing an */ + /* PHY_ENABLE_COMMUNICATIONS command */ +#define PHY_IGNORE_CHG_MODEM_STATUS 0x0002 /* don't report changes in modem status to the application */ + +/* settings for the 'API_options' */ +#define PHY_DISCARD_RX_UNASSIGNED_CELLS 0x0001 /* discard incoming Unassigned Cells */ +#define PHY_DISCARD_RX_IDLE_CELLS 0x0002 /* discard incoming Idle Cells */ +#define PHY_DISCARD_RX_PHYS_LAYER_CELLS 0x0004 /* discard incoming Physical Layer Cells */ +#define PHY_TRANSPARENT_TX_RX_CELLS 0x0010 /* cells passed to and from the application transparently */ +#define PHY_DECODED_TX_RX_CELLS 0x0020 /* cells decoded and formatted by the PHY firmware */ +#define PHY_APP_REVERSES_BIT_ORDER 0x0040 /* let application revers bits */ + +/* settings for the 'protocol_options' */ +#define PHY_UNI 0x0001 /* configure as a User-Network Interface */ +#define PHY_NNI 0x0002 /* configure as a Network Node Interface */ +#define PHY_MANUAL_RX_SYNC 0x0100 /* use user-defined Rx synchronization parameters */ + +/* settings for the 'HEC_options' */ +#define PHY_DISABLE_RX_HEC_CHECK 0x0001 /* disable the checking of the HEC value in received cells */ +#define PHY_DISABLE_AUTO_SYNC_BAD_HEC 0x0002 /* disable automatic resynchronization on receipt of cells with bad HEC values */ +#define PHY_DISABLE_RX_COSET 0x0010 /* disable XOR with COSET when checking the HEC value in received cells */ +#define PHY_DISABLE_TX_COSET 0x0020 /* disable XOR with COSET when setting the HEC value in transmitted cells */ +#define PHY_CUSTOM_RX_COSET 0x0040 /* use a custom COSET when checking the HEC value in received cells */ +#define PHY_CUSTOM_TX_COSET 0x0080 /* use a custom COSET when setting the HEC value in transmitted cells */ + +/* bit settings for the 'buffer_options' */ +#define PHY_TX_ONLY 0x0001 /* transmit only (no reception) */ +#define PHY_RX_ONLY 0x0002 /* receive only (no transmission) */ +#define PHY_SINGLE_TX_BUFFER 0x0010 /* configure a single transmit buffer */ + +/* settings for the 'statistics_options' */ +#define PHY_TX_BYTE_COUNT_STAT 0x0001 /* record the number of bytes transmitted */ +#define PHY_RX_BYTE_COUNT_STAT 0x0002 /* record the number of bytes received */ +#define PHY_TX_THROUGHPUT_STAT 0x0004 /* compute the transmit throughput */ +#define PHY_RX_THROUGHPUT_STAT 0x0008 /* compute the receive throughput */ +#define PHY_INCL_UNDERRUN_TX_THRUPUT 0x0010 /* include Tx underrun cells in Tx throughput */ +#define PHY_INCL_DISC_RX_THRUPUT 0x0020 /* include discarded (idle/unassigned) Rx cells in Rx throughput */ + +/* permitted minimum and maximum values for setting the PHY configuration */ +#define PHY_MAX_BAUD_RATE_S508 2666666 /* maximum baud rate (S508) */ +#define PHY_MAX_BAUD_RATE_S514 2750000 /* maximum baud rate (S514) */ +#define PHY_MIN_MODEM_TIMER 0 /* minimum modem status timer */ +#define PHY_MAX_MODEM_TIMER 6000 /* maximum modem status timer */ +#define PHY_MIN_RX_HUNT_TIMER 1 /* minimum receiver hunt timer */ +#define PHY_MAX_RX_HUNT_TIMER 6000 /* maximum receiver hunt timer */ +#define PHY_MIN_RX_SYNC_OFFSET 0 /* minimum offset of receiver synchronization bytes */ +#define PHY_MAX_RX_SYNC_OFFSET 50 /* maximum offset of receiver synchronization bytes */ +#define PHY_MIN_CELLS_IN_TX_BLOCK 1 /* minimum number of cells in an outgoing block */ +#define PHY_MAX_CELLS_IN_TX_BLOCK 96 /* maximum number of cells in an outgoing block */ +#define PHY_MIN_CELLS_TX_UNDERRUN 1 /* minimum number of cells to be transmitted in an underrun condition */ +#define PHY_MAX_CELLS_TX_UNDERRUN 5 /* minimum number of cells to be transmitted in an underrun condition */ +#define PHY_MIN_CELLS_IN_RX_BLOCK 1 /* minimum number of cells in an incoming block */ +#define PHY_MAX_CELLS_IN_RX_BLOCK 96 /* maximum number of cells in an incoming block */ +#define PHY_MAX_RX_SYNC_LOSS_TIMER 6000 /* maximum cell reception sync loss timer */ +#define PHY_MAX_RX_HEC_CHECK_TIMER 6000 /* maximum receive HEC check timer */ +#define PHY_MIN_RX_BAD_HEC_TIMER 5 /* minimum time for monitoring cells with bad HEC values */ +#define PHY_MAX_RX_BAD_HEC_TIMER 60000 /* maximum time for monitoring cells with bad HEC values */ +#define PHY_MIN_RX_BAD_HEC_COUNT 1 /* the minimum bad HEC counter */ +#define PHY_MAX_RX_BAD_HEC_COUNT 10000 /* the maximum bad HEC counter */ +#define PHY_MAX_RX_INCORRECT_HEC_COUNT 100 /* maximum receive consecutive incorrect HEC counter */ +#define PHY_MIN_CELLS_RX_DISCARD 1 /* minimum number of cells to be discarded in a buffer overrun condition */ +#define PHY_MAX_CELLS_RX_DISCARD 5 /* maximum number of cells to be discarded in a buffer overrun condition */ + + + +/* ---------------------------------------------------------------------------- + * Constants for the PHY_READ_STATUS command + * --------------------------------------------------------------------------*/ + +/* the PHY-level status structure */ +typedef struct { + unsigned char Rx_sync_status; /* receiver synchronization status */ + unsigned char excep_conditions; /* PHY exception conditions */ + unsigned char no_Rx_blocks_avail; /* number of Rx blocks available for the application */ + unsigned short Rx_sync_time; /* receiver synchronization time */ + unsigned short Rx_sync_bytes; /* receiver synchronization bytes */ + unsigned short Rx_sync_offset; /* offset of the receiver synchronization bytes */ +} PHY_STATUS_STRUCT; + +/* settings for the 'Rx_sync_status' variable */ +#define PHY_RX_SYNC_LOST 0x00 /* synchronization has been lost */ +#define PHY_RX_HUNT 0x01 /* receiver in hunt state */ +#define PHY_RX_PRESYNC 0x02 /* receiver in presync state */ +#define PHY_RX_SYNCHRONIZED 0x80 /* receiver synchronized */ + + + +/* ---------------------------------------------------------------------------- + * Constants for the PHY_READ_OPERATIONAL_STATS command + * --------------------------------------------------------------------------*/ + +/* the PHY-level operational statistics structure */ +typedef struct { + + /* transmission statistics */ + unsigned long blocks_Tx_count; /* number of blocks transmitted */ + unsigned long bytes_Tx_count; /* number of bytes transmitted */ + unsigned long Tx_throughput; /* transmit throughput */ + unsigned long no_ms_for_Tx_thruput_comp; /* millisecond time used for the Tx throughput computation */ + unsigned long Tx_underrun_cell_count; /* number of underrun cells transmitted */ + unsigned long Tx_length_error_count; /* number of blocks transmitted with a length error */ + unsigned long reserved_Tx_stat0; /* reserved for later use */ + unsigned long reserved_Tx_stat1; /* reserved for later use */ + + /* reception statistics */ + unsigned long blocks_Rx_count; /* number of blocks received */ + unsigned long bytes_Rx_count; /* number of bytes received */ + unsigned long Rx_throughput; /* receive throughput */ + unsigned long no_ms_for_Rx_thruput_comp; /* millisecond time used for the Rx throughput computation */ + unsigned long Rx_blocks_discard_count; /* number of incoming blocks discarded */ + unsigned long Rx_Idle_Cell_discard_count; /* number of incoming Idle Cells discarded */ + unsigned long Rx_Unas_Cell_discard_count; /* number of incoming Unassigned Cells discarded */ + unsigned long Rx_Phys_Lyr_Cell_discard_count;/* number of incoming Physical Layer Cells discarded */ + unsigned long Rx_bad_HEC_count; /* number of incoming cells with a bad HEC */ + unsigned long reserved_Rx_stat0; /* reserved for later use */ + unsigned long reserved_Rx_stat1; /* reserved for later use */ + + /* synchronization statistics */ + unsigned long Rx_sync_attempt_count; /* receiver synchronization attempt count */ + unsigned long Rx_sync_achieved_count; /* receiver synchronization achieved count */ + unsigned long Rx_sync_failure_count; /* receiver synchronization failure count */ + unsigned long Rx_hunt_attempt_count; /* Rx hunt attempt count */ + unsigned long Rx_hunt_char_sync_count; /* Rx hunt character synchronization count */ + unsigned long Rx_hunt_timeout_count; /* Rx hunt timeout count */ + unsigned long Rx_hunt_achieved_count; /* Rx hunt achieved count */ + unsigned long Rx_hunt_failure_count; /* Rx hunt failure count */ + unsigned long Rx_presync_attempt_count; /* Rx presync attempt count */ + unsigned long Rx_presync_achieved_count; /* Rx presync achieved count */ + unsigned long Rx_presync_failure_count; /* Rx presync failure count */ + unsigned long Rx_resync_bad_HEC_count; /* Rx re-synchronization due to cells received with a bad HEC */ + unsigned long Rx_resync_reception_loss_count;/* Rx re-synchronization due to loss of reception */ + unsigned long Rx_resync_overrun_count; /* Rx re-synchronization due receiver overrun */ + unsigned long reserved_Rx_sync_stat0; /* reserved for later use */ + unsigned long reserved_Rx_sync_stat1; /* reserved for later use */ +} PHY_OPERATIONAL_STATS_STRUCT; + + + +/* ---------------------------------------------------------------------------- + * Constants for the PHY_SET_TX_UNDERRUN_CONFIG command + * --------------------------------------------------------------------------*/ + +/* the PHY transmit underrun cell structure */ +typedef struct { + unsigned char Tx_underrun_cell_GFC; /* the GFC value in a Tx underrun cell */ + unsigned char Tx_underrun_cell_PT; /* the PT value in a Tx underrun cell */ + unsigned char Tx_underrun_cell_CLP; /* the CLP value in a Tx underrun cell */ + unsigned char Tx_underrun_cell_payload; /* the payload character in a Tx underrun cell */ +} PHY_TX_UNDERRUN_STRUCT; + + + +/* ---------------------------------------------------------------------------- + * Constants for using application interrupts + * --------------------------------------------------------------------------*/ + +/* the structure used for the PHY_SET_INTERRUPT_TRIGGERS/PHY_READ_INTERRUPT_TRIGGERS command */ +typedef struct { + unsigned char interrupt_triggers; /* interrupt trigger configuration */ + unsigned char IRQ; /* IRQ to be used */ + unsigned short interrupt_timer; /* interrupt timer */ + unsigned short misc_interrupt_bits; /* miscellaneous interrupt bits */ +} PHY_INT_TRIGGERS_STRUCT; + +/* 'interrupt_triggers' bit settings */ +#define PHY_INT_RX 0x01 /* interrupt on reception */ +#define PHY_INT_TX 0x02 /* interrupt on transmission */ +#define PHY_INT_COMMAND_COMPLETE 0x04 /* interrupt when an interface command is complete */ +#define PHY_INT_TIMER 0x08 /* interrupt on a defined 1/100th second timeout */ +#define PHY_INT_GLOBAL_EXCEP_COND 0x10 /* interrupt on a global exception condition */ +#define PHY_INT_PHY_EXCEP_COND 0x20 /* interrupt on a PHY-level exception condition */ +#define PHY_INT_TRACE 0x80 /* interrupt when trace data is available */ + +/* 'interrupt_timer' limitation */ +#define MAX_INTERRUPT_TIMER_VALUE 60000 /* the maximum permitted timer interrupt value */ + +/* interrupt types indicated at 'interrupt_type' byte of the INTERRUPT_INFORMATION_STRUCT */ +#define PHY_NO_INT_PEND 0x00 /* no interrups are pending */ +#define PHY_RX_INT_PEND 0x01 /* a receive interrupt is pending */ +#define PHY_TX_INT_PEND 0x02 /* a transmit interrupt is pending */ +#define PHY_COMMAND_COMPLETE_INT_PEND 0x04 /* a 'command complete' interrupt is pending */ +#define PHY_TIMER_INT_PEND 0x08 /* a timer interrupt is pending */ +#define PHY_GLOBAL_EXCEP_COND_INT_PEND 0x10 /* a global exception condition interrupt is pending */ +#define PHY_PHY_EXCEP_COND_INT_PEND 0x20 /* a PHY exception condition interrupt is pending */ +#define PHY_TRACE_INT_PEND 0x80 /* a trace data interrupt is pending */ + + + +/* ---------------------------------------------------------------------------- + * Constants for block transmission + * --------------------------------------------------------------------------*/ + +/* the block transmit status element configuration structure */ +typedef struct { + unsigned short number_Tx_status_els; /* number of transmit status elements */ + unsigned long base_addr_Tx_status_els; /* base address of the transmit element list */ + unsigned long next_Tx_status_el_to_use; /* pointer to the next transmit element to be used */ +} PHY_TX_STATUS_EL_CFG_STRUCT; + +/* the block transmit status element structure */ +typedef struct { + unsigned char opp_flag; /* opp flag */ + unsigned short block_length; /* length of the block to be transmitted */ + unsigned char misc_Tx_bits; /* miscellaneous Tx bits */ + unsigned char Tx_underrun_cell_GFC; /* the GFC value in a Tx underrun cell */ + unsigned char Tx_underrun_cell_PT; /* the PT value in a Tx underrun cell */ + unsigned char Tx_underrun_cell_CLP; /* the CLP value in a Tx underrun cell */ + unsigned char Tx_underrun_cell_payload; /* the payload character in a Tx underrun cell */ + unsigned char reserved[4]; /* reserved for internal use */ + unsigned long ptr_data_bfr; /* pointer to the data area */ +} PHY_TX_STATUS_EL_STRUCT; + +/* settings for the 'misc_Tx_bits' */ +#define PHY_UPDATE_TX_UNDERRUN_CONFIG 0x01 /* update the transmit underrun cell configuration */ + + + +/* ---------------------------------------------------------------------------- + * Constants for block reception + * --------------------------------------------------------------------------*/ + +/* the block receive status element configuration structure */ +typedef struct { + unsigned short number_Rx_status_els; /* number of receive status elements */ + unsigned long base_addr_Rx_status_els; /* base address of the receive element list */ + unsigned long next_Rx_status_el_to_use; /* pointer to the next receive element to be used */ +} PHY_RX_STATUS_EL_CFG_STRUCT; + +/* the block receive status element structure */ +typedef struct { + unsigned char opp_flag; /* opp flag */ + unsigned short block_length; /* length of the received block */ + unsigned char misc_Rx_bits; /* miscellaneous Rx bits */ + unsigned short time_stamp; /* receive time stamp */ + unsigned char reserved[6]; /* reserved for internal use */ + unsigned long ptr_data_bfr; /* pointer to the data area */ +} PHY_RX_STATUS_EL_STRUCT; + +/* settings for the 'misc_Rx_bits' */ +#define RX_OVERRUN_ERROR 0x04 /* the incoming block has an overrun error */ +#define HEC_ERROR 0x08 /* the received cell has a HEC error */ + +/* structure used for transmitting and receiving cells that are decoded and formatted by the PHY firmware */ +typedef struct { + unsigned char reserved[5]; /* reserved for internal use */ + unsigned char payload[48]; /* information payload */ + unsigned short GFC_VPI; /* GFC (Generic Flow Control)/VPI (Virtual Path Identifier) */ + unsigned short VCI; /* VCI (Virtual Channel Identifier) */ + unsigned char PT; /* PT (Payload Type) */ + unsigned char CLP; /* CLP (Cell Loss Priority) */ + unsigned char HEC; /* HEC (Header Error Control) */ +} PHY_TX_RX_DECODE_STRUCT; + + + +/* ---------------------------------------------------------------------------- + * Constants defining the shared memory information area + * --------------------------------------------------------------------------*/ + +/* the global information structure */ +typedef struct { + unsigned char global_status; /* global status */ + unsigned char modem_status; /* current modem status */ + unsigned char global_excep_conditions; /* global exception conditions */ + unsigned char glob_info_reserved[5]; /* reserved */ + unsigned char code_name[4]; /* code name */ + unsigned char code_version[4]; /* code version */ +} GLOBAL_INFORMATION_STRUCT; + +/* the PHY information structure */ +typedef struct { + unsigned char Rx_sync_status; /* receiver synchronization status */ + unsigned char PHY_excep_conditions; /* PHY exception conditions */ + unsigned char no_Rx_blocks_avail; /* number of Rx blocks available for the application */ + unsigned char PHY_info_reserved[13]; /* reserved */ +} PHY_INFORMATION_STRUCT; + +/* the interrupt information structure */ +typedef struct { + unsigned char interrupt_type; /* type of interrupt triggered */ + unsigned char interrupt_permission; /* interrupt permission mask */ + unsigned char int_info_reserved[14]; /* reserved */ +} INTERRUPT_INFORMATION_STRUCT; + +/* the front-end information structure */ +typedef struct { + unsigned char parallel_port_A_input; /* input - parallel port A */ + unsigned char parallel_port_B_input; /* input - parallel port B */ + unsigned char FT1_INS_alarm_condition; /* the current FT1 in-service/alarm condition */ + unsigned char FT1_info_reserved[13]; /* reserved */ +} FE_INFORMATION_STRUCT; + +/* the shared memory area information structure */ +typedef struct { + GLOBAL_INFORMATION_STRUCT global_info_struct; /* the global information structure */ + PHY_INFORMATION_STRUCT PHY_info_struct; /* the PHY information structure */ + INTERRUPT_INFORMATION_STRUCT interrupt_info_struct;/* the interrupt information structure */ + FE_INFORMATION_STRUCT FE_info_struct; /* the front-end information structure */ +} SHARED_MEMORY_INFO_STRUCT; + + +#pragma pack() + + +#undef wan_udphdr_data +#define wan_udphdr_data wan_udphdr_u.atm.data + +#ifdef __KERNEL__ +#undef wan_udp_data +#define wan_udp_data wan_udp_hdr.wan_udphdr_u.atm.data +#endif + + +//#define SHARED_MEMORY_INFO_STRUCT void +//#define CONFIGURATION_STRUCT PHY_CONFIGURATION_STRUCT +//#define INTERRUPT_INFORMATION_STRUCT void +#define DATA_RX_STATUS_EL_STRUCT PHY_RX_STATUS_EL_STRUCT +#define DATA_TX_STATUS_EL_STRUCT PHY_TX_STATUS_EL_STRUCT +#define INT_TRIGGERS_STRUCT PHY_INT_TRIGGERS_STRUCT +#define TX_STATUS_EL_CFG_STRUCT PHY_TX_STATUS_EL_CFG_STRUCT +#define RX_STATUS_EL_CFG_STRUCT PHY_RX_STATUS_EL_CFG_STRUCT +//#define TRACE_STATUS_EL_CFG_STRUCT void +//#define TRACE_STATUS_ELEMENT_STRUCT void +//#define LINE_TRACE_CONFIG_STRUCT void +//#define COMMS_ERROR_STATS_STRUCT void +#define OPERATIONAL_STATS_STRUCT PHY_OPERATIONAL_STATS_STRUCT + +#define DFLT_TEMPLATE_VALUE ... + +#define WANCONFIG_FRMW WANCONFIG_ATM + +#define COMMAND_OK OK + +#define APP_INT_ON_TIMER PHY_INT_TIMER +#define APP_INT_ON_TX_FRAME PHY_INT_TX +#define APP_INT_ON_RX_FRAME PHY_INT_RX +#define APP_INT_ON_GLOBAL_EXCEP_COND PHY_INT_GLOBAL_EXCEP_COND +#define APP_INT_ON_EXCEP_COND PHY_INT_PHY_EXCEP_COND +#define APP_INT_ON_COMMAND_COMPLETE PHY_INT_COMMAND_COMPLETE + + +#define COMMAND_COMPLETE_APP_INT_PEND PHY_COMMAND_COMPLETE_INT_PEND +#define RX_APP_INT_PEND PHY_RX_INT_PEND +#define TX_APP_INT_PEND PHY_TX_INT_PEND +#define EXCEP_COND_APP_INT_PEND PHY_PHY_EXCEP_COND_INT_PEND +#define GLOBAL_EXCEP_COND_APP_INT_PEND PHY_GLOBAL_EXCEP_COND_INT_PEND +#define TIMER_APP_INT_PEND PHY_TIMER_INT_PEND +#define TRACE_APP_INT_PEND PHY_TRACE_INT_PEND + + +#define READ_CODE_VERSION PHY_READ_CODE_VERSION + +#define READ_CONFIGURATION PHY_READ_CONFIGURATION +#define SET_CONFIGURATION PHY_SET_CONFIGURATION + +#define DISABLE_COMMUNICATIONS PHY_DISABLE_COMMUNICATIONS +#define ENABLE_COMMUNICATIONS PHY_ENABLE_COMMUNICATIONS + +#define SET_INTERRUPT_TRIGGERS PHY_SET_INTERRUPT_TRIGGERS +#define READ_INTERRUPT_TRIGGERS PHY_READ_INTERRUPT_TRIGGERS + +#define UDPMGMT_SIGNATURE "ATMPIPEA" + +//#define FT1_MONITOR_STATUS_CTRL DFLT_TEMPLATE_VALUE +//#define ENABLE_READ_FT1_STATUS DFLT_TEMPLATE_VALUE +//#define ENABLE_READ_FT1_OP_STATS DFLT_TEMPLATE_VALUE +//#define CPIPE_FT1_READ_STATUS DFLT_TEMPLATE_VALUE +//#define TRACE_INACTIVE DFLT_TEMPLATE_VALUE + +//#define READ_GLOBAL_STATISTICS DFLT_TEMPLATE_VALUE +//#define READ_MODEM_STATUS DFLT_TEMPLATE_VALUE +//#define READ_LINK_STATUS DFLT_TEMPLATE_VALUE +//#define READ_COMMS_ERROR_STATS DFLT_TEMPLATE_VALUE +//#define READ_TRACE_CONFIGURATION DFLT_TEMPLATE_VALUE +//#define GET_TRACE_INFO DFLT_TEMPLATE_VALUE + +enum { + ROUTER_UP_TIME = 0x50, + FT1_READ_STATUS, + SET_FT1_MODE, + ENABLE_TRACING, + DISABLE_TRACING, + GET_TRACE_INFO, + FT1_MONITOR_STATUS_CTRL, + ENABLE_READ_FT1_STATUS, + ENABLE_READ_FT1_OP_STATS, + READ_FT1_OPERATIONAL_STATS, + ATM_LINK_STATUS +}; + +#define ATM_TRACE_CELL 0x01 +#define ATM_TRACE_PDU 0x02 +#define ATM_TRACE_DATA 0x04 + + +#define READ_OPERATIONAL_STATS PHY_READ_OPERATIONAL_STATS +//#define SET_TRACE_CONFIGURATION DFLT_TEMPLATE_VALUE +//#define TRACE_ACTIVE DFLT_TEMPLATE_VALUE + +#define EXCEP_IRQ_TIMEOUT EXCEP_APP_IRQ_TIMEOUT +#define READ_EXCEPTION_CONDITION PHY_READ_EXCEPTION_CONDITION +#define EXCEP_LINK_ACTIVE DFLT_TEMPLATE_VALUE +#define EXCEP_LINK_INACTIVE_MODEM DFLT_TEMPLATE_VALUE +#define EXCEP_LINK_INACTIVE_KPALV DFLT_TEMPLATE_VALUE +#define EXCEP_IP_ADDRESS_DISCOVERED DFLT_TEMPLATE_VALUE +#define EXCEP_LOOPBACK_CONDITION DFLT_TEMPLATE_VALUE +#define NO_EXCEP_COND_TO_REPORT DFLT_TEMPLATE_VALUE + +//#define READ_GLOBAL_EXCEPTION_CONDITION DFLT_TEMPLATE_VALUE +//#define EXCEP_MODEM_STATUS_CHANGE DFLT_TEMPLATE_VALUE +#define DCD_HIGH 0x08 +#define CTS_HIGH 0x20 + +#define INTERFACE_LEVEL_RS232 PHY_INTERFACE_LEVEL_RS232 +#define INTERFACE_LEVEL_V35 PHY_INTERFACE_LEVEL_V35 + + +#define MIN_WP_PRI_MTU 1500 +#define MAX_WP_PRI_MTU MIN_WP_PRI_MTU +#define DEFAULT_WP_PRI_MTU MIN_WP_PRI_MTU + +#define ATM_CELL_SIZE 53 +#define MIN_WP_SEC_MTU 50 +#define MAX_WP_SEC_MTU PHY_MAX_CELLS_IN_RX_BLOCK*ATM_CELL_SIZE/ATM_OVERHEAD +#define DEFAULT_WP_SEC_MTU 1500 + + +/* reasons for enabling the timer interrupt on the adapter */ +#define TMR_INT_ENABLED_UDP 0x01 +#define TMR_INT_ENABLED_UPDATE 0x02 +#define TMR_INT_ENABLED_CONFIG 0x10 +#define TMR_INT_ENABLED_TE 0x20 + +#ifdef __KERNEL__ + +#define PRI_BASE_ADDR_MB_STRUCT BASE_ADDR_MB_STRUCT + +extern unsigned char calculate_hec_crc(unsigned char *util_ptr); + +#endif +#endif diff -Nur linux.org/include/linux/sdla_bitstrm.h linux-2.6.17/include/linux/sdla_bitstrm.h --- linux.org/include/linux/sdla_bitstrm.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/sdla_bitstrm.h 2006-08-30 10:07:15.000000000 +0000 @@ -0,0 +1,563 @@ +/********************************************************************************** + * * + * BSTRMAPI.H - the 'C' header file for the Sangoma S508/S514 BITSTREAM code API. * + * * + ********************************************************************************** +*/ + +#ifndef _SDLA_BITSTRM_H_ +#define _SDLA_BITSTRM_H_ + +#include + +#pragma pack(1) + +/* ---------------------------------------------------------------------------- + * Constants defining the shared memory control block (mailbox) + * --------------------------------------------------------------------------*/ + +#define PRI_BASE_ADDR_MB_STRUCT 0xE000 /* the base address of the mailbox structure (primary port) */ +#define SEC_BASE_ADDR_MB_STRUCT 0xE800 /* the base address of the mailbox structure (secondary port) */ +#define NUMBER_MB_RESERVED_BYTES 0x0B /* the number of reserved bytes in the mailbox header area */ +#define SIZEOF_MB_DATA_BFR 2032 /* the size of the actual mailbox data area */ + +#if 0 +/* the control block mailbox structure */ +typedef struct { + unsigned char opp_flag; /* the opp flag */ + unsigned char command; /* the user command */ + unsigned short buffer_length; /* the data length */ + unsigned char return_code; /* the return code */ + char MB_reserved[NUMBER_MB_RESERVED_BYTES]; /* reserved for later use */ + char data[SIZEOF_MB_DATA_BFR]; /* the data area */ +} BSTRM_MAILBOX_STRUCT; +#endif + + +/* ---------------------------------------------------------------------------- + * Interface commands + * --------------------------------------------------------------------------*/ + +/* global interface commands */ +#define READ_GLOBAL_EXCEPTION_CONDITION 0x01 /* read a global exception condition from the adapter */ +#define SET_GLOBAL_CONFIGURATION 0x02 /* set the global operational configuration */ +#define READ_GLOBAL_CONFIGURATION 0x03 /* read the global configuration */ +#define READ_GLOBAL_STATISTICS 0x04 /* retrieve the global statistics */ +#define FLUSH_GLOBAL_STATISTICS 0x05 /* flush the global statistics */ +#define SET_MODEM_STATUS 0x06 /* set the status of DTR and/or RTS */ +#define READ_MODEM_STATUS 0x07 /* read the current status of CTS and DCD */ +#define READ_COMMS_ERROR_STATS 0x08 /* read the communication error statistics */ +#define FLUSH_COMMS_ERROR_STATS 0x09 /* flush the communication error statistics */ + +/* BSTRM-level interface commands */ +#define READ_BSTRM_CODE_VERSION 0x20 /* read the BSTRM code version */ +#define READ_BSTRM_EXCEPTION_CONDITION 0x21 /* read an BSTRM exception condition from the adapter */ +#define SET_BSTRM_CONFIGURATION 0x22 /* set the BSTRM configuration */ +#define READ_BSTRM_CONFIGURATION 0x23 /* read the BSTRM configuration */ +#define ENABLE_BSTRM_COMMUNICATIONS 0x24 /* enable BSTRM communications */ +#define DISABLE_BSTRM_COMMUNICATIONS 0x25 /* disable BSTRM communications */ +#define READ_BSTRM_STATUS 0x26 /* read the BSTRM status */ +#define READ_BSTRM_OPERATIONAL_STATS 0x27 /* retrieve the BSTRM operational statistics */ +#define FLUSH_BSTRM_OPERATIONAL_STATS 0x28 /* flush the BSTRM operational statistics */ +#define SET_BSTRM_INTERRUPT_TRIGGERS 0x30 /* set the BSTRM application interrupt triggers */ +#define READ_BSTRM_INTERRUPT_TRIGGERS 0x31 /* read the BSTRM application interrupt trigger configuration */ + + + +/* ---------------------------------------------------------------------------- + * Return codes from interface commands + * --------------------------------------------------------------------------*/ + +#define OK 0x00 /* the interface command was successful */ + +/* return codes from global interface commands */ +#define NO_GLOBAL_EXCEP_COND_TO_REPORT 0x01 /* there is no BSTRM exception condition to report */ +#define LGTH_GLOBAL_CFG_DATA_INVALID 0x01 /* the length of the passed global configuration data is invalid */ +#define IRQ_TIMEOUT_VALUE_INVALID 0x02 /* an invalid application IRQ timeout value was selected */ +#define ADAPTER_OPERATING_FREQ_INVALID 0x03 /* an invalid adapter operating frequency was selected */ +#define TRANSMIT_TIMEOUT_INVALID 0x04 /* the block transmit timeout is invalid */ + +/* return codes from command READ_GLOBAL_EXCEPTION_CONDITION */ +#define EXCEP_MODEM_STATUS_CHANGE 0x10 /* a modem status change occurred */ +#define EXCEP_APP_IRQ_TIMEOUT 0x12 /* an application IRQ timeout has occurred */ + +/* return codes from BSTRM-level interface commands */ +#define NO_BSTRM_EXCEP_COND_TO_REPORT 0x21 /* there is no BSTRM exception condition to report */ +#define BSTRM_COMMS_DISABLED 0x21 /* communications are not currently enabled */ +#define BSTRM_COMMS_ENABLED 0x21 /* communications are currently enabled */ +#define DISABLE_COMMS_BEFORE_CFG 0x21 /* communications must be disabled before setting the configuration */ +#define ENABLE_BSTRM_COMMS_BEFORE_CONN 0x21 /* communications must be enabled before using the BSTRM_CONNECT conmmand */ +#define CFG_BEFORE_COMMS_ENABLED 0x22 /* perform a SET_BSTRM_CONFIGURATION before enabling comms */ +#define LGTH_BSTRM_CFG_DATA_INVALID 0x22 /* the length of the passed configuration data is invalid */ +#define LGTH_INT_TRIGGERS_DATA_INVALID 0x22 /* the length of the passed interrupt trigger data is invalid */ +#define INVALID_IRQ_SELECTED 0x23 /* an invalid IRQ was selected in the SET_BSTRM_INTERRUPT_TRIGGERS */ +#define INVALID_BSTRM_CFG_DATA 0x23 /* the passed configuration data is invalid */ +#define IRQ_TMR_VALUE_INVALID 0x24 /* an invalid application IRQ timer value was selected */ +#define T1_E1_AMI_NOT_SUPPORTED 0x25 /* T1/E1 - AMI decoding not supported */ +#define S514_BOTH_PORTS_SAME_CLK_MODE 0x26 /* S514 - both ports must have the same clocking mode */ +#define INVALID_BSTRM_COMMAND 0x4F /* the defined BSTRM interface command is invalid */ +#define COMMAND_INVALID_FOR_PORT 0x50 /* the command is invalid for the selected port */ + +/* return codes from command READ_BSTRM_EXCEPTION_CONDITION */ +#define EXCEP_SYNC_LOST 0x30 /* the BSTRM receiver has lost synchronization */ +#define EXCEP_SYNC_ACHIEVED 0x31 /* the BSTRM receiver has achieved synchronization */ +#define EXCEP_RX_DISCARD 0x36 /* an incoming block of data was discarded */ +#define EXCEP_TX_IDLE 0x37 /* a block was transmitted from the idle buffer */ + + + + +/* ---------------------------------------------------------------------------- + * Constants for the SET_GLOBAL_CONFIGURATION/READ_GLOBAL_CONFIGURATION commands + * --------------------------------------------------------------------------*/ + +/* the global configuration structure */ +typedef struct { + unsigned short adapter_config_options; /* adapter configuration options */ + unsigned short app_IRQ_timeout; /* application IRQ timeout */ + unsigned long adapter_operating_frequency; /* adapter operating frequency */ +} GLOBAL_CONFIGURATION_STRUCT; + +/* settings for the 'adapter_config_options' */ +#define ADPTR_CFG_S514 0x0001 /* S514 adapter */ + +/* settings for the 'app_IRQ_timeout' */ +#define MAX_APP_IRQ_TIMEOUT_VALUE 5000 /* the maximum permitted IRQ timeout */ + + + +/* ---------------------------------------------------------------------------- + * Constants for the READ_GLOBAL_STATISTICS command + * --------------------------------------------------------------------------*/ + +/* the global statistics structure */ +typedef struct { + unsigned short app_IRQ_timeout_count; /* application IRQ timeout count */ +} GLOBAL_STATS_STRUCT; + + + +/* ---------------------------------------------------------------------------- + * Constants for the READ_BSTRM_EXCEPTION_CONDITION command + * --------------------------------------------------------------------------*/ + +/* the structure returned on a return code EXCEP_RX_DISCARD and EXCEP_TX_IDLE */ +typedef struct { + unsigned long Rx_discard_count; /* number of incoming blocks discarded */ + unsigned long Tx_idle_count; /* number of Tx blocks transmitted from the idle code buffer (T1/E1) */ +} RX_DISC_TX_IDLE_EXCEP_STRUCT; + + + +/* ---------------------------------------------------------------------------- + * Constants for the READ_COMMS_ERROR_STATS command + * --------------------------------------------------------------------------*/ + +/* the communications error statistics structure */ +typedef struct { + unsigned short Rx_overrun_err_count; /* receiver overrun error count */ + unsigned short Rx_dis_pri_bfrs_full_count; /* receiver disabled count */ + unsigned short pri_missed_Tx_DMA_int_count; /* primary port - missed Tx DMA interrupt count */ + unsigned short sync_lost_count; /* synchronization lost count */ + unsigned short sync_achieved_count; /* synchronization achieved count */ + unsigned short P0_T1_E1_sync_failed_count; /* T1/E1 synchronization failure count */ + unsigned short reserved_1; /* reserved for later use */ + unsigned short DCD_state_change_count; /* DCD state change count */ + unsigned short CTS_state_change_count; /* CTS state change count */ +} COMMS_ERROR_STATS_STRUCT; + + + +/* ---------------------------------------------------------------------------- + * Constants for the SET_BSTRM_CONFIGURATION/READ_BSTRM_CONFIGURATION command + * --------------------------------------------------------------------------*/ + +/* the BSTRM configuration structure */ +typedef struct { + unsigned long baud_rate; /* the baud rate */ + unsigned short line_config_options; /* line configuration options */ + unsigned short modem_config_options; /* modem configuration options */ + unsigned short modem_status_timer; /* timer for monitoring modem status changes */ + unsigned short API_options; /* API options */ + unsigned short SYNC_options; /* sync options */ + unsigned short Rx_sync_char; /* receive sync character */ + unsigned char monosync_Tx_time_fill_char; /* transmit time fill character (monosync mode) */ + unsigned short buffer_options; /* Tx/Rx buffer options */ + unsigned short max_length_Tx_data_block; /* the maximum length of a Tx data block */ + unsigned short Rx_complete_length; /* length of receive block */ + unsigned short Rx_complete_timer; /* the Rx completion timer */ + unsigned short statistics_options; /* operational statistics options */ + unsigned long ptr_shared_mem_info_struct; /* a pointer to the shared memory area information structure */ + unsigned long ptr_Tx_stat_el_cfg_struct; /* a pointer to the transmit status element configuration structure */ + unsigned long ptr_Rx_stat_el_cfg_struct; /* a pointer to the receive status element configuration structure */ +} BSTRM_CONFIGURATION_STRUCT; + +/* settings for the 'line_config_options' */ +#define INTERFACE_LEVEL_V35 0x0000 /* V.35 interface level */ + +#define INTERFACE_LEVEL_RS232 0x0001 /* RS-232 interface level */ + +#define NRZI_ENCODING 0x0010 /* NRZI data encoding */ + +/* settings for the 'modem_config_options' */ +#define DONT_RAISE_DTR_RTS_ON_EN_COMMS 0x0001 /* don't automatically raise DTR and RTS when performing an */ + /* ENABLE_BSTRM_COMMUNICATIONS command */ +#define DONT_REPORT_CHG_IN_MODEM_STAT 0x0002 /* don't report changes in modem status to the application */ + +/* settings for the 'API_options' */ +#define MANUAL_RESYNC_AFTER_SYNC_LOSS 0x0001 /* manual re-synchronization after synchronization loss */ +#define PERMIT_APP_INT_TX_RX_BFR_ERR 0x0002 /* permit a BSTRM exception condition interrupt on a Tx or Rx */ + /* buffer error */ + +/* settings for the 'SYNC_options' */ +#define MONOSYNC_8_BIT_SYNC 0x0001 /* monosync, 8-bit sync character */ +#define MONOSYNC_6_BIT_SYNC 0x0002 /* monosync, 6-bit sync character */ +#define BISYNC_16_BIT_SYNC 0x0004 /* bisync, 16-bit sync character */ +#define BISYNC_12_BIT_SYNC 0x0008 /* bisync, 12-bit sync character */ +#define EXTERNAL_SYNC_8_BIT_TIME_FILL 0x0010 /* external sync, 8-bit sync character */ +#define EXTERNAL_SYNC_6_BIT_TIME_FILL 0x0020 /* external sync, 6-bit sync character */ +#define SYNC_CHAR_LOAD_INHIBIT 0x0100 /* inhibit loading of the received sync character */ +/* ??????????????wwwwwww */ +#define T1_E1_ENABLE_TX_ALIGN_CHECK 0x1000 /* T1/E1 - enable checking of the transmit channel alignment */ + +/* bit settings for the 'buffer_options' */ +#define TX_ONLY 0x0001 /* transmit only for this port (no reception) */ +#define RX_ONLY 0x0002 /* receive only for this port (no transmission) */ +#define SINGLE_TX_BUFFER 0x0010 /* configure a single transmit buffer */ +#define SEC_DMA_RX 0x0100 /* secondary port - configure for high speed DMA receive mode */ + +/* settings for the 'statistics_options' */ +#define TX_DATA_BYTE_COUNT_STAT 0x0001 /* record the number of data bytes transmitted */ +#define RX_DATA_BYTE_COUNT_STAT 0x0002 /* record the number of data bytes received */ +#define TX_THROUGHPUT_STAT 0x0004 /* compute the data transmit throughput */ +#define RX_THROUGHPUT_STAT 0x0008 /* compute the data receive throughput */ + +/* permitted minimum and maximum values for setting the BSTRM configuration */ +#define PRI_MAX_BAUD_RATE_S508 2666666 /* primary port - maximum baud rate (S508) */ +#define SEC_MAX_BAUD_RATE_S508 258064 /* secondary port - maximum baud rate (S508) */ +#define PRI_MAX_BAUD_RATE_S514 2750000 /* primary port - maximum baud rate (S514) */ +#define SEC_MAX_BAUD_RATE_S514 515625 /* secondary port - maximum baud rate (S514) */ +#define MIN_PERMITTED_MODEM_TIMER 0 /* minimum modem status timer */ +#define MAX_PERMITTED_MODEM_TIMER 5000 /* maximum modem status timer */ +#define PRI_MAX_LENGTH_TX_DATA_BLOCK 4096 /* primary port - maximum length of the Tx data block */ +#define SEC_MAX_LENGTH_TX_DATA_BLOCK 2048 /* secondary port - maximum length of the Tx data block */ +#define MAX_RX_COMPLETE_LENGTH 4096 /* the maximum length of receive data block */ +#define MAX_RX_COMPLETE_TIMER 60000 /* the maximum Rx completion timer value */ + + + +/* ---------------------------------------------------------------------------- + * Constants for the READ_BSTRM_STATUS command + * --------------------------------------------------------------------------*/ + +/* the BSTRM status structure */ +typedef struct { + unsigned char sync_status; /* synchronization status */ + unsigned char BSTRM_excep_conditions; /* BSTRM exception conditions */ + unsigned char no_Rx_data_blocks_avail; /* number of Rx data blocks available for the application */ + unsigned char receiver_status; /* receiver status (enabled/disabled) */ +} READ_BSTRM_STATUS_STRUCT; + +/* settings for the 'sync_status' variable */ +#define SYNC_LOST 0x01 +#define SYNC_ACHIEVED 0x02 + +/* settings for the 'receiver_status' variable */ +#define RCVR_NOT_DISCARD 0x00 /* receiver not discarding incoming blocks */ +#define RCVR_DISCARD 0x01 /* receiver discarding incoming blocks */ + + + +/* ---------------------------------------------------------------------------- + * Constants for the READ_BSTRM_OPERATIONAL_STATS command + * --------------------------------------------------------------------------*/ + +/* the BSTRM operational statistics structure */ +typedef struct { + + /* data transmission statistics */ + unsigned long blocks_Tx_count; /* number of blocks transmitted */ + unsigned long bytes_Tx_count; /* number of bytes transmitted */ + unsigned long Tx_throughput; /* transmit throughput */ + unsigned long no_ms_for_Tx_thruput_comp; /* millisecond time used for the Tx throughput computation */ + unsigned long Tx_idle_count; /* number of times the transmitter reverted to the idle line condition (serial) OR */ + /* number of Tx blocks transmitted from the idle code buffer (T1/E1) */ + unsigned long Tx_discard_lgth_err_count; /* number of Tx blocks discarded (length error) */ + unsigned long reserved_Tx_stat0; /* reserved for later use */ + unsigned long reserved_Tx_stat1; /* reserved for later use */ + unsigned long reserved_Tx_stat2; /* reserved for later use */ + + /* data reception statistics */ + unsigned long blocks_Rx_count; /* number of blocks received */ + unsigned long bytes_Rx_count; /* number of bytes received */ + unsigned long Rx_throughput; /* receive throughput */ + unsigned long no_ms_for_Rx_thruput_comp; /* millisecond time used for the Rx throughput computation */ + unsigned long Rx_discard_count; /* number of incoming blocks discarded */ + unsigned long reserved_Rx_stat1; /* reserved for later use */ + unsigned long reserved_Rx_stat2; /* reserved for later use */ + +} BSTRM_OPERATIONAL_STATS_STRUCT; + + + +/* ---------------------------------------------------------------------------- + * Constants for using application interrupts + * --------------------------------------------------------------------------*/ + +/* the structure used for the SET_BSTRM_INTERRUPT_TRIGGERS/READ_BSTRM_INTERRUPT_TRIGGERS command */ +typedef struct { + unsigned char BSTRM_interrupt_triggers; /* BSTRM interrupt trigger configuration */ + unsigned char IRQ; /* IRQ to be used */ + unsigned short interrupt_timer; /* interrupt timer */ + unsigned short misc_interrupt_bits; /* miscellaneous interrupt bits */ +} BSTRM_INT_TRIGGERS_STRUCT; + +/* 'BSTRM_interrupt_triggers' bit settings */ +#define APP_INT_ON_RX_BLOCK 0x01 /* interrupt on data block reception */ +#define APP_INT_ON_TX_BLOCK 0x02 /* interrupt when an data block may be transmitted */ +#define APP_INT_ON_COMMAND_COMPLETE 0x04 /* interrupt when an interface command is complete */ +#define APP_INT_ON_TIMER 0x08 /* interrupt on a defined millisecond timeout */ +#define APP_INT_ON_GLOBAL_EXCEP_COND 0x10 /* interrupt on a global exception condition */ +#define APP_INT_ON_BSTRM_EXCEP_COND 0x20 /* interrupt on an BSTRM exception condition */ + +/* 'interrupt_timer' limitation */ +#define MAX_INTERRUPT_TIMER_VALUE 60000 /* the maximum permitted timer interrupt value */ + +/* interrupt types indicated at 'interrupt_type' byte of the INTERRUPT_INFORMATION_STRUCT */ +#define NO_APP_INTS_PEND 0x00 /* no interrups are pending */ +#define RX_APP_INT_PEND 0x01 /* a receive interrupt is pending */ +#define TX_APP_INT_PEND 0x02 /* a transmit interrupt is pending */ +#define COMMAND_COMPLETE_APP_INT_PEND 0x04 /* a 'command complete' interrupt is pending */ +#define TIMER_APP_INT_PEND 0x08 /* a timer interrupt is pending */ +#define GLOBAL_EXCEP_COND_APP_INT_PEND 0x10 /* a global exception condition interrupt is pending */ +#define BSTRM_EXCEP_COND_APP_INT_PEND 0x20 /* an BSTRM exception condition interrupt is pending */ + + + +/* ---------------------------------------------------------------------------- + * Constants for data block transmission + * --------------------------------------------------------------------------*/ + +/* the data block transmit status element configuration structure */ +typedef struct { + unsigned short number_Tx_status_elements; /* number of transmit status elements */ + unsigned long base_addr_Tx_status_elements; /* base address of the transmit element list */ + unsigned long next_Tx_status_element_to_use; /* pointer to the next transmit element to be used */ +} BSTRM_TX_STATUS_EL_CFG_STRUCT; + +/* the data block transmit status element structure */ +typedef struct { + unsigned char opp_flag; /* opp flag */ + unsigned short block_length; /* length of the block to be transmitted */ + unsigned char misc_Tx_bits; /* miscellaneous transmit bits */ + unsigned short Tx_time_fill_char; /* transmit time fill character */ + unsigned short reserved_0; /* reserved for internal use */ + unsigned long reserved_1; /* reserved for internal use */ + unsigned long ptr_data_bfr; /* pointer to the data area */ +} BSTRM_DATA_TX_STATUS_EL_STRUCT; + +/* settings for the 'misc_Tx_bits' */ +#define UPDATE_TX_TIME_FILL_CHAR 0x01 /* update the transmit time fill character */ + + + +/* ---------------------------------------------------------------------------- + * Constants for data block reception + * --------------------------------------------------------------------------*/ + +/* the data block receive status element configuration structure */ +typedef struct { + unsigned short number_Rx_status_elements; /* number of receive status elements */ + unsigned long base_addr_Rx_status_elements; /* base address of the receive element list */ + unsigned long next_Rx_status_element_to_use; /* pointer to the next receive element to be used */ +} BSTRM_RX_STATUS_EL_CFG_STRUCT; + +/* the data block receive status element structure */ +typedef struct { + unsigned char opp_flag; /* opp flag */ + unsigned short block_length; /* length of the received block */ + unsigned char error_flag; /* block errors */ + unsigned short time_stamp; /* receive time stamp */ + unsigned long reserved_0; /* reserved for internal use */ + unsigned short reserved_1; /* reserved for internal use */ + unsigned long ptr_data_bfr; /* pointer to the data area */ +} BSTRM_DATA_RX_STATUS_EL_STRUCT; + +/* settings for the 'error_flag' */ +#define RX_OVERRUN_ERROR 0x04 /* the incoming block has an overrun error */ + + + +/* ---------------------------------------------------------------------------- + * Constants defining the shared memory information area + * --------------------------------------------------------------------------*/ + +/* the global information structure */ +typedef struct { + unsigned char global_status; /* global status */ + unsigned char modem_status; /* current modem status */ + unsigned char global_excep_conditions; /* global exception conditions */ + unsigned char Rx_disabled_Rx_bfrs_full; /* receiver disabled */ + unsigned char glob_info_reserved[4]; /* reserved */ + unsigned char code_name[4]; /* code name */ + unsigned char code_version[4]; /* code version */ +} GLOBAL_INFORMATION_STRUCT; + +/* the BSTRM information structure */ +typedef struct { + unsigned char sync_status; /* synchronization status */ + unsigned char BSTRM_excep_conditions; /* BSTRM exception conditions */ + unsigned char no_Rx_data_blocks_avail; /* number of Rx data blocks available for the application */ + unsigned long Rx_discard_count; /* number of incoming blocks discarded */ + unsigned long Tx_idle_count; /* number of Tx blocks transmitted from the idle code buffer (T1/E1) */ + unsigned char BSTRM_info_reserved[5]; /* reserved */ +} BSTRM_INFORMATION_STRUCT; + +/* the interrupt information structure */ +typedef struct { + unsigned char interrupt_type; /* type of interrupt triggered */ + unsigned char interrupt_permission; /* interrupt permission mask */ + unsigned char int_info_reserved[14]; /* reserved */ +} INTERRUPT_INFORMATION_STRUCT; + +/* the FT1 information structure */ +typedef struct { + unsigned char parallel_port_A_input; /* input - parallel port A */ + unsigned char parallel_port_B_input; /* input - parallel port B */ + unsigned char FT1_INS_alarm_condition; /* the current FT1 in-service/alarm condition */ + unsigned char FT1_info_reserved[13]; /* reserved */ +} FT1_INFORMATION_STRUCT; + +/* settings for the 'FT1_INS_alarm_condition' */ +#define BITSTRM_FT1_IN_SERVICE 0x00 /* the FT1 is in-service */ +#define BITSTRM_BLUE_ALARM 'B' /* blue alarm condition */ +#define BITSTRM_YELLOW_ALARM 'Y' /* yellow alarm condition */ +#define BITSTRM_RED_ALARM 'R' /* red alarm condition */ + +/* the shared memory area information structure */ +typedef struct { + GLOBAL_INFORMATION_STRUCT global_info_struct; /* the global information structure */ + BSTRM_INFORMATION_STRUCT BSTRM_info_struct; /* the BSTRM information structure */ + INTERRUPT_INFORMATION_STRUCT interrupt_info_struct;/* the interrupt information structure */ + FT1_INFORMATION_STRUCT FT1_info_struct; /* the FT1 information structure */ +} SHARED_MEMORY_INFO_STRUCT; + + + + + + +typedef struct { + unsigned char error_flag ; + unsigned short time_stamp ; + unsigned char channel ; + unsigned char direction ; + unsigned char reserved[11] ; +} api_rx_hdr_t; + +typedef struct { + api_rx_hdr_t api_rx_hdr ; + unsigned char data[1] ; +} api_rx_element_t; + +typedef struct { + unsigned char attr ; + unsigned char reserved[15] ; +} api_tx_hdr_t; + +typedef struct { + api_tx_hdr_t api_tx_hdr ; + unsigned char data[1] ; +} api_tx_element_t; + + +/* Special UDP drivers management commands */ +#define BPIPE_ENABLE_TRACING 0x50 +#define BPIPE_DISABLE_TRACING 0x51 +#define BPIPE_GET_TRACE_INFO 0x52 +#define BPIPE_GET_IBA_DATA 0x53 +#define BPIPE_FT1_READ_STATUS 0x54 +#define BPIPE_DRIVER_STAT_IFSEND 0x55 +#define BPIPE_DRIVER_STAT_INTR 0x56 +#define BPIPE_DRIVER_STAT_GEN 0x57 +#define BPIPE_FLUSH_DRIVER_STATS 0x58 +#define BPIPE_ROUTER_UP_TIME 0x59 + + +/* modem status changes */ +#define DCD_HIGH 0x08 +#define CTS_HIGH 0x20 + +#define UDPMGMT_SIGNATURE "BTPIPEAB" +/* valid ip_protocol for UDP management */ +#define UDPMGMT_UDP_PROTOCOL 0x11 + +#pragma pack() + + + +enum { + SIOC_WANPIPE_BITSTRM_T1E1_CFG = SIOC_WANPIPE_PIPEMON + 1, + SIOC_CUSTOM_BITSTRM_COMMANDS, + + SIOC_WRITE_RBS_SIG = SIOC_WANPIPE_DEVPRIVATE, + SIOC_READ_RBS_SIG +}; + +enum { + COMMS_ALREADY_ENABLED=1, + COMMS_ALREADY_DISABLED, + IF_IN_DISCONNECED_STATE, + FRONT_END_IN_DISCONNECTED_STATE +}; + + +typedef struct{ + unsigned char control_code; + unsigned short reg; + unsigned char bit_number; +}custom_control_call_t; + +//values for 'control_code' +enum { + SET_BIT_IN_PMC_REGISTER, + RESET_BIT_IN_PMC_REGISTER +}; + +#ifdef __KERNEL__ + +static inline void bstrm_skb_queue_purge(struct sk_buff_head *list) +{ + struct sk_buff *skb; + while ((skb=skb_dequeue(list))!=NULL) + dev_kfree_skb_any(skb); +} + +static inline void bstrm_test_rx_tx_discard (sdla_t *card) +{ + unsigned long cnt; + card->hw_iface.peek(card->hw, card->u.b.rx_discard_off, + &cnt,sizeof(unsigned long)); + if (cnt){ + DEBUG_EVENT("%s: Error: Rx discard cnt %lu\n", + card->devname,cnt); + cnt=0; + card->hw_iface.poke(card->hw, card->u.b.rx_discard_off, + &cnt,sizeof(unsigned long)); + } + + card->hw_iface.peek(card->hw, card->u.b.rx_discard_off, + &cnt,sizeof(unsigned long)); + if (cnt){ + DEBUG_EVENT("%s: Error: Tx idle cnt %lu\n", + card->devname,cnt); + cnt=0; + card->hw_iface.poke(card->hw, card->u.b.tx_idle_off, + &cnt,sizeof(unsigned long)); + } +} + +#endif + + +#endif diff -Nur linux.org/include/linux/sdla_bscmp.h linux-2.6.17/include/linux/sdla_bscmp.h --- linux.org/include/linux/sdla_bscmp.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/sdla_bscmp.h 2006-08-30 10:07:15.000000000 +0000 @@ -0,0 +1,143 @@ + +#ifndef _BSC_HEADER_ +#define _BSC_HEADER_ + + +#ifndef PACKED +#define PACKED __attribute__((packed)) +#endif /* PACKED */ + + +/*========== MAILBOX COMMANDS AND RETURN CODES ==========*/ +#define BSC_READ 0x00 +#define BSC_WRITE 0x01 +#define OPEN_LINK 0x02 +#define CLOSE_LINK 0x03 +#define CAM_WRITE 0x04 +#define CAM_READ 0x05 +#define LINK_STATUS 0x06 +#define READ_OPERATIONAL_STATISTICS 0x07 +#define FLUSH_OPERATIONAL_STATISTICS 0x08 +#define READ_COMMS_ERROR_STATISTICS 0x09 +#define FLUSH_COMMS_ERROR_STATISTICS 0x0A +#define READ_BSC_ERROR_STATISTICS 0x0B +#define FLUSH_BSC_ERROR_STATISTICS 0x0C +#define FLUSH_BSC_TEXT_BUFFERS 0x0D +#define SET_CONFIGURATION 0x0E +#define READ_CONFIGURATION 0x0F +#define SET_MODEM_STATUS 0x10 +#define READ_MODEM_STATUS 0x11 +#define READ_CODE_VERSION 0x12 +#define ADD_STATION 0x20 +#define DELETE_STATION 0x21 +#define DELETE_ALL_STATIONS 0x22 +#define LIST_STATIONS 0x23 +#define SET_GENERAL_OR_SPECIFIC_POLL 0x24 +#define SET_STATION_STATUS 0x25 + +#define READ_STATE_DIAGNOSTICS 0x30 + +#define UNUSED_CMD_FOR_EVENTS 0x7e + +#define Z80_TIMEOUT_ERROR 0x0a +#define DATA_LENGTH_TOO_BIG 0x03 + +#define BSC_SENDBOX 0xF000 /* send mailbox */ + +#define MDATALEN 4000 +#define MBOX_HEADER_SZ 15 + +/* for point-to-point, ignore station_number and address fields in CBLOCK */ + +/* note: structure must be packed on 1-byte boundaries + and for a block this size, it is not wise to allocate it on + the stack - should be a static global +*/ +/* control block */ +typedef struct { + unsigned char opp_flag PACKED; + unsigned char command PACKED; + unsigned short buffer_length PACKED; + unsigned char return_code PACKED; + unsigned char misc_tx_rx_bits PACKED; + unsigned short heading_length PACKED; + unsigned short notify PACKED; + unsigned char station PACKED; + unsigned char poll_address PACKED; + unsigned char select_address PACKED; + unsigned char device_address PACKED; + unsigned char notify_extended PACKED; + unsigned char reserved PACKED; + unsigned char data[MDATALEN] PACKED; +} BSC_MAILBOX_STRUCT; + + + +typedef struct { + unsigned char line_speed_number PACKED; + unsigned short max_data_frame_size PACKED; + unsigned char secondary_station PACKED; + unsigned char num_consec_PAD_eof PACKED; + unsigned char num_add_lead_SYN PACKED; + unsigned char conversational_mode PACKED; + unsigned char pp_dial_up_operation PACKED; + unsigned char switched_CTS_RTS PACKED; + unsigned char EBCDIC_encoding PACKED; + unsigned char auto_open PACKED; + unsigned char misc_bits PACKED; + unsigned char protocol_options1 PACKED; + unsigned char protocol_options2 PACKED; + unsigned short reserved_pp PACKED; + unsigned char max_retransmissions PACKED; + unsigned short fast_poll_retries PACKED; + unsigned short TTD_retries PACKED; + unsigned short restart_timer PACKED; + unsigned short pp_slow_restart_timer PACKED; + unsigned short TTD_timer PACKED; + unsigned short pp_delay_between_EOT_ENQ PACKED; + unsigned short response_timer PACKED; + unsigned short rx_data_timer PACKED; + unsigned short NAK_retrans_delay_timer PACKED; + unsigned short wait_CTS_timer PACKED; + unsigned char mp_max_consec_ETX PACKED; + unsigned char mp_general_poll_address PACKED; + unsigned short sec_poll_timeout PACKED; + unsigned char pri_poll_skips_inactive PACKED; + unsigned char sec_additional_stn_send_gpoll PACKED; + unsigned char pri_select_retries PACKED; + unsigned char mp_multipoint_options PACKED; + unsigned short reserved PACKED; +} BSC_CONFIG_STRUCT; + + +typedef struct { + unsigned char max_tx_queue PACKED; + unsigned char max_rx_queue PACKED; + unsigned char station_flags PACKED; +}ADD_STATION_STRUCT; + +typedef struct { + unsigned char station PACKED; + unsigned short time_stamp PACKED; + unsigned char reserved[13] PACKED; +} api_rx_hdr_t; + +typedef struct { + api_rx_hdr_t api_rx_hdr PACKED; + void * data PACKED; +} api_rx_element_t; + +typedef struct { + unsigned char station PACKED; + unsigned char misc_tx_rx_bits PACKED; + unsigned char reserved[14] PACKED; +} api_tx_hdr_t; + +typedef struct { + api_tx_hdr_t api_tx_hdr PACKED; + void * data PACKED; +} api_tx_element_t; + +#define SIOC_WANPIPE_EXEC_CMD SIOC_WANPIPE_DEVPRIVATE + +#endif diff -Nur linux.org/include/linux/sdla_bscstrm.h linux-2.6.17/include/linux/sdla_bscstrm.h --- linux.org/include/linux/sdla_bscstrm.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/sdla_bscstrm.h 2006-08-30 10:07:15.000000000 +0000 @@ -0,0 +1,262 @@ +/* $Header$ */ + + +/* + *********************************************************************************** + * * + * BSTRMAPI.H is the 'C' API header file for the Sangoma BSC Tx/Rx streaming code. * + * * + *********************************************************************************** +*/ + + +/* + * $Log$ + * Revision 1.3 2004/09/28 21:47:30 sangoma + * *** empty log message *** + * + * Revision 1.2 2004/04/21 21:11:20 sangoma + * *** empty log message *** + * + * Revision 1.1.1.1 2002/11/25 09:20:00 ncorbic + * Wanpipe Linux Development + * + * Revision 1.2 2002/06/05 09:32:55 ncorbic + * *** empty log message *** + * + * Revision 1.1 2002/03/20 20:58:43 ncorbic + * *** empty log message *** + * + * + * Rev 1.2 24 Nov 1998 12:08:54 gideon + * Added definitions to handle the inclusion of timer interrupt logic. + * The code version is now 1.03. + * + * + * Rev 1.1 30 Jan 1998 17:29:54 gideon + * Modifications made to improve error handling when receiving Type 3 blocks as + * follows: + * 1) The 'comms_err_res_Rx' in the COMMUNICATIONS_ERROR_STRUCT was changed to + * 'Rx_invalid_block_count'. + * 2) Added the definition RX_INVALID_BLOCK for the 'Rx_error_bits' in the + * RECEIVE mailbox. + * The code version is now 1.02. + * + * + * Rev 1.0 10 Dec 1997 11:19:48 gideon + * Initial revision. + * + * + */ + +#ifndef _BSCSTRM_HEADER_ +#define _BSCSTRM_HEADER_ + +#pragma pack(1) + +/* physical addresses on the adapter */ +#define BASE_ADDR_SEND_MB 0xE000 /* the base address of the SEND mailbox area */ +#define BASE_ADDR_RECEIVE_MB 0xF000 /* the base address of the RECEIVE mailbox area */ +#define PTR_INTERRUPT_REPORT_IB 0xFFF0 /* a pointer to the interrupt reporting interface byte */ +#define PTR_INTERRUPT_PERMIT_IB 0xFFF1 /* a pointer to the interrupt permission interface byte */ +#define PTR_MODEM_STATUS_IB 0xFFF4 /* a pointer to the modem status interface byte */ + + + +/* BSC streaming commands */ +#define BSC_WRITE 0x01 /* transmit a BSC block */ +#define ENABLE_COMMUNICATIONS 0x02 /* enable communications */ +#define DISABLE_COMMUNICATIONS 0x03 /* disable communications */ +#define READ_OPERATIONAL_STATS 0x07 /* retrieve the operational statistics */ +#define FLUSH_OPERATIONAL_STATS 0x08 /* flush the operational statistics */ +#define READ_COMMS_ERR_STATS 0x09 /* read the communication error statistics */ +#define FLUSH_COMMS_ERR_STATS 0x0A /* flush the communication error statistics */ +#define SET_MODEM_STATUS 0x0B /* set the modem status */ +#define READ_MODEM_STATUS 0x0C /* read the current modem status (CTS and DCD status) */ +#define FLUSH_BSC_BUFFERS 0x0D /* flush any queued transmit and receive buffers */ +#define READ_CONFIGURATION 0x10 /* read the current operational configuration */ +#define SET_CONFIGURATION 0x11 /* set the operational configuration */ +#define READ_CODE_VERSION 0x15 /* read the code version */ +#define SET_INTERRUPT_TRIGGERS 0x20 /* set the interrupt triggers */ +#define READ_INTERRUPT_TRIGGERS 0x21 /* read the interrupt trigger configuration */ +//#define READ_ADAPTER_CONFIGURATION 0xA0 /* find out what type of adapter is being used */ + + + +/* return code from BSC streaming commands */ +#define COMMAND_SUCCESSFULL 0x00 /* the command was successfull */ +#define COMMUNICATIONS_DISABLED 0x01 /* communications are currently disabled */ +#define COMMUNICATIONS_ENABLED 0x02 /* communications are currently enabled */ +#define SET_CONFIG_BEFORE_ENABLE_COMMS 0x03 /* SET_CONFIGURATION before ENABLE_COMMUNICATIONS */ +#define SET_CONFIG_BEFORE_INT_TRIGGERS 0x03 /* SET_CONFIGURATION before SET_INTERRUPT_TRIGGERS */ +#define INVALID_CONFIGURATION_DATA 0x03 /* the passed configuration data is invalid */ +#define INVALID_TX_DATA_LGTH 0x03 /* the length of the data to be transmitted is invalid */ +#define CANT_FLUSH_BUSY_SENDING 0x03 /* the BSC buffers cannot be flushed as a block is being transmitted */ +#define TX_BUFFERS_FULL 0x04 /* the transmit buffers are full */ +#define INVALID_INTERRUPT_TIMER 0x04 /* the interrupt timer interval value is invalid */ +#define ILLEGAL_COMMAND 0x05 /* the defined HDLC command is invalid */ +#define MODEM_STATUS_CHANGE 0x10 /* a modem (DCD/CTS) status change ocurred */ + + + +/* mailbox definitions */ +/* +The two mailboxes take up a total of 8192 bytes, so each is 4096 bytes in size. However, we reserve the last 16 bytes +in the receive mailbox for miscellaneous interface bytes, so each mailbox is now 4080 bytes. If we subtract 16 bytes +for the mailbox header area, we are left with a mailbox data size of 4064 bytes. +*/ +#define SIZEOF_MB_DATA_BFR 4064 + +/* the mailbox structure */ +typedef struct { + unsigned char opp_flag; /* the opp flag */ + unsigned char command; /* the user command */ + unsigned short buffer_length; /* the data length */ + unsigned char return_code; /* the return code */ + unsigned char misc_Tx_Rx_bits; /* miscellaneous transmit and receive bits */ + unsigned char Rx_error_bits; /* an indication of a block received with an error */ + unsigned short Rx_time_stamp; /* a millisecond receive time stamp */ + unsigned char reserved[7]; /* reserved for later use */ + char data[SIZEOF_MB_DATA_BFR]; /* the data area */ +} MAILBOX_STRUCT; + + +#define MBOX_HEADER_SZ 16 + + +/* definitions for setting the configuration */ +#define MAXIMUM_BAUD_RATE 112000 /* the maximum permitted baud rate */ +#define MIN_BLOCK_LENGTH 2 /* the minimum permitted block length */ +#define MAX_BLOCK_LENGTH 2200 /* the maximum permitted block length */ +#define MIN_NO_CONSEC_PADs_EOB 1 /* the minimum number of consecutive PADs defining the end-of-block */ +#define MAX_NO_CONSEC_PADs_EOB 50 /* the maximum number of consecutive PADs defining the end-of-block */ +#define MIN_ADD_LEAD_TX_SYN_CHARS 0 /* the minimum number of additional leading SYN characters */ +#define MAX_ADD_LEAD_TX_SYN_CHARS 50 /* the maximum number of additional leading SYN characters */ +#define MIN_NO_BITS_PER_CHAR 8 /* the minimum number of bits per character */ +#define MAX_NO_BITS_PER_CHAR 8 /* the maximum number of bits per character */ + +/* definitions for the 'Rx_block_type' */ +#define RX_BLOCK_TYPE_1 1 +#define RX_BLOCK_TYPE_2 2 +#define RX_BLOCK_TYPE_3 3 + +/* definitions for 'parity' */ +#define NO_PARITY 0 /* no parity */ +#define ODD_PARITY 1 /* odd parity */ +#define EVEN_PARITY 2 /* even parity */ + +/* definitions for the 'statistics_options' */ +#define RX_STATISTICS 0x0001 /* enable receiver statistics */ +#define RX_TIME_STAMP 0x0002 /* enable the receive time stamp */ +#define TX_STATISTICS 0x0100 /* enable transmitter statistics */ + +/* definitions for the 'misc_config_options' */ +#define STRIP_PARITY_BIT_FROM_DATA 0x0001 /* strip the parity bit from the data for block types 1 & 3 */ + +/* definitions for the 'modem_config_options' */ +#define DONT_RAISE_DTR_RTS_EN_COMMS 0x0001 /* don't raise DTR and RTS when enabling communications */ + +/* the configuration structure */ +typedef struct { + unsigned long baud_rate; /* the baud rate */ + unsigned long adapter_frequency; /* the adapter frequecy */ + unsigned short max_data_length; /* the maximum length of a BSC data block */ + unsigned short EBCDIC_encoding; /* EBCDIC/ASCII encoding */ + unsigned short Rx_block_type; /* the type of BSC block to be received */ + unsigned short no_consec_PADs_EOB; /* the number of consecutive PADs indicating the end of the block */ + unsigned short no_add_lead_Tx_SYN_chars; /* the number of additional leading transmit SYN characters */ + unsigned short no_bits_per_char; /* the number of bits per character */ + unsigned short parity; /* parity */ + unsigned short misc_config_options; /* miscellaneous configuration options */ + unsigned short statistics_options; /* statistic options */ + unsigned short modem_config_options; /* modem configuration options */ +} CONFIGURATION_STRUCT; + + + +/* definitions for reading the communications errors */ +/* the communications error structure */ +typedef struct { + unsigned short Rx_overrun_err_count; /* the number of receiver overrun errors */ + unsigned short BCC_err_count; /* the number of receiver BCC errors */ + unsigned short nxt_Rx_bfr_occupied_count; /* the number of times a block had to be discarded due to buffering */ + /* limitations */ + unsigned short Rx_too_long_int_lvl_count; /* the number of blocks received which exceeded the maximum permitted */ + /* block size (interrupt level) */ + unsigned short Rx_too_long_app_lvl_count; /* the number of blocks received which exceeded the configured maximum */ + /* block size (application level) */ + unsigned short Rx_invalid_block_count; /* the number of invalid blocks received */ + unsigned short Tx_underrun_count; /* the number of transmit underruns */ + unsigned short comms_err_res_Tx; /* reserved (later use) for a transmit statistic */ + unsigned short DCD_state_change_count; /* the number of times DCD changed state */ + unsigned short CTS_state_change_count; /* the number of times CTS changed state */ +} COMMUNICATIONS_ERROR_STRUCT; + + + +/* definitions for reading the operational statistics */ +/* the operational statistics structure */ +typedef struct { + unsigned long no_blocks_Rx; /* the number of data blocks received and made available for the application */ + unsigned long no_bytes_Rx; /* the number of bytes received and made available for the application */ + unsigned long no_blocks_Tx; /* the number of data blocks transmitted */ + unsigned long no_bytes_Tx; /* the number of bytes transmitted */ +} OPERATIONAL_STATS_STRUCT; + + + +/* definitions for interrupt usage */ +/* 'interrupt_triggers' bit mapping set by a SET_INTERRUPT_TRIGGERS command */ +#define INTERRUPT_ON_RX_BLOCK 0x01 /* interrupt when an data block is available for the application */ +#define INTERRUPT_ON_TIMER 0x20 /* interrupt at a defined millisecond interval */ + +/* interrupt types indicated at 'ptr_interrupt_interface_byte' */ +#define RX_INTERRUPT_PENDING 0x01 /* a receive interrupt is pending */ +#define TIMER_INTERRUPT_PENDING 0x20 /* a timer interrupt is pending */ + +#define MAX_INTERRUPT_TIMER_VALUE 60000 /* the maximum permitted interrupt timer value */ + + +/* definitions for data block transmission */ +/* the setting of the 'misc_Tx_Rx_bits' in the mailbox */ +#define TX_BLK_TRANSPARENT 0x01 /* send a transparent text block */ +#define ETB_DEFINES_EOB 0x02 /* an ETB character defines the end of this text block */ +#define ITB_DEFINES_EOB 0x04 /* an ITB character defines the end of this text block */ +#define USR_DEFINES_TX_DATA 0x10 /* the user application defines the data to be transmitted */ + + + +/* definitions for the 'Rx_error_bits' in the RECEIVE mailbox */ +#define RX_BCC_ERROR 0x01 /* a receive BCC error occurred */ +#define RX_OVERRUN_ERROR 0x02 /* a receive overrun error occurred */ +#define RX_INVALID_BLOCK 0x04 /* an invalid block was received */ +#define RX_EXCESSIVE_LGTH_ERR_INT_LVL 0x10 /* the received block was too long (interrupt level) */ +#define RX_EXCESSIVE_LGTH_ERR_APP_LVL 0x20 /* the received block was too long (application level) */ + +typedef struct { + unsigned char station PACKED; + unsigned short time_stamp PACKED; + unsigned char reserved[13] PACKED; +} api_rx_hdr_t; + +typedef struct { + api_rx_hdr_t api_rx_hdr PACKED; + unsigned char data[1] PACKED; +} api_rx_element_t; + +typedef struct { + unsigned char station PACKED; + unsigned char misc_tx_rx_bits PACKED; + unsigned char reserved[14] PACKED; +} api_tx_hdr_t; + +typedef struct { + api_tx_hdr_t api_tx_hdr PACKED; + unsigned char data[1] PACKED; +} api_tx_element_t; + +#pragma pack() + +#define SIOC_WANPIPE_EXEC_CMD SIOC_WANPIPE_DEVPRIVATE + +#endif diff -Nur linux.org/include/linux/sdla_bstrm.h linux-2.6.17/include/linux/sdla_bstrm.h --- linux.org/include/linux/sdla_bstrm.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/sdla_bstrm.h 2006-08-30 10:07:15.000000000 +0000 @@ -0,0 +1,217 @@ +/***************************************************************************** +* bsc_api.h Bisync Streaming API header file. +* +* Author: Jaspreet Singh +* +* Copyright: (c) 1998-1997 Sangoma Technologies Inc. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version +* 2 of the License, or (at your option) any later version. +* ============================================================================ +* Sep 24, 1998 Jaspreet Singh o Initial Version. +*****************************************************************************/ + +#ifdef _GNUC_ +# ifndef PACKED +# define PACKED __attribute__((packed)) +# endif /* PACKED */ +#else +# define PACKED +#endif +#ifdef _MSC_ +# pragma pack(1) +#endif + +/* Status flag for determining whether to perform a check on socket receive + * queue. + */ +#define NO_SK_RX_CHECK 0x00 +#define TOP_CHECK_SK_RX_Q 0x01 +#define BTM_CHECK_SK_RX_Q 0x02 + +#define NO_READ_CMD 0x00 +#define READ_CMD 0x01 + +/* physical addresses on the adapter + */ +#define SEND_MB_OFF 0x0000 /* base addr of the SEND mb area */ +#define RECEIVE_MB_OFF 0x1000 /* base addr of the RECEIVE mb area */ +#define INTERRUPT_REPORT_IB_OFF 0x1FF0 /* a ptr to the interrupt reporting interface byte */ +#define INTERRUPT_PERMIT_IB_OFF 0x1FF1 /* a pointer to the interrupt permission interface byte */ +#define PTR_MODEM_STATUS_IB 0xFFF4 /* a pointer to the modem status interface byte */ + + +/* BSC streaming commands */ +#define BSC_WRITE 0x01 /* transmit a BSC block */ +#define BSC_READ 0x90 +#define ENABLE_COMMUNICATIONS 0x02 /* enable communications */ +#define DISABLE_COMMUNICATIONS 0x03 /* disable communications */ +#define READ_OPERATIONAL_STATS 0x07 /* retrieve the operational statistics */ +#define FLUSH_OPERATIONAL_STATS 0x08 /* flush the operational statistics */ +#define READ_COMMS_ERR_STATS 0x09 /* read the communication error statistics */ +#define FLUSH_COMMS_ERR_STATS 0x0A /* flush the communication error statistics */ +#define SET_MODEM_STATUS 0x0B /* set the modem status */ +#define READ_MODEM_STATUS 0x0C /* read the current modem status (CTS and DCD status) */ +#define FLUSH_BSC_BUFFERS 0x0D /* flush any queued transmit and receive buffers */ +#define READ_CONFIGURATION 0x10 /* read the current operational configuration */ +#define SET_CONFIGURATION 0x11 /* set the operational configuration */ +#define READ_CODE_VERSION 0x15 /* read the code version */ +#define SET_INTERRUPT_TRIGGERS 0x20 /* set the interrupt triggers */ +#define READ_INTERRUPT_TRIGGERS 0x21 /* read the interrupt trigger configuration */ +#define READ_ADAPTER_CONFIGURATION 0xA0 /* find out what type of adapter is being used */ + + + +/* return code from BSC streaming commands */ +#define COMMAND_SUCCESSFULL 0x00 /* the command was successfull */ +#define COMMUNICATIONS_DISABLED 0x01 /* communications are currently disabled */ +#define COMMUNICATIONS_ENABLED 0x02 /* communications are currently enabled */ +#define SET_CONFIG_BEFORE_ENABLE_COMMS 0x03 /* SET_CONFIGURATION before ENABLE_COMMUNICATIONS */ +#define INVALID_CONFIGURATION_DATA 0x03 /* the passed configuration data is invalid */ +#define INVALID_TX_DATA_LGTH 0x03 /* the length of the data to be transmitted is invalid */ +#define CANT_FLUSH_BUSY_SENDING 0x03 /* the BSC buffers cannot be flushed as a block is being transmitted */ +#define TX_BUFFERS_FULL 0x04 /* the transmit buffers are full */ +#define ILLEGAL_COMMAND 0x05 /* the defined HDLC command is invalid */ +#define MODEM_STATUS_CHANGE 0x10 /* a modem (DCD/CTS) status change ocurred */ +#define NO_DATA_AVAILABLE 0x20 + +/* mailbox definitions */ +/* +The two mailboxes take up a total of 8192 bytes, so each is 4096 bytes in size. However, we reserve the last 16 bytes +in the receive mailbox for miscellaneous interface bytes, so each mailbox is now 4080 bytes. If we subtract 16 bytes +for the mailbox header area, we are left with a mailbox data size of 4064 bytes. +*/ +#define SIZEOF_MB_DATA_BFR 4064 +#define MAILBOX_SIZE 20 + +/* the mailbox structure */ +typedef struct { + unsigned char opp_flag PACKED; /* the opp flag */ + unsigned char command PACKED; /* the user command */ + unsigned short buffer_length PACKED; /* the data length */ + unsigned char return_code PACKED; /* the return code */ + unsigned char misc_Tx_Rx_bits PACKED; /* miscellaneous transmit and receive bits */ + unsigned char Rx_error_bits PACKED; /* an indication of a block received with an error */ + unsigned short Rx_time_stamp PACKED; /* a millisecond receive time stamp */ + unsigned char reserved[7] PACKED; /* reserved for later use */ + char data[SIZEOF_MB_DATA_BFR] PACKED; /* the data area */ +} MAILBOX_STRUCT; + +typedef struct { + pid_t pid_num PACKED; + MAILBOX_STRUCT cmdarea PACKED; +} CMDBLOCK_STRUCT; + +/* definitions for setting the configuration */ +#define MAXIMUM_BAUD_RATE 112000 /* the maximum permitted baud rate */ +#define MIN_BLOCK_LENGTH 2 /* the minimum permitted block length */ +#define MAX_BLOCK_LENGTH 2200 /* the maximum permitted block length */ +#define MIN_NO_CONSEC_PADs_EOB 1 /* the minimum number of consecutive PADs defining the end-of-block */ +#define MAX_NO_CONSEC_PADs_EOB 50 /* the maximum number of consecutive PADs defining the end-of-block */ +#define MIN_ADD_LEAD_TX_SYN_CHARS 0 /* the minimum number of additional leading SYN characters */ +#define MAX_ADD_LEAD_TX_SYN_CHARS 50 /* the maximum number of additional leading SYN characters */ +#define MIN_NO_BITS_PER_CHAR 8 /* the minimum number of bits per character */ +#define MAX_NO_BITS_PER_CHAR 8 /* the maximum number of bits per character */ + +/* definitions for the 'Rx_block_type' */ +#define RX_BLOCK_TYPE_1 1 +#define RX_BLOCK_TYPE_2 2 +#define RX_BLOCK_TYPE_3 3 + +/* definitions for 'parity' */ +#define NO_PARITY 0 /* no parity */ +#define ODD_PARITY 1 /* odd parity */ +#define EVEN_PARITY 2 /* even parity */ + +/* definitions for the 'statistics_options' */ +#define RX_STATISTICS 0x0001 /* enable receiver statistics */ +#define RX_TIME_STAMP 0x0002 /* enable the receive time stamp */ +#define TX_STATISTICS 0x0100 /* enable transmitter statistics */ + +/* definitions for the 'misc_config_options' */ +#define STRIP_PARITY_BIT_FROM_DATA 0x0001 /* strip the parity bit from the data for block types 1 & 3 */ + +/* definitions for the 'modem_config_options' */ +#define DONT_RAISE_DTR_RTS_EN_COMMS 0x0001 /* don't raise DTR and RTS when enabling communications */ + +/* the configuration structure */ +typedef struct { + unsigned long baud_rate PACKED; /* the baud rate */ + unsigned long adapter_frequency PACKED; /* the adapter frequecy */ + unsigned short max_data_length PACKED; /* the maximum length of a BSC data block */ + unsigned short EBCDIC_encoding PACKED; /* EBCDIC/ASCII encoding */ + unsigned short Rx_block_type PACKED; /* the type of BSC block to be received */ + unsigned short no_consec_PADs_EOB PACKED; /* the number of consecutive PADs indicating the end of the block */ + unsigned short no_add_lead_Tx_SYN_chars PACKED; /* the number of additional leading transmit SYN characters */ + unsigned short no_bits_per_char PACKED; /* the number of bits per character */ + unsigned short parity PACKED; /* parity */ + unsigned short misc_config_options PACKED; /* miscellaneous configuration options */ + unsigned short statistics_options PACKED; /* statistic options */ + unsigned short modem_config_options PACKED; /* modem configuration options */ +} CONFIGURATION_STRUCT; + + + +/* definitions for reading the communications errors */ +/* the communications error structure */ +typedef struct { + unsigned short Rx_overrun_err_count; /* the number of receiver overrun errors */ + unsigned short BCC_err_count; /* the number of receiver BCC errors */ + unsigned short nxt_Rx_bfr_occupied_count; /* the number of times a block had to be discarded due to buffering */ + /* limitations */ + unsigned short Rx_too_long_int_lvl_count; /* the number of blocks received which exceeded the maximum permitted */ + /* block size (interrupt level) */ + unsigned short Rx_too_long_app_lvl_count; /* the number of blocks received which exceeded the configured maximum */ + /* block size (application level) */ + unsigned short comms_err_res_Rx; /* reserved (later use) for a receive statistic */ + unsigned short Tx_underrun_count; /* the number of transmit underruns */ + unsigned short comms_err_res_Tx; /* reserved (later use) for a transmit statistic */ + unsigned short DCD_state_change_count; /* the number of times DCD changed state */ + unsigned short CTS_state_change_count; /* the number of times CTS changed state */ +} COMMUNICATIONS_ERROR_STRUCT; + + + +/* definitions for reading the operational statistics */ +/* the operational statistics structure */ +typedef struct { + unsigned long no_blocks_Rx PACKED; /* the number of data blocks received and made available for the application */ + unsigned long no_bytes_Rx PACKED; /* the number of bytes received and made available for the application */ + unsigned long no_blocks_Tx PACKED; /* the number of data blocks transmitted */ + unsigned long no_bytes_Tx PACKED; /* the number of bytes transmitted */ +} OPERATIONAL_STATS_STRUCT; + + + +/* definitions for interrupt usage */ +/* 'interrupt_triggers' bit mapping set by a SET_INTERRUPT_TRIGGERS command */ +#define INTERRUPT_ON_RX_BLOCK 0x01 /* interrupt when an data block is + available for the application */ +#define NO_INTERRUPTS 0x00 +#define INTERRUPT_ON_TIMER 0x20 + +/* interrupt types indicated at 'ptr_interrupt_interface_byte' */ +#define RX_INTERRUPT_PENDING 0x01 /* a receive interrupt is pending */ + +typedef struct { + char int_type; + char int_allowed; +} BSC_INT_BYTES; + + +/* definitions for data block transmission */ +/* the setting of the 'misc_Tx_Rx_bits' in the mailbox */ +#define TX_BLK_TRANSPARENT 0x01 /* send a transparent text block */ +#define ETB_DEFINES_EOB 0x02 /* an ETB character defines the end of this text block */ +#define ITB_DEFINES_EOB 0x04 /* an ITB character defines the end of this text block */ +#define USR_DEFINES_TX_DATA 0x10 /* the user application defines the data to be transmitted */ + + + +/* definitions for the 'Rx_error_bits' in the RECEIVE mailbox */ +#define RX_BCC_ERROR 0x01 /* a receive BCC error occurred */ +#define RX_OVERRUN_ERROR 0x02 /* a receive overrun error occurred */ +#define RX_EXCESSIVE_LGTH_ERR_INT_LVL 0x10 /* the received block was too long (interrupt level) */ +#define RX_EXCESSIVE_LGTH_ERR_APP_LVL 0x20 /* the received block was too long (application level) */ diff -Nur linux.org/include/linux/sdla_chdlc.h linux-2.6.17/include/linux/sdla_chdlc.h --- linux.org/include/linux/sdla_chdlc.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/sdla_chdlc.h 2006-08-30 10:07:15.000000000 +0000 @@ -0,0 +1,823 @@ +/************************************************************************* + sdla_chdlc.h Sangoma Cisco HDLC firmware API definitions + + Author: Gideon Hack + Nenad Corbic + + Copyright: (c) 1995-2000 Sangoma Technologies Inc. + + This program is free software; you can redistribute it and/or + modify it under the term of the GNU General Public License + as published by the Free Software Foundation; either version + 2 of the License, or (at your option) any later version. + +=========================================================================== + Oct 04, 1999 Nenad Corbic Updated API support + Jun 02, 1999 Gideon Hack Changes for S514 usage. + Oct 28, 1998 Jaspreet Singh Made changes for Dual Port CHDLC. + Jun 11, 1998 David Fong Initial version. +=========================================================================== + + Organization + - Compatibility notes + - Constants defining the shared memory control block (mailbox) + - Interface commands + - Return code from interface commands + - Constants for the commands (structures for casting data) + - UDP Management constants and structures + +*************************************************************************/ + +#ifndef _SDLA_CHDLC_H +#define _SDLA_CHDLC_H + +#if defined(__LINUX__) +# include +#else +# include +#endif + +/*------------------------------------------------------------------------ + Notes: + + All structres defined in this file are byte-aligned. + + Compiler Platform + ------------------------ + GNU C Linux + +------------------------------------------------------------------------*/ + +#ifndef PACKED +#define PACKED __attribute__((packed)) +#endif /* PACKED */ + + +#pragma pack(1) + +/* ---------------------------------------------------------------------------- + * Constants defining the shared memory control block (mailbox) + * --------------------------------------------------------------------------*/ + +#define PRI_BASE_ADDR_MB_STRUCT 0xE000 /* the base address of the mailbox structure on the adapter */ +#define SEC_BASE_ADDR_MB_STRUCT 0xE800 /* the base address of the mailbox structure on the adapter */ +#define SIZEOF_MB_DATA_BFR 2032 /* the size of the actual mailbox data area */ +#define NUMBER_MB_RESERVED_BYTES 0x0B /* the number of reserved bytes in the mailbox header area */ + + +#define MIN_LGTH_CHDLC_DATA_CFG 300 /* min length of the CHDLC data field (for configuration purposes) */ +#define PRI_MAX_NO_DATA_BYTES_IN_FRAME 15354 /* PRIMARY - max length of the CHDLC data field */ + +#if 0 +typedef struct { + unsigned char opp_flag PACKED; /* the opp flag */ + unsigned char command PACKED; /* the user command */ + unsigned short buffer_length PACKED; /* the data length */ + unsigned char return_code PACKED; /* the return code */ + unsigned char MB_reserved[NUMBER_MB_RESERVED_BYTES] PACKED; /* reserved for later */ + unsigned char data[SIZEOF_MB_DATA_BFR] PACKED; /* the data area */ +} CHDLC_MAILBOX_STRUCT; +#endif + + +/* ---------------------------------------------------------------------------- + * Interface commands + * --------------------------------------------------------------------------*/ + +/* global interface commands */ +#define READ_GLOBAL_EXCEPTION_CONDITION 0x01 +#define SET_GLOBAL_CONFIGURATION 0x02 +/*#define READ_GLOBAL_CONFIGURATION 0x03*/ +#define READ_GLOBAL_STATISTICS 0x04 +#define FLUSH_GLOBAL_STATISTICS 0x05 +#define SET_MODEM_STATUS 0x06 /* set status of DTR or RTS */ +#define READ_MODEM_STATUS 0x07 /* read status of CTS and DCD */ +#define READ_COMMS_ERROR_STATS 0x08 +#define FLUSH_COMMS_ERROR_STATS 0x09 +#define SET_TRACE_CONFIGURATION 0x0A /* set the line trace config */ +#define READ_TRACE_CONFIGURATION 0x0B /* read the line trace config */ +#define READ_TRACE_STATISTICS 0x0C /* read the trace statistics */ +#define FLUSH_TRACE_STATISTICS 0x0D /* flush the trace statistics */ +#define FT1_MONITOR_STATUS_CTRL 0x1C /* set the status of the S508/FT1 monitoring */ +#define SET_FT1_CONFIGURATION 0x18 /* set the FT1 configuration */ +#define READ_FT1_CONFIGURATION 0x19 /* read the FT1 configuration */ +#define TRANSMIT_ASYNC_DATA_TO_FT1 0x1A /* output asynchronous data to the FT1 */ +#define RECEIVE_ASYNC_DATA_FROM_FT1 0x1B /* receive asynchronous data from the FT1 */ +#define FT1_MONITOR_STATUS_CTRL 0x1C /* set the status of the FT1 monitoring */ + +#define READ_FT1_OPERATIONAL_STATS 0x1D /* read the S508/FT1 operational statistics */ +#define SET_FT1_MODE 0x1E /* set the operational mode of the S508/FT1 module */ + +/* CHDLC-level interface commands */ +/*#define READ_CHDLC_CODE_VERSION 0x20*/ +#define READ_CHDLC_EXCEPTION_CONDITION 0x21 /* read exception condition from the adapter */ +#define SET_CHDLC_CONFIGURATION 0x22 +/*#define READ_CHDLC_CONFIGURATION 0x23*/ +#define ENABLE_CHDLC_COMMUNICATIONS 0x24 +#define DISABLE_CHDLC_COMMUNICATIONS 0x25 +#define READ_CHDLC_LINK_STATUS 0x26 + +#define SET_MISC_TX_RX_PARAMETERS 0x29 +/* set miscellaneous Tx/Rx parameters */ +#define START_BAUD_CALIBRATION 0x2A +/* calibrate an external clock */ +#define READ_BAUD_CALIBRATION_RESULT 0x2B + +#define RESET_ESCC 0x2C +/* read the result of a baud rate calibration */ + +#define SET_CHDLC_INTERRUPT_TRIGGERS 0x30 +/* set application interrupt triggers */ +#define READ_CHDLC_INTERRUPT_TRIGGERS 0x31 +/* read application interrupt trigger configuration */ + +/* Special UDP drivers management commands */ +#define CPIPE_ENABLE_TRACING 0x50 +#define CPIPE_DISABLE_TRACING 0x51 +#define CPIPE_GET_TRACE_INFO 0x52 +#define CPIPE_GET_IBA_DATA 0x53 +#define CPIPE_FT1_READ_STATUS 0x54 +#define CPIPE_DRIVER_STAT_IFSEND 0x55 +#define CPIPE_DRIVER_STAT_INTR 0x56 +#define CPIPE_DRIVER_STAT_GEN 0x57 +#define CPIPE_FLUSH_DRIVER_STATS 0x58 +#define CPIPE_ROUTER_UP_TIME 0x59 + +#if 0 +#define CPIPE_MPPP_TRACE_ENABLE 0x60 +#define CPIPE_MPPP_TRACE_DISABLE 0x61 +#define CPIPE_TE1_56K_STAT 0x62 /* TE1_56K */ +#define CPIPE_GET_MEDIA_TYPE 0x63 /* TE1_56K */ +#define CPIPE_FLUSH_TE1_PMON 0x64 /* TE1 */ +#define CPIPE_READ_REGISTER 0x65 /* TE1_56K */ +#define CPIPE_TE1_CFG 0x66 /* TE1 */ +#endif + +/* Driver specific commands for API */ +#define CHDLC_READ_TRACE_DATA 0xE4 /* read trace data */ +#define TRACE_ALL 0x00 +#define TRACE_PROT 0x01 +#define TRACE_DATA 0x02 + +#define DISCARD_RX_ERROR_FRAMES 0x0001 + +/* ---------------------------------------------------------------------------- + * Return codes from interface commands + * --------------------------------------------------------------------------*/ + +#define COMMAND_OK 0x00 + +/* return codes from global interface commands */ +#define NO_GLOBAL_EXCEP_COND_TO_REPORT 0x01 /* there is no CHDLC exception condition to report */ +#define LGTH_GLOBAL_CFG_DATA_INVALID 0x01 /* the length of the passed global configuration data is invalid */ +#define LGTH_TRACE_CFG_DATA_INVALID 0x01 /* the length of the passed trace configuration data is invalid */ +#define IRQ_TIMEOUT_VALUE_INVALID 0x02 /* an invalid application IRQ timeout value was selected */ +#define TRACE_CONFIG_INVALID 0x02 /* the passed line trace configuration is invalid */ +#define ADAPTER_OPERATING_FREQ_INVALID 0x03 /* an invalid adapter operating frequency was selected */ +#define TRC_DEAC_TMR_INVALID 0x03 /* the trace deactivation timer is invalid */ +#define S508_FT1_ADPTR_NOT_PRESENT 0x0C /* the S508/FT1 adapter is not present */ +#define INVALID_FT1_STATUS_SELECTION 0x0D /* the S508/FT1 status selection is invalid */ +#define FT1_OP_STATS_NOT_ENABLED 0x0D /* the FT1 operational statistics have not been enabled */ +#define FT1_OP_STATS_NOT_AVAILABLE 0x0E /* the FT1 operational statistics are not currently available */ +#define S508_FT1_MODE_SELECTION_BUSY 0x0E /* the S508/FT1 adapter is busy selecting the operational mode */ + +/* return codes from command READ_GLOBAL_EXCEPTION_CONDITION */ +#define EXCEP_MODEM_STATUS_CHANGE 0x10 /* a modem status change occurred */ +#define EXCEP_TRC_DISABLED 0x11 /* the trace has been disabled */ +#define EXCEP_IRQ_TIMEOUT 0x12 /* IRQ timeout */ +#define EXCEP_CSU_DSU_STATE_CHANGE 0x16 + +/* return codes from CHDLC-level interface commands */ +#define NO_CHDLC_EXCEP_COND_TO_REPORT 0x21 /* there is no CHDLC exception condition to report */ +#define CHDLC_COMMS_DISABLED 0x21 /* communications are not currently enabled */ +#define CHDLC_COMMS_ENABLED 0x21 /* communications are currently enabled */ +#define DISABLE_CHDLC_COMMS_BEFORE_CFG 0x21 /* CHDLC communications must be disabled before setting the configuration */ +#define ENABLE_CHDLC_COMMS_BEFORE_CONN 0x21 /* communications must be enabled before using the CHDLC_CONNECT conmmand */ +#define CHDLC_CFG_BEFORE_COMMS_ENABLED 0x22 /* perform a SET_CHDLC_CONFIGURATION before enabling comms */ +#define LGTH_CHDLC_CFG_DATA_INVALID 0x22 /* the length of the passed CHDLC configuration data is invalid */ +#define LGTH_INT_TRIGGERS_DATA_INVALID 0x22 /* the length of the passed interrupt trigger data is invalid */ +#define INVALID_IRQ_SELECTED 0x23 /* in invalid IRQ was selected in the SET_CHDLC_INTERRUPT_TRIGGERS */ +#define INVALID_CHDLC_CFG_DATA 0x23 /* the passed CHDLC configuration data is invalid */ +#define IRQ_TMR_VALUE_INVALID 0x24 /* an invalid application IRQ timer value was selected */ +#define LARGER_PERCENT_TX_BFR_REQUIRED 0x24 /* a larger Tx buffer percentage is required */ +#define LARGER_PERCENT_RX_BFR_REQUIRED 0x25 /* a larger Rx buffer percentage is required */ +#define S514_BOTH_PORTS_SAME_CLK_MODE 0x26 /* S514 - both ports must have same clock mode */ +#define BAUD_CALIBRATION_NOT_DONE 0x29 /* a baud rate calibration has not been performed */ +#define BUSY_WITH_BAUD_CALIBRATION 0x2A /* adapter busy with a baud rate calibration */ +#define BAUD_CAL_FAILED_NO_TX_CLK 0x2B /* baud rate calibration failed (no transmit clock) */ +#define BAUD_CAL_FAILED_BAUD_HI 0x2C /* baud rate calibration failed (baud too high) */ +#define CANNOT_DO_BAUD_CAL 0x2D /* a baud rate calibration cannot be performed */ + +#define INVALID_CMND_HDLC_STREAM_MODE 0x4E /* the CHDLC interface command is invalid for HDLC streaming mode */ +#define INVALID_CHDLC_COMMAND 0x4F /* the defined CHDLC interface command is invalid */ + +/* return codes from command READ_CHDLC_EXCEPTION_CONDITION */ +#define EXCEP_LINK_ACTIVE 0x30 /* the CHDLC link has become active */ +#define EXCEP_LINK_INACTIVE_MODEM 0x31 /* the CHDLC link has become inactive (modem status) */ +#define EXCEP_LINK_INACTIVE_KPALV 0x32 /* the CHDLC link has become inactive (keepalive status) */ +#define EXCEP_IP_ADDRESS_DISCOVERED 0x33 /* the IP address has been discovered */ +#define EXCEP_LOOPBACK_CONDITION 0x34 /* a loopback condition has occurred */ + + +/* return code from command CHDLC_SEND_WAIT and CHDLC_SEND_NO_WAIT */ +#define LINK_DISCONNECTED 0x21 +#define NO_TX_BFRS_AVAIL 0x24 + + +/* ---------------------------------------------------------------------------- + * Constants for the SET_GLOBAL_CONFIGURATION/READ_GLOBAL_CONFIGURATION commands + * --------------------------------------------------------------------------*/ + +/* the global configuration structure */ +typedef struct { + unsigned short adapter_config_options PACKED; /* adapter config options */ + unsigned short app_IRQ_timeout PACKED; /* application IRQ timeout */ + unsigned int adapter_operating_frequency PACKED; /* adapter operating frequency */ + unsigned short frame_transmit_timeout PACKED; +} GLOBAL_CONFIGURATION_STRUCT; + +/* settings for the 'app_IRQ_timeout' */ +#define MAX_APP_IRQ_TIMEOUT_VALUE 5000 /* the maximum permitted IRQ timeout */ + + + +/* ---------------------------------------------------------------------------- + * Constants for the READ_GLOBAL_STATISTICS command + * --------------------------------------------------------------------------*/ + +/* the global statistics structure */ +typedef struct { + unsigned short app_IRQ_timeout_count PACKED; +} GLOBAL_STATS_STRUCT; + + + +/* ---------------------------------------------------------------------------- + * Constants for the READ_COMMS_ERROR_STATS command + * --------------------------------------------------------------------------*/ + +/* the communications error statistics structure */ +typedef struct { + unsigned short Rx_overrun_err_count PACKED; + unsigned short CRC_err_count PACKED; /* receiver CRC error count */ + unsigned short Rx_abort_count PACKED; /* abort frames recvd count */ + unsigned short Rx_dis_pri_bfrs_full_count PACKED;/* receiver disabled */ + unsigned short comms_err_stat_reserved_1 PACKED;/* reserved for later */ + unsigned short sec_Tx_abort_msd_Tx_int_count PACKED; /* secondary - abort frames transmitted count (missed Tx interrupt) */ + unsigned short missed_Tx_und_int_count PACKED; /* missed tx underrun interrupt count */ + unsigned short sec_Tx_abort_count PACKED; /*secondary-abort frames tx count */ + unsigned short DCD_state_change_count PACKED; /* DCD state change */ + unsigned short CTS_state_change_count PACKED; /* CTS state change */ +} COMMS_ERROR_STATS_STRUCT; + + + +/* ---------------------------------------------------------------------------- + * Constants used for line tracing + * --------------------------------------------------------------------------*/ + +/* the trace configuration structure (SET_TRACE_CONFIGURATION/READ_TRACE_CONFIGURATION commands) */ +typedef struct { + unsigned char trace_config PACKED; /* trace configuration */ + unsigned short trace_deactivation_timer PACKED; /* trace deactivation timer */ + unsigned int ptr_trace_stat_el_cfg_struct PACKED; /* a pointer to the line trace element configuration structure */ +} LINE_TRACE_CONFIG_STRUCT; + +/* 'trace_config' bit settings */ +#define TRACE_INACTIVE 0x00 /* trace is inactive */ +#define TRACE_ACTIVE 0x01 /* trace is active */ +#define TRACE_DELAY_MODE 0x04 /* operate the trace in delay mode */ +#define TRACE_DATA_FRAMES 0x08 /* trace Data frames */ +#define TRACE_SLARP_FRAMES 0x10 /* trace SLARP frames */ +#define TRACE_CDP_FRAMES 0x20 /* trace CDP frames */ + +/* the line trace status element configuration structure */ +typedef struct { + unsigned short number_trace_status_elements PACKED; /* number of line trace elements */ + unsigned int base_addr_trace_status_elements PACKED; /* base address of the trace element list */ + unsigned int next_trace_element_to_use PACKED; /* pointer to the next trace element to be used */ + unsigned int base_addr_trace_buffer PACKED; /* base address of the trace data buffer */ + unsigned int end_addr_trace_buffer PACKED; /* end address of the trace data buffer */ +} TRACE_STATUS_EL_CFG_STRUCT; + +/* the line trace status element structure */ +typedef struct { + unsigned char opp_flag PACKED; /* opp flag */ + unsigned short trace_length PACKED; /* trace length */ + unsigned char trace_type PACKED; /* trace type */ + unsigned short trace_time_stamp PACKED; /* time stamp */ + unsigned short trace_reserved_1 PACKED; /* reserved for later use */ + unsigned int trace_reserved_2 PACKED; /* reserved for later use */ + unsigned int ptr_data_bfr PACKED; /* ptr to the trace data buffer */ +} TRACE_STATUS_ELEMENT_STRUCT; + +/* "trace_type" bit settings */ +#define TRACE_INCOMING 0x00 +#define TRACE_OUTGOINGING 0x01 +#define TRACE_INCOMING_ABORTED 0x10 +#define TRACE_INCOMING_CRC_ERROR 0x20 +#define TRACE_INCOMING_OVERRUN_ERROR 0x40 + + + +/* the line trace statistics structure */ +typedef struct { + unsigned int frames_traced_count PACKED; /* number of frames traced */ + unsigned int trc_frms_not_recorded_count PACKED; /* number of trace frames discarded */ +} LINE_TRACE_STATS_STRUCT; + + +/* ---------------------------------------------------------------------------- + * Constants for the FT1_MONITOR_STATUS_CTRL command + * --------------------------------------------------------------------------*/ + +#define DISABLE_FT1_STATUS_STATISTICS 0x00 /* disable the FT1 status and statistics monitoring */ +#define ENABLE_READ_FT1_STATUS 0x01 /* read the FT1 operational status */ +#define ENABLE_READ_FT1_OP_STATS 0x02 /* read the FT1 operational statistics */ +#define FLUSH_FT1_OP_STATS 0x04 /* flush the FT1 operational statistics */ + + + + +/* ---------------------------------------------------------------------------- + * Constants for the SET_CHDLC_CONFIGURATION command + * --------------------------------------------------------------------------*/ + +/* the CHDLC configuration structure */ +typedef struct { + unsigned int baud_rate PACKED; /* the baud rate */ + unsigned short line_config_options PACKED; /* line configuration options */ + unsigned short modem_config_options PACKED; /* modem configration options */ + unsigned short modem_status_timer PACKED; /* timer for monitoring modem status changes */ + unsigned short CHDLC_API_options PACKED; /* CHDLC API options */ + unsigned short CHDLC_protocol_options PACKED; /* CHDLC protocol options */ + unsigned short percent_data_buffer_for_Tx PACKED; /* percentage data buffering used for Tx */ + unsigned short CHDLC_statistics_options PACKED; /* CHDLC operational statistics options */ + unsigned short max_CHDLC_data_field_length PACKED; /* the maximum length of the CHDLC Data field */ + unsigned short transmit_keepalive_timer PACKED; /* the transmit keepalive timer */ + unsigned short receive_keepalive_timer PACKED; /* the receive keepalive timer */ + unsigned short keepalive_error_tolerance PACKED; /* the receive keepalive error tolerance */ + unsigned short SLARP_request_timer PACKED; /* the SLARP request timer */ + unsigned int IP_address PACKED; /* the IP address */ + unsigned int IP_netmask PACKED; /* the IP netmask */ + unsigned int ptr_shared_mem_info_struct PACKED; /* a pointer to the shared memory area information structure */ + unsigned int ptr_CHDLC_Tx_stat_el_cfg_struct PACKED; /* a pointer to the transmit status element configuration structure */ + unsigned int ptr_CHDLC_Rx_stat_el_cfg_struct PACKED; /* a pointer to the receive status element configuration structure */ +} CHDLC_CONFIGURATION_STRUCT; + +/* settings for the 'line_config_options' */ +#define INTERFACE_LEVEL_V35 0x0000 +/* V.35 interface level */ + +#define INTERFACE_LEVEL_RS232 0x0001 +/* RS-232 interface level */ + +#define NRZI_ENCODING 0x0010 +/* NRZI data encoding */ + +#define IDLE_MARK 0x0020 +/* idle line condition is mark (not flags) */ + + +/* settings for the 'modem_config_options' */ + +#define DONT_RAISE_DTR_RTS_ON_EN_COMMS 0x0001 +/* don't automatically raise DTR and RTS when performing an + ENABLE_CHDLC_COMMUNICATIONS command */ + +#define DONT_REPORT_CHG_IN_MODEM_STAT 0x0002 +/* don't report changes in modem status to the application */ + +#define SWITCHED_CTS_RTS 0x0010 +/* switched CTS/RTS */ + + +/* bit settings for the 'CHDLC_protocol_options' byte */ + +#define IGNORE_DCD_FOR_LINK_STAT 0x0001 +/* ignore DCD in determining the CHDLC link status */ + +#define IGNORE_CTS_FOR_LINK_STAT 0x0002 +/* ignore CTS in determining the CHDLC link status */ + +#define IGNORE_KPALV_FOR_LINK_STAT 0x0004 +/* ignore keepalive frames in determining the CHDLC link status */ + +#define INSTALL_FAST_INT_HANDLERS 0x1000 +/* install 'fast' interrupt handlers for improved dual-port perf. */ + +#define USE_32_BIT_CRC 0x2000 +/* use a 32-bit CRC */ + +#define SINGLE_TX_BUFFER 0x4000 +/* configure a single transmit buffer */ + +#define HDLC_STREAMING_MODE 0x8000 + +/* settings for the 'CHDLC_statistics_options' */ + +#define CHDLC_TX_DATA_BYTE_COUNT_STAT 0x0001 +/* record the number of Data bytes transmitted */ + +#define CHDLC_RX_DATA_BYTE_COUNT_STAT 0x0002 +/* record the number of Data bytes received */ + +#define CHDLC_TX_THROUGHPUT_STAT 0x0004 +/* compute the Data frame transmit throughput */ + +#define CHDLC_RX_THROUGHPUT_STAT 0x0008 +/* compute the Data frame receive throughput */ + + +/* permitted minimum and maximum values for setting the CHDLC configuration */ +#define PRI_MAX_BAUD_RATE_S508 2666666 /* PRIMARY - maximum baud rate (S508) */ +#define SEC_MAX_BAUD_RATE_S508 258064 /* SECONDARY - maximum baud rate (S508) */ +#define PRI_MAX_BAUD_RATE_S514 2750000 /* PRIMARY - maximum baud rate (S508) */ +#define SEC_MAX_BAUD_RATE_S514 515625 /* SECONDARY - maximum baud rate (S508) */ + +#define MIN_MODEM_TIMER 0 /* minimum modem status timer */ +#define MAX_MODEM_TIMER 5000 /* maximum modem status timer */ + +#define SEC_MAX_NO_DATA_BYTES_IN_FRAME 2048 /* SECONDARY - max length of the CHDLC data field */ + +#define MIN_Tx_KPALV_TIMER 0 /* minimum transmit keepalive timer */ +#define MAX_Tx_KPALV_TIMER 60000 /* maximum transmit keepalive timer */ +#define DEFAULT_Tx_KPALV_TIMER 10000 /* default transmit keepalive timer */ + +#define MIN_Rx_KPALV_TIMER 10 /* minimum receive keepalive timer */ +#define MAX_Rx_KPALV_TIMER 60000 /* maximum receive keepalive timer */ +#define DEFAULT_Rx_KPALV_TIMER 10000 /* default receive keepalive timer */ + +#define MIN_KPALV_ERR_TOL 1 /* min kpalv error tolerance count */ +#define MAX_KPALV_ERR_TOL 20 /* max kpalv error tolerance count */ +#define DEFAULT_KPALV_ERR_TOL 3 /* default value */ + +#define MIN_SLARP_REQ_TIMER 0 /* min transmit SLARP Request timer */ +#define MAX_SLARP_REQ_TIMER 60000 /* max transmit SLARP Request timer */ +#define DEFAULT_SLARP_REQ_TIMER 0 /* default value -- no SLARP */ + + + +/* ---------------------------------------------------------------------------- + * Constants for the READ_CHDLC_LINK_STATUS command + * --------------------------------------------------------------------------*/ + +/* the CHDLC status structure */ +typedef struct { + unsigned char CHDLC_link_status PACKED; /* CHDLC link status */ + unsigned char no_Data_frms_for_app PACKED; /* number of Data frames available for the application */ + unsigned char receiver_status PACKED; /* enabled/disabled */ + unsigned char SLARP_state PACKED; /* internal SLARP state */ +} CHDLC_LINK_STATUS_STRUCT; + +/* settings for the 'CHDLC_link_status' variable */ +#define CHDLC_LINK_INACTIVE 0x00 /* the CHDLC link is inactive */ +#define CHDLC_LINK_ACTIVE 0x01 /* the CHDLC link is active */ + + + +/* ---------------------------------------------------------------------------- + * Constants for using application interrupts + * --------------------------------------------------------------------------*/ + +/* the structure used for the SET_CHDLC_INTERRUPT_TRIGGERS/READ_CHDLC_INTERRUPT_TRIGGERS command */ +typedef struct { + unsigned char CHDLC_interrupt_triggers PACKED; /* CHDLC interrupt trigger configuration */ + unsigned char IRQ PACKED; /* IRQ to be used */ + unsigned short interrupt_timer PACKED; /* interrupt timer */ + unsigned short misc_interrupt_bits PACKED; /* miscellaneous bits */ +} CHDLC_INT_TRIGGERS_STRUCT; + +/* 'CHDLC_interrupt_triggers' bit settings */ +#define APP_INT_ON_RX_FRAME 0x01 /* interrupt on Data frame reception */ +#define APP_INT_ON_TX_FRAME 0x02 /* interrupt when an Data frame may be transmitted */ +#define APP_INT_ON_COMMAND_COMPLETE 0x04 /* interrupt when an interface command is complete */ +#define APP_INT_ON_TIMER 0x08 /* interrupt on a defined millisecond timeout */ +#define APP_INT_ON_GLOBAL_EXCEP_COND 0x10 /* interrupt on a global exception condition */ +#define APP_INT_ON_CHDLC_EXCEP_COND 0x20 /* interrupt on an CHDLC exception condition */ +#define APP_INT_ON_TRACE_DATA_AVAIL 0x80 /* interrupt when trace data is available */ + +/* interrupt types indicated at 'interrupt_type' byte of the INTERRUPT_INFORMATION_STRUCT */ +#define NO_APP_INTS_PEND 0x00 /* no interrups are pending */ +#define RX_APP_INT_PEND 0x01 /* a receive interrupt is pending */ +#define TX_APP_INT_PEND 0x02 /* a transmit interrupt is pending */ +#define COMMAND_COMPLETE_APP_INT_PEND 0x04 /* a 'command complete' interrupt is pending */ +#define TIMER_APP_INT_PEND 0x08 /* a timer interrupt is pending */ +#define GLOBAL_EXCEP_COND_APP_INT_PEND 0x10 /* a global exception condition interrupt is pending */ +#define CHDLC_EXCEP_COND_APP_INT_PEND 0x20 /* an CHDLC exception condition interrupt is pending */ +#define TRACE_DATA_AVAIL_APP_INT_PEND 0x80 /* a trace data available interrupt is pending */ + + +/* modem status changes */ +#define DCD_HIGH 0x08 +#define CTS_HIGH 0x20 + + +/* ---------------------------------------------------------------------------- + * Constants for Data frame transmission + * --------------------------------------------------------------------------*/ + +/* the Data frame transmit status element configuration structure */ +typedef struct { + unsigned short number_Tx_status_elements PACKED; /* number of transmit status elements */ + unsigned int base_addr_Tx_status_elements PACKED; /* base address of the transmit element list */ + unsigned int next_Tx_status_element_to_use PACKED; /* pointer to the next transmit element to be used */ +} CHDLC_TX_STATUS_EL_CFG_STRUCT; + +/* the Data frame transmit status element structure */ +typedef struct { + unsigned char opp_flag PACKED; /* opp flag */ + unsigned short frame_length PACKED; /* length of the frame to be transmitted */ + unsigned char misc_Tx_bits PACKED; /* miscellaneous transmit bits */ + unsigned int reserved_2 PACKED; /* reserved for internal use */ + unsigned int reserved_3 PACKED; /* reserved for internal use */ + unsigned int ptr_data_bfr PACKED; /* pointer to the data area */ +} CHDLC_DATA_TX_STATUS_EL_STRUCT; + + +/* settings for the 'misc_Tx_bits' + * (pertains only to switched CTS/RTS and + * 'idle mark' configurations) */ + +#define DROP_RTS_AFTER_TX 0x01 +/* drop RTS after transmission of this frame */ + +#define IDLE_FLAGS_AFTER_TX 0x02 +/* idle flags after transmission of this frame */ + +/* settings for the 'misc_Tx_bits' for IPv4/IPv6 usage */ +#define TX_DATA_IPv4 0x00 +/* apply the IPv4 CHDLC header to the transmitted Data frame */ +#define TX_DATA_IPv6 0x80 +/* apply the IPv6 CHDLC header to the transmitted Data frame */ + + + + +/* ---------------------------------------------------------------------------- + * Constants for Data frame reception + * --------------------------------------------------------------------------*/ + +/* the Data frame receive status element configuration structure */ +typedef struct { + unsigned short number_Rx_status_elements PACKED; /* number of receive status elements */ + unsigned int base_addr_Rx_status_elements PACKED; /* base address of the receive element list */ + unsigned int next_Rx_status_element_to_use PACKED; /* pointer to the next receive element to be used */ + unsigned int base_addr_Rx_buffer PACKED; /* base address of the receive data buffer */ + unsigned int end_addr_Rx_buffer PACKED; /* end address of the receive data buffer */ +} CHDLC_RX_STATUS_EL_CFG_STRUCT; + +/* the Data frame receive status element structure */ +typedef struct { + unsigned char opp_flag PACKED; /* opp flag */ + unsigned short frame_length PACKED; /* length of the received frame */ + unsigned char error_flag PACKED; /* frame errors (HDLC_STREAMING_MODE)*/ + unsigned short time_stamp PACKED; /* receive time stamp (HDLC_STREAMING_MODE) */ + unsigned int reserved_1 PACKED; /* reserved for internal use */ + unsigned short reserved_2 PACKED; /* reserved for internal use */ + unsigned int ptr_data_bfr PACKED; /* pointer to the data area */ +} CHDLC_DATA_RX_STATUS_EL_STRUCT; + + +/* settings for the 'error_flag' */ +#define RX_FRM_ABORT 0x01 +#define RX_FRM_CRC_ERROR 0x02 +#define RX_FRM_OVERRUN_ERROR 0x04 + +/* settings for the 'error_flag' for IPv4/IPv6 usage */ +#define RX_DATA_IPv4 0x00 +/* the received Data frame is IPv4 */ +#define RX_DATA_IPv6 0x80 +/* the received Data frame is IPv6 */ + + +/* ---------------------------------------------------------------------------- + * Constants defining the shared memory information area + * --------------------------------------------------------------------------*/ + +/* the global information structure */ +typedef struct { + unsigned char global_status PACKED; /* global status */ + unsigned char modem_status PACKED; /* current modem status */ + unsigned char global_excep_conditions PACKED; /* global exception conditions */ + unsigned char glob_info_reserved[5] PACKED; /* reserved */ + unsigned char codename[4] PACKED; /* Firmware name */ + unsigned char codeversion[4] PACKED; /* Firmware version */ +} GLOBAL_INFORMATION_STRUCT; + +/* the CHDLC information structure */ +typedef struct { + unsigned char CHDLC_status PACKED; /* CHDLC status */ + unsigned char CHDLC_excep_conditions PACKED; /* CHDLC exception conditions */ + unsigned char CHDLC_info_reserved[14] PACKED; /* reserved */ +} CHDLC_INFORMATION_STRUCT; + +/* the interrupt information structure */ +typedef struct { + unsigned char interrupt_type PACKED; /* type of interrupt triggered */ + unsigned char interrupt_permission PACKED; /* interrupt permission mask */ + unsigned char int_info_reserved[14] PACKED; /* reserved */ +} INTERRUPT_INFORMATION_STRUCT; + +/* the S508/FT1 information structure */ +typedef struct { + unsigned char parallel_port_A_input PACKED; /* input - parallel port A */ + unsigned char parallel_port_B_input PACKED; /* input - parallel port B */ + unsigned char FT1_info_reserved[14] PACKED; /* reserved */ +} FT1_INFORMATION_STRUCT; + +/* the shared memory area information structure */ +typedef struct { + GLOBAL_INFORMATION_STRUCT global_info_struct PACKED; /* the global information structure */ + CHDLC_INFORMATION_STRUCT CHDLC_info_struct PACKED; /* the CHDLC information structure */ + INTERRUPT_INFORMATION_STRUCT interrupt_info_struct PACKED; /* the interrupt information structure */ + FT1_INFORMATION_STRUCT FT1_info_struct PACKED; /* the S508/FT1 information structure */ +} SHARED_MEMORY_INFO_STRUCT; + +/* ---------------------------------------------------------------------------- + * UDP Management constants and structures + * --------------------------------------------------------------------------*/ + +/* The embedded control block for UDP mgmt + This is essentially a mailbox structure, without the large data field */ + +#ifndef HDLC_PROT_ONLY + +typedef struct { + unsigned char opp_flag PACKED; /* the opp flag */ + unsigned char command PACKED; /* the user command */ + unsigned short buffer_length PACKED; /* the data length */ + unsigned char return_code PACKED; /* the return code */ + unsigned char MB_reserved[NUMBER_MB_RESERVED_BYTES] PACKED; /* reserved for later */ +} cblock_t; + +/* UDP management packet layout (data area of ip packet) */ +/* +typedef struct { + unsigned char signature[8] PACKED; + unsigned char request_reply PACKED; + unsigned char id PACKED; + unsigned char reserved[6] PACKED; + cblock_t cblock PACKED; + unsigned char num_frames PACKED; + unsigned char ismoredata PACKED; + unsigned char data[SIZEOF_MB_DATA_BFR] PACKED; +} udp_management_packet_t; + +*/ + +typedef struct { + unsigned char num_frames PACKED; + unsigned char ismoredata PACKED; +} trace_info_t; + +#if 0 +typedef struct { + ip_pkt_t ip_pkt PACKED; + udp_pkt_t udp_pkt PACKED; + wp_mgmt_t wp_mgmt PACKED; + cblock_t cblock PACKED; + trace_info_t trace_info PACKED; + unsigned char data[SIZEOF_MB_DATA_BFR] PACKED; +} chdlc_udp_pkt_t; +#endif + +typedef struct ft1_exec_cmd{ + unsigned char command PACKED; /* the user command */ + unsigned short buffer_length PACKED; /* the data length */ + unsigned char return_code PACKED; /* the return code */ + unsigned char MB_reserved[NUMBER_MB_RESERVED_BYTES] PACKED; +} ft1_exec_cmd_t; + +typedef struct { + unsigned char opp_flag PACKED; + ft1_exec_cmd_t cmd PACKED; + unsigned char data[SIZEOF_MB_DATA_BFR] PACKED; +} ft1_exec_t; + + +#define UDPMGMT_SIGNATURE "CTPIPEAB" +#define UDPMGMT_SIGNATURE_LEN 8 + + +/* UDP/IP packet (for UDP management) layout */ +/* +typedef struct { + unsigned char reserved[2] PACKED; + unsigned short ip_length PACKED; + unsigned char reserved2[4] PACKED; + unsigned char ip_ttl PACKED; + unsigned char ip_protocol PACKED; + unsigned short ip_checksum PACKED; + unsigned int ip_src_address PACKED; + unsigned int ip_dst_address PACKED; + unsigned short udp_src_port PACKED; + unsigned short udp_dst_port PACKED; + unsigned short udp_length PACKED; + unsigned short udp_checksum PACKED; + udp_management_packet_t um_packet PACKED; +} ip_packet_t; +*/ + +/* valid ip_protocol for UDP management */ +#define UDPMGMT_UDP_PROTOCOL 0x11 + +#if 0 +typedef struct { + unsigned char status PACKED; + unsigned char data_avail PACKED; + unsigned short real_length PACKED; + unsigned short time_stamp PACKED; + unsigned char data[1] PACKED; +} trace_pkt_t; +#endif + +typedef struct { + unsigned char error_flag PACKED; + unsigned short time_stamp PACKED; + unsigned int sec PACKED; + unsigned int usec PACKED; + unsigned char reserved[5] PACKED; +} api_rx_hdr_t; + +typedef struct { + api_rx_hdr_t api_rx_hdr PACKED; + unsigned char data[1] PACKED; +} api_rx_element_t; + +typedef struct { + unsigned char attr PACKED; + unsigned char misc_Tx_bits PACKED; + unsigned char reserved[14] PACKED; +} api_tx_hdr_t; + +typedef struct { + api_tx_hdr_t api_tx_hdr PACKED; + unsigned char data[1] PACKED; +} api_tx_element_t; + +#endif //HDLC_PROT_ONLY +/* ---------------------------------------------------------------------------- + * Constants for the SET_FT1_CONFIGURATION/READ_FT1_CONFIGURATION command + * --------------------------------------------------------------------------*/ + +/* the FT1 configuration structure */ +typedef struct { + unsigned short framing_mode; + unsigned short encoding_mode; + unsigned short line_build_out; + unsigned short channel_base; + unsigned short baud_rate_kbps; /* the baud rate (in kbps) */ + unsigned short clock_mode; +} ft1_config_t; + + + +/* settings for the 'framing_mode' */ +#define ESF_FRAMING 0x00 /* ESF framing */ +#define D4_FRAMING 0x01 /* D4 framing */ + +/* settings for the 'encoding_mode' */ +#define B8ZS_ENCODING 0x00 /* B8ZS encoding */ +#define AMI_ENCODING 0x01 /* AMI encoding */ + +/* settings for the 'line_build_out' */ +#define LN_BLD_CSU_0dB_DSX1_0_to_133 0x00 /* set build out to CSU (0db) or DSX-1 (0-133ft) */ +#define LN_BLD_DSX1_133_to_266 0x01 /* set build out DSX-1 (133-266ft) */ +#define LN_BLD_DSX1_266_to_399 0x02 /* set build out DSX-1 (266-399ft) */ +#define LN_BLD_DSX1_399_to_533 0x03 /* set build out DSX-1 (399-533ft) */ +#define LN_BLD_DSX1_533_to_655 0x04 /* set build out DSX-1 (533-655ft) */ +#define LN_BLD_CSU_NEG_7dB 0x05 /* set build out to CSU (-7.5db) */ +#define LN_BLD_CSU_NEG_15dB 0x06 /* set build out to CSU (-15db) */ +#define LN_BLD_CSU_NEG_22dB 0x07 /* set build out to CSU (-22.5db) */ + +/* settings for the 'channel_base' */ +#define MIN_CHANNEL_BASE_VALUE 1 /* the minimum permitted channel base value */ +#define MAX_CHANNEL_BASE_VALUE 24 /* the maximum permitted channel base value */ + +/* settings for the 'baud_rate_kbps' */ +#define MIN_BAUD_RATE_KBPS 0 /* the minimum permitted baud rate (kbps) */ +#define MAX_BAUD_RATE_KBPS 1536 /* the maximum permitted baud rate (kbps) */ +#define BAUD_RATE_FT1_AUTO_CONFIG 0xFFFF /* the baud rate used to trigger an automatic FT1 configuration */ + +/* settings for the 'clock_mode' */ +#define CLOCK_MODE_NORMAL 0x00 /* clock mode set to normal (slave) */ +#define CLOCK_MODE_MASTER 0x01 /* clock mode set to master */ + + +#define BAUD_RATE_FT1_AUTO_CONFIG 0xFFFF +#define AUTO_FT1_CONFIG_NOT_COMPLETE 0x08 +#define AUTO_FT1_CFG_FAIL_OP_MODE 0x0C +#define AUTO_FT1_CFG_FAIL_INVALID_LINE 0x0D + +#undef wan_udphdr_data +#define wan_udphdr_data wan_udphdr_u.chdlc.data + +#ifdef __KERNEL__ +#undef wan_udp_data +#define wan_udp_data wan_udp_hdr.wan_udphdr_u.chdlc.data +#endif + +#pragma pack() + +#endif /* _SDLA_CHDLC_H */ diff -Nur linux.org/include/linux/sdladrv.h linux-2.6.17/include/linux/sdladrv.h --- linux.org/include/linux/sdladrv.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/sdladrv.h 2006-08-30 10:07:15.000000000 +0000 @@ -0,0 +1,582 @@ +/* + * Copyright (c) 1997, 1998, 1999 + * Alex Feldman . All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Alex Feldman. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Alex Feldman AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Alex Feldman OR THE VOICES IN HIS HEAD + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + * $Id$ + */ + +/***************************************************************************** + * sdladrv.h SDLA Support Module. Kernel API Definitions. + * + * Author: Alex Feldman + * + * ============================================================================ + * Dec 06, 1999 Alex Feldman Updated to FreeBSD 3.2 + * Dec 06, 1995 Gene Kozin Initial version. + ***************************************************************************** + */ +#ifndef _SDLADRV_H +# define _SDLADRV_H + +#ifdef __SDLADRV__ +# define EXTERN +#else +# define EXTERN extern +#endif + +/* +****************************************************************** +** I N C L U D E S ** +****************************************************************** +*/ +#if defined(__LINUX__) +# include +# include +#endif + +/* +****************************************************************** +** D E F I N E S ** +****************************************************************** +*/ +#define SDLADRV_MAGIC 0x414C4453L /* signature: 'SDLA' reversed */ + +#define SDLADRV_MAJOR_VER 2 +#define SDLADRV_MINOR_VER 1 +#define SDLA_MAXIORANGE 4 /* maximum I/O port range */ +#define SDLA_WINDOWSIZE 0x2000 /* default dual-port memory window size */ + +/* */ +#define SDLA_MEMBASE 0x01 +#define SDLA_MEMEND 0x02 +#define SDLA_MEMSIZE 0x03 +#define SDLA_IRQ 0x04 +#define SDLA_ADAPTERTYPE 0x05 +#define SDLA_CPU 0x06 +#define SDLA_SLOT 0x07 +#define SDLA_IOPORT 0x08 +#define SDLA_IORANGE 0x09 +#define SDLA_CARDTYPE 0x0A +#define SDLA_DMATAG 0x0B +#define SDLA_MEMORY 0x0C +#define SDLA_PCIEXTRAVER 0x0D +#define SDLA_HWTYPE 0x0E +#define SDLA_BUS 0x0F +#define SDLA_BASEADDR 0x10 +#define SDLA_COREREV 0x11 +#define SDLA_USEDCNT 0x12 +#define SDLA_ADAPTERSUBTYPE 0x13 +#define SDLA_HWEC_NO 0x14 + + +#define SDLA_MAX_CPUS 2 + + /* Serial card - 2, A104 - 4, A108 - 8 */ +#define SDLA_MAX_PORTS 8 + +/* Status values */ +#define SDLA_MEM_RESERVED 0x0001 +#define SDLA_MEM_MAPPED 0x0002 +#define SDLA_IO_MAPPED 0x0004 +#define SDLA_PCI_ENABLE 0x0008 + +#define SDLA_NAME_SIZE 20 + +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) +# define PCI_DMA_FROMDEVICE 1 +# define PCI_DMA_TODEVICE 2 +#endif +/* +****************************************************************** +** T Y P E D E F S ** +****************************************************************** +*/ +#if defined(__FreeBSD__) +typedef void* sdla_mem_handle_t; +# if (__FreeBSD_version < 400000) +typedef bus_addr_t sdla_base_addr_t; +typedef bus_addr_t sdla_dma_addr_t; +typedef pcici_t sdla_pci_dev_t; +# else +typedef uint32_t sdla_base_addr_t; +typedef uint32_t sdla_dma_addr_t; +typedef struct device* sdla_pci_dev_t; +# endif +#elif defined(__OpenBSD__) +typedef bus_space_handle_t sdla_mem_handle_t; +typedef bus_addr_t sdla_base_addr_t; +typedef bus_addr_t sdla_dma_addr_t; +typedef struct pci_attach_args* sdla_pci_dev_t; +#elif defined(__NetBSD__) +typedef bus_space_handle_t sdla_mem_handle_t; +typedef bus_addr_t sdla_base_addr_t; +typedef bus_addr_t sdla_dma_addr_t; +typedef struct pci_attach_args* sdla_pci_dev_t; +#elif defined(__LINUX__) +#if defined(__iomem) +typedef void __iomem* sdla_mem_handle_t; +#else +typedef void * sdla_mem_handle_t; +#endif +typedef unsigned long sdla_base_addr_t; +typedef dma_addr_t sdla_dma_addr_t; +typedef struct pci_dev* sdla_pci_dev_t; +#else +# warning "Undefined types sdla_mem_handle_t/sdla_base_addr_t!" +#endif + +/* +****************************************************************** +** M A C R O S ** +****************************************************************** +*/ +#if defined(__FreeBSD__) +# define virt_to_phys(x) kvtop((caddr_t)x) +# define phys_to_virt(x) (sdla_mem_handle_t)x +#elif defined(__OpenBSD__) +# define virt_to_phys(x) kvtop((caddr_t)x) +# define phys_to_virt(x) (bus_space_handle_t)x +#elif defined(__NetBSD__) +# define virt_to_phys(x) kvtop((caddr_t)x) +# define phys_to_virt(x) (bus_space_handle_t)x +#elif defined(__LINUX__) +#else +# warning "Undefined virt_to_phys/phys_to_virt macros!" +#endif + +#define IS_SDLA_PCI(hw) (hw->type == SDLA_S514 || hw->type == SDLA_ADSL) +#define IS_SDLA_ISA(hw) (hw->type == SDLA_S508) + +#define WAN_HWCALL(func, x) \ + if (card->hw_iface.func){ \ + card->hw_iface.func x; \ + }else{ \ + DEBUG_EVENT("%s: Unknown hw function pointer (%s:%d)!\n",\ + card->devname, __FUNCTION__,__LINE__); \ + } + +/* +****************************************************************** +** S T R U C T U R E S ** +****************************************************************** +*/ +typedef struct sdla_hw_probe { + int used; + unsigned char hw_info[100]; + WAN_LIST_ENTRY(sdla_hw_probe) next; +} sdla_hw_probe_t; + + +/* + * This structure keeps common parameters per physical card. + */ +typedef struct sdlahw_card { + int used; + unsigned int hw_type; /* ISA/PCI */ + unsigned int type; /* S50x/S514/ADSL/SDLA_AFT */ + unsigned char cfg_type; /* Config card type WANOPT_XXX */ + unsigned int adptr_type; /* Adapter type (subvendor ID) */ + unsigned char adptr_subtype; /* Adapter Subtype (Normal|Shark) */ + unsigned char adptr_name[SDLA_NAME_SIZE]; + unsigned char core_id; /* SubSystem ID [0..7] */ + unsigned char core_rev; /* SubSystem ID [8..15] */ + unsigned char pci_extra_ver; + unsigned int slot_no; + unsigned int bus_no; + unsigned int ioport; +#if defined(__LINUX__) + sdla_pci_dev_t pci_dev; /* PCI config header info */ +#else +#if defined(__NetBSD__) || defined(__OpenBSD__) + bus_space_tag_t iot; /* adapter I/O port tag */ + bus_space_tag_t memt; +#endif + sdla_pci_dev_t pci_dev; /* PCI config header info */ +#endif + wan_spinlock_t pcard_lock; /* lock per physical card */ + wan_smp_flag_t fe_rw_flag; + unsigned char adptr_security; /* Adapter security (AFT cards) */ + u16 hwec_chan_no; /* max hwec channels number */ + WAN_LIST_ENTRY(sdlahw_card) next; +} sdlahw_card_t; + + +/*------------------------------------------------------------- + * + */ +typedef struct sdlahw_port +{ + int used; + char *devname; + sdla_hw_probe_t *hwprobe; +} sdlahw_port_t; + +/*---------------------------------------------------------------------------- + * Adapter hardware configuration. Pointer to this structure is passed to all + * APIs. + */ +typedef struct sdlahw +{ + int used; + char *devname; + u16 status; + unsigned fwid; /* firmware ID */ +#if defined(__NetBSD__) || defined(__OpenBSD__) + bus_space_handle_t ioh; /* adapter I/O port handle */ + bus_dma_tag_t dmat; +#endif + int irq; /* interrupt request level */ +#if (defined(__FreeBSD__) && __FreeBSD_version >= 450000) + void* irqh[SDLA_MAX_PORTS]; +#endif + unsigned int cpu_no; /* PCI CPU Number */ + unsigned int line_no; /* PCI CPU Number */ + char auto_pci_cfg; /* Auto PCI configuration */ + sdla_mem_handle_t dpmbase; /* dual-port memory base */ + sdla_base_addr_t mem_base_addr; + unsigned dpmsize; /* dual-port memory size */ + unsigned pclk; /* CPU clock rate, kHz */ + unsigned long memory; /* memory size */ + sdla_mem_handle_t vector; /* local offset of the DPM window */ + unsigned io_range; /* I/O port range */ + unsigned char regs[SDLA_MAXIORANGE]; /* was written to registers */ + + unsigned reserved[5]; + unsigned char hw_info[100]; + + /* */ + unsigned magic; + void* dev; /* used only for FreeBSD/OpenBSD */ + u16 configured; + int max_ports; + sdlahw_port_t hwport[SDLA_MAX_PORTS]; + sdlahw_card_t* hwcard; + WAN_LIST_ENTRY(sdlahw) next; +} sdlahw_t; + +typedef struct sdlahw_iface +{ + int (*setup)(void*,wandev_conf_t*); + int (*load)(void*,void*, unsigned); + int (*down)(void*); + int (*start)(sdlahw_t* hw, unsigned addr); + int (*hw_halt)(void*); + int (*intack)(void*, uint32_t); + int (*read_int_stat)(void*, uint32_t*); + int (*mapmem)(void*, unsigned long); + int (*check_mismatch)(void*, unsigned char); + int (*getcfg)(void*, int, void*); + int (*isa_read_1)(void* hw, unsigned int offset, u8*); + int (*isa_write_1)(void* hw, unsigned int offset, u8); + int (*io_write_1)(void* hw, unsigned int offset, u8); + int (*io_read_1)(void* hw, unsigned int offset, u8*); + int (*bus_write_1)(void* hw, unsigned int offset, u8); + int (*bus_write_2)(void* hw, unsigned int offset, u16); + int (*bus_write_4)(void* hw, unsigned int offset, u32); + int (*bus_read_1)(void* hw, unsigned int offset, u8*); + int (*bus_read_2)(void* hw, unsigned int offset, u16*); + int (*bus_read_4)(void* hw, unsigned int offset, u32*); + int (*pci_write_config_byte)(void* hw, int reg, u8 value); + int (*pci_write_config_word)(void* hw, int reg, u16 value); + int (*pci_write_config_dword)(void* hw, int reg, u32 value); + int (*pci_read_config_byte)(void* hw, int reg, u8* value); + int (*pci_read_config_word)(void* hw, int reg, u16* value); + int (*pci_read_config_dword)(void* hw, int reg, u32* value); + int (*cmd)(void* phw, unsigned long offset, wan_mbox_t* mbox); + int (*peek)(void*,unsigned long, void*,unsigned); + int (*poke)(void*,unsigned long, void*,unsigned); + int (*poke_byte)(void*,unsigned long, u8); + int (*set_bit)(void*,unsigned long, u8); + int (*clear_bit)(void*,unsigned long,u8); + int (*set_intrhand)(void*, void (*isr_func)(void*), void*,int); + int (*restore_intrhand)(void*,int); + int (*is_te1)(void*); + int (*is_56k)(void*); + int (*get_hwcard)(void*, void**); + int (*get_hwprobe)(void*, int comm_port, void**); + int (*hw_unlock)(void *phw, wan_smp_flag_t *flag); + int (*hw_lock)(void *phw, wan_smp_flag_t *flag); + int (*hw_same)(void *phw1, void *phw2); + int (*fe_test_and_set_bit)(void *phw); + int (*fe_clear_bit)(void *phw); + sdla_dma_addr_t (*pci_map_dma)(void *phw, void *buf, int len, int ctrl); + int (*pci_unmap_dma)(void *phw, sdla_dma_addr_t buf, int len, int ctrl); + int (*read_cpld)(void *phw, u16, u8*); + int (*write_cpld)(void *phw, u16, u8); +} sdlahw_iface_t; + +typedef struct sdla_hw_type_cnt +{ + unsigned char s508_adapters; + unsigned char s514x_adapters; + unsigned char s518_adapters; + unsigned char aft101_adapters; + unsigned char aft104_adapters; + unsigned char aft300_adapters; + unsigned char aft200_adapters; + unsigned char aft108_adapters; + unsigned char aft_x_adapters; +}sdla_hw_type_cnt_t; + +/****** Function Prototypes *************************************************/ + +EXTERN unsigned int sdla_hw_probe(void); +EXTERN void *sdla_get_hw_probe (void); +EXTERN void *sdla_get_hw_adptr_cnt(void); +EXTERN void* sdla_register (sdlahw_iface_t* hw_iface, wandev_conf_t*,char*); +EXTERN int sdla_unregister (void**, char*); + +#ifdef __SDLADRV__ + +static __inline unsigned int sdla_get_pci_bus(sdlahw_t* hw) +{ + sdlahw_card_t* card; + + WAN_ASSERT(hw == NULL); + WAN_ASSERT(hw->hwcard == NULL); + card = hw->hwcard; +#if defined(__FreeBSD__) +# if (__FreeBSD_version > 400000) + return pci_get_bus(card->pci_dev); +# else + return card->pci_dev->bus; +# endif +#elif defined(__NetBSD__) || defined(__OpenBSD__) + return card->pci_dev->pa_bus; +#elif defined(__LINUX__) + return ((struct pci_bus*)card->pci_dev->bus)->number; +#else +# warning "sdla_get_pci_bus: Not supported yet!" +#endif + return 0; +} + +static __inline unsigned int sdla_get_pci_slot(sdlahw_t* hw) +{ + sdlahw_card_t* card; + + WAN_ASSERT(hw == NULL); + WAN_ASSERT(hw->hwcard == NULL); + card = hw->hwcard; +#if defined(__FreeBSD__) +# if (__FreeBSD_version > 400000) + return pci_get_slot(card->pci_dev); +# else + return card->pci_dev->slot; +# endif +#elif defined(__NetBSD__) || defined(__OpenBSD__) + return card->pci_dev->pa_device; +#elif defined(__LINUX__) + return ((card->pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK); +#else +# warning "sdla_get_pci_slot: Not supported yet!" +#endif + return 0; +} + +static __inline int +sdla_bus_space_map(sdlahw_t* hw, int reg, int size, sdla_mem_handle_t* handle) +{ + int err = 0; +#if defined(__FreeBSD__) + *handle = (sdla_mem_handle_t)pmap_mapdev(hw->mem_base_addr + reg, size); +#elif defined(__NetBSD__) || defined(__OpenBSD__) + err = bus_space_map(hw->hwcard->memt, + hw->mem_base_addr+reg, + size, + 0, + handle); +#elif defined(__LINUX__) + *handle = (sdla_mem_handle_t)ioremap(hw->mem_base_addr+reg, size); +#else +# warning "sdla_bus_space_map: Not supported yet!" +#endif + return err; + +} + +static __inline void +sdla_bus_space_unmap(sdlahw_t* hw, sdla_mem_handle_t offset, int size) +{ +#if defined(__FreeBSD__) + int i = 0; + for (i = 0; i < size; i += PAGE_SIZE){ + pmap_kremove((vm_offset_t)offset + i); + } + kmem_free(kernel_map, (vm_offset_t)offset, size); +#elif defined(__NetBSD__) || defined(__OpenBSD__) + bus_space_unmap(hw->hwcard->memt, offset, size); +#elif defined(__LINUX__) + iounmap((void*)offset); +#else +# warning "sdla_bus_space_unmap: Not supported yet!" +#endif + +} + + +static __inline void +sdla_bus_set_region_1(sdlahw_t* hw, unsigned int offset, unsigned char val, unsigned int cnt) +{ +#if defined(__FreeBSD__) + return; +#elif defined(__NetBSD__) || defined(__OpenBSD__) + bus_space_set_region_1(hw->hwcard->memt, hw->dpmbase, offset, val, cnt); +#elif defined(__LINUX__) + wp_memset_io(hw->dpmbase + offset, val, cnt); +#else +# warning "sdla_bus_set_region_1: Not supported yet!" +#endif +} + +static __inline int +sdla_request_mem_region(sdlahw_t* hw, sdla_base_addr_t base_addr, unsigned int len, unsigned char* name, void** pres) +{ +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) + /* We don't need for BSD */ + return 0; +#elif defined(__LINUX__) + void* resource; + if ((resource = request_mem_region(base_addr, len, name)) == NULL){ + return -EINVAL; + } + *pres = resource; + return 0; +#else +# warning "sdla_request_mem_region: Not supported yet!" + return 0; +#endif +} + +static __inline void +sdla_release_mem_region(sdlahw_t* hw, sdla_base_addr_t base_addr, unsigned int len) +{ +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) + return; +#elif defined(__LINUX__) + release_mem_region(base_addr, len); +#else +# warning "sdla_release_mem_region: Not supported yet!" +#endif +} + +static __inline int +sdla_pci_enable_device(sdlahw_t* hw) +{ + sdlahw_card_t* card; + + WAN_ASSERT(hw == NULL); + WAN_ASSERT(hw->hwcard == NULL); + card = hw->hwcard; +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) + return 0; +#elif defined(__LINUX__) + return pci_enable_device(card->pci_dev); +#else +# warning "sdla_release_mem_region: Not supported yet!" + return -EINVAL; +#endif +} + +static __inline int +sdla_pci_disable_device(sdlahw_t* hw) +{ + sdlahw_card_t* card; + + WAN_ASSERT(hw == NULL); + WAN_ASSERT(hw->hwcard == NULL); + card = hw->hwcard; +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) + return 0; +#elif defined(__LINUX__) + pci_disable_device(card->pci_dev); + return 0; +#else +# warning "sdla_release_mem_region: Not supported yet!" + return -EINVAL; +#endif +} + + + +static __inline void +sdla_pci_set_master(sdlahw_t* hw) +{ + sdlahw_card_t* card; + + WAN_ASSERT1(hw == NULL); + WAN_ASSERT1(hw->hwcard == NULL); + card = hw->hwcard; +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) + return; +#elif defined(__LINUX__) + pci_set_master(card->pci_dev); +#else +# warning "sdla_pci_set_master: Not supported yet!" +#endif +} + + +static __inline void +sdla_get_pci_base_resource_addr(sdlahw_t* hw, int pci_offset, sdla_base_addr_t *base_addr) +{ + sdlahw_card_t* card; + + WAN_ASSERT1(hw == NULL); + WAN_ASSERT1(hw->hwcard == NULL); + card = hw->hwcard; + +#if defined(__FreeBSD__) +# if (__FreeBSD_version > 400000) + *base_addr = (sdla_base_addr_t)pci_read_config(card->pci_dev, pci_offset, 4); +# else + *base_addr = (sdla_base_addr_t)ci_cfgread(card->pci_dev, pci_offset, 4); +# endif +#elif defined(__NetBSD__) || defined(__OpenBSD__) + *base_addr = (sdla_base_addr_t)pci_conf_read(card->pci_dev->pa_pc, card->pci_dev->pa_tag, pci_offset); +#elif defined(__LINUX__) + + if (pci_offset == PCI_IO_BASE_DWORD){ + *base_addr = (sdla_base_addr_t)pci_resource_start(card->pci_dev,0); + }else{ + *base_addr = (sdla_base_addr_t)pci_resource_start(card->pci_dev,1); + } +#else +# warning "sdla_get_pci_base_resource_addr: Not supported yet!" +#endif +} + + + +#endif /* __SDLADRV__ */ + + +#undef EXTERN +#endif /* _SDLADRV_H */ diff -Nur linux.org/include/linux/sdla_ec.h linux-2.6.17/include/linux/sdla_ec.h --- linux.org/include/linux/sdla_ec.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/sdla_ec.h 2006-08-30 10:07:15.000000000 +0000 @@ -0,0 +1,281 @@ +/****************************************************************************** + * sdla_ec.h + * + * Author: Alex Feldman + * + * Copyright: (c) 1995-2001 Sangoma Technologies Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * ============================================================================ + ****************************************************************************** + */ + +#ifndef __SDLA_EC_H +# define __SDLA_EC_H + +#define AFT_HWEC_CLEAR_RESET 1 +#define AFT_HWEC_SET_RESET 2 + +#define WAN_OCT6100_RC_OK 0x0000 +#define WAN_OCT6100_RC_CPU_INTERFACE_NO_RESPONSE 0x0001 +/* OCT6100 state machine */ +enum { + WAN_OCT6100_STATE_NONE = 0x00, + WAN_OCT6100_STATE_RESET, + WAN_OCT6100_STATE_READY, + WAN_OCT6100_STATE_CHIP_READY +}; +#define WAN_OCT6100_STATE_DECODE(state) \ + (state == WAN_OCT6100_STATE_RESET) ? "Reset" : \ + (state == WAN_OCT6100_STATE_READY) ? "Ready" : \ + (state == WAN_OCT6100_STATE_CHIP_READY) ? "Chip Ready" :\ + "Unknown" + +#define WAN_EC_SOUT_DTMF_1 0x40000011 +#define WAN_EC_SOUT_DTMF_2 0x40000012 +#define WAN_EC_SOUT_DTMF_3 0x40000013 +#define WAN_EC_SOUT_DTMF_A 0x4000001A +#define WAN_EC_SOUT_DTMF_4 0x40000014 +#define WAN_EC_SOUT_DTMF_5 0x40000015 +#define WAN_EC_SOUT_DTMF_6 0x40000016 +#define WAN_EC_SOUT_DTMF_B 0x4000001B +#define WAN_EC_SOUT_DTMF_7 0x40000017 +#define WAN_EC_SOUT_DTMF_8 0x40000018 +#define WAN_EC_SOUT_DTMF_9 0x40000019 +#define WAN_EC_SOUT_DTMF_C 0x4000001C +#define WAN_EC_SOUT_DTMF_STAR 0x4000001E +#define WAN_EC_SOUT_DTMF_0 0x40000010 +#define WAN_EC_SOUT_DTMF_POUND 0x4000001F +#define WAN_EC_SOUT_DTMF_D 0x4000001D +#define WAN_EC_ROUT_DTMF_1 0x10000011 +#define WAN_EC_ROUT_DTMF_2 0x10000012 +#define WAN_EC_ROUT_DTMF_3 0x10000013 +#define WAN_EC_ROUT_DTMF_A 0x1000001A +#define WAN_EC_ROUT_DTMF_4 0x10000014 +#define WAN_EC_ROUT_DTMF_5 0x10000015 +#define WAN_EC_ROUT_DTMF_6 0x10000016 +#define WAN_EC_ROUT_DTMF_B 0x1000001B +#define WAN_EC_ROUT_DTMF_7 0x10000017 +#define WAN_EC_ROUT_DTMF_8 0x10000018 +#define WAN_EC_ROUT_DTMF_9 0x10000019 +#define WAN_EC_ROUT_DTMF_C 0x1000001C +#define WAN_EC_ROUT_DTMF_STAR 0x1000001E +#define WAN_EC_ROUT_DTMF_0 0x10000010 +#define WAN_EC_ROUT_DTMF_POUND 0x1000001F +#define WAN_EC_ROUT_DTMF_D 0x1000001D +#define WAN_EC_DECODE_DTMF_ID(id) \ + (id == WAN_EC_SOUT_DTMF_0) ? "SOUT_0" : \ + (id == WAN_EC_SOUT_DTMF_1) ? "SOUT_1" : \ + (id == WAN_EC_SOUT_DTMF_2) ? "SOUT_2" : \ + (id == WAN_EC_SOUT_DTMF_3) ? "SOUT_3" : \ + (id == WAN_EC_SOUT_DTMF_4) ? "SOUT_4" : \ + (id == WAN_EC_SOUT_DTMF_5) ? "SOUT_5" : \ + (id == WAN_EC_SOUT_DTMF_6) ? "SOUT_6" : \ + (id == WAN_EC_SOUT_DTMF_7) ? "SOUT_7" : \ + (id == WAN_EC_SOUT_DTMF_8) ? "SOUT_8" : \ + (id == WAN_EC_SOUT_DTMF_9) ? "SOUT_9" : \ + (id == WAN_EC_SOUT_DTMF_A) ? "SOUT_A" : \ + (id == WAN_EC_SOUT_DTMF_B) ? "SOUT_B" : \ + (id == WAN_EC_SOUT_DTMF_C) ? "SOUT_C" : \ + (id == WAN_EC_SOUT_DTMF_D) ? "SOUT_D" : \ + (id == WAN_EC_SOUT_DTMF_STAR) ? "SOUT_STAR" : \ + (id == WAN_EC_SOUT_DTMF_POUND) ? "SOUT_POUND" :\ + (id == WAN_EC_ROUT_DTMF_0) ? "ROUT_0" : \ + (id == WAN_EC_ROUT_DTMF_1) ? "ROUT_1" : \ + (id == WAN_EC_ROUT_DTMF_2) ? "ROUT_2" : \ + (id == WAN_EC_ROUT_DTMF_3) ? "ROUT_3" : \ + (id == WAN_EC_ROUT_DTMF_4) ? "ROUT_4" : \ + (id == WAN_EC_ROUT_DTMF_5) ? "ROUT_5" : \ + (id == WAN_EC_ROUT_DTMF_6) ? "ROUT_6" : \ + (id == WAN_EC_ROUT_DTMF_7) ? "ROUT_7" : \ + (id == WAN_EC_ROUT_DTMF_8) ? "ROUT_8" : \ + (id == WAN_EC_ROUT_DTMF_9) ? "ROUT_9" : \ + (id == WAN_EC_ROUT_DTMF_A) ? "ROUT_A" : \ + (id == WAN_EC_ROUT_DTMF_B) ? "ROUT_B" : \ + (id == WAN_EC_ROUT_DTMF_C) ? "ROUT_C" : \ + (id == WAN_EC_ROUT_DTMF_D) ? "ROUT_D" : \ + (id == WAN_EC_ROUT_DTMF_STAR) ? "ROUT_STAR" : \ + (id == WAN_EC_ROUT_DTMF_POUND) ? "ROUT_POUND" :\ + "Unknown" + +#define WAN_EC_TONE_NONE 0x00000000 +#define WAN_EC_TONE_PRESENT 0x00000001 +#define WAN_EC_TONE_STOP 0x00000002 +#define WAN_EC_DECODE_TONE_TYPE(type) \ + (type == WAN_EC_TONE_PRESENT) ? "Present" : \ + (type == WAN_EC_TONE_STOP) ? "Stop" : \ + "Unknown" + +/* OCT6100 api command */ +#if 1 +# define WAN_OCT6100_CMD_NONE _IOWR('E', 1, struct wan_ec_api_) +# define WAN_OCT6100_CMD_GET_INFO _IOWR('E', 2, struct wan_ec_api_) +# define WAN_OCT6100_CMD_SET_INFO _IOWR('E', 3, struct wan_ec_api_) +# define WAN_OCT6100_CMD_CLEAR_RESET _IOWR('E', 4, struct wan_ec_api_) +# define WAN_OCT6100_CMD_SET_RESET _IOWR('E', 5, struct wan_ec_api_) +# define WAN_OCT6100_CMD_BYPASS_ENABLE _IOWR('E', 6, struct wan_ec_api_) +# define WAN_OCT6100_CMD_BYPASS_DISABLE _IOWR('E', 7, struct wan_ec_api_) +# define WAN_OCT6100_CMD_API_WRITE _IOWR('E', 8, struct wan_ec_api_) +# define WAN_OCT6100_CMD_API_WRITE_SMEAR _IOWR('E', 9, struct wan_ec_api_) +# define WAN_OCT6100_CMD_API_WRITE_BURST _IOWR('E', 10, struct wan_ec_api_) +# define WAN_OCT6100_CMD_API_READ _IOWR('E', 11, struct wan_ec_api_) +# define WAN_OCT6100_CMD_API_READ_BURST _IOWR('E', 12, struct wan_ec_api_) +# define WAN_OCT6100_CMD_TONE_DETECTION _IOWR('E', 13, struct wan_ec_api_) +#else +enum { + WAN_OCT6100_CMD_NONE = 0x00, + WAN_OCT6100_CMD_GET_INFO, + WAN_OCT6100_CMD_SET_INFO, + WAN_OCT6100_CMD_CLEAR_RESET, + WAN_OCT6100_CMD_SET_RESET, + WAN_OCT6100_CMD_BYPASS_ENABLE, + WAN_OCT6100_CMD_BYPASS_DISABLE, + WAN_OCT6100_CMD_API_WRITE, + WAN_OCT6100_CMD_API_WRITE_SMEAR, + WAN_OCT6100_CMD_API_WRITE_BURST, + WAN_OCT6100_CMD_API_READ, + WAN_OCT6100_CMD_API_READ_BURST, + WAN_OCT6100_CMD_TONE_DETECTION +}; +#endif + +#define WAN_OCT6100_CMD_DECODE(cmd) \ + (cmd == WAN_OCT6100_CMD_GET_INFO) ? "Get Info" : \ + (cmd == WAN_OCT6100_CMD_SET_INFO) ? "Set Info" : \ + (cmd == WAN_OCT6100_CMD_CLEAR_RESET) ? "Clear Reset" : \ + (cmd == WAN_OCT6100_CMD_SET_RESET) ? "Set Reset" : \ + (cmd == WAN_OCT6100_CMD_BYPASS_ENABLE) ? "Bypass Enable" : \ + (cmd == WAN_OCT6100_CMD_BYPASS_DISABLE) ? "Bypass Disable" : \ + (cmd == WAN_OCT6100_CMD_API_WRITE) ? "Oct6100 API WRITE" : \ + (cmd == WAN_OCT6100_CMD_API_WRITE_SMEAR) ? "Oct6100 API WRITE SMEAR" : \ + (cmd == WAN_OCT6100_CMD_API_WRITE_BURST) ? "Oct6100 API WRITE BURST" : \ + (cmd == WAN_OCT6100_CMD_API_READ) ? "Oct6100 API READ" : \ + (cmd == WAN_OCT6100_CMD_API_READ_BURST) ? "Oct6100 API READ BURST" : \ + (cmd == WAN_OCT6100_CMD_TONE_DETECTION) ? "Oct6100 TONE DETECTION" : \ + "Unknown" + +#if 0 +enum { + WAN_OCT6100_BYPASS = 0x01, + WAN_OCT6100_BYPASS_FULL, + WAN_OCT6100_BYPASS_LINE, +}; +#endif + +/*===========================================================================*\ + User process context - This would probably have to be defined elsewhere. + This structure must be allocated by the calling process and the parameters + should be defined prior to open the OCT6100 chip. +\*===========================================================================*/ +typedef struct _OCTPCIDRV_USER_PROCESS_CONTEXT_ +{ + /* Is main process */ + unsigned int fMainProcess; + + /* Handle to driver (opened by calling process) */ + unsigned int hDriver; + + /* Interface name to driver (copied by calling process) */ + unsigned char devname[WAN_DRVNAME_SZ+1]; + unsigned char ifname[WAN_IFNAME_SZ+1]; + + /* Handle to serialization object used for read and writes */ + unsigned int ulUserReadWriteSerObj; + + /* Board index. */ + unsigned int ulBoardId; + + /* Board type. */ + unsigned int ulBoardType; + +} tOCTPCIDRV_USER_PROCESS_CONTEXT, *tPOCTPCIDRV_USER_PROCESS_CONTEXT; + +#define u_ecd u.ecd +#define u_tone u.tone +#define u_oct6100_write u.oct6100_write +#define u_oct6100_write_swear u.oct6100_write_swear +#define u_oct6100_write_burst u.oct6100_write_burst +#define u_oct6100_read u.oct6100_read +#define u_oct6100_read_burst u.oct6100_read_burst +typedef struct wan_ec_api_ { + char name[WAN_DRVNAME_SZ+1]; + char devname[WAN_DRVNAME_SZ+1]; + char if_name[WAN_IFNAME_SZ+1]; + unsigned int cmd; + unsigned int type; + unsigned int ulResult; + unsigned int dummy; + + union { + struct ecd_ { + unsigned int state; + unsigned char fe_media; + unsigned int fe_lineno; + unsigned int fe_max_channels; + unsigned int fe_tdmv_law; + unsigned int channel; + unsigned int chip_no; + unsigned int max_channels; + unsigned int max_ec_channels; + unsigned int ulApiInstanceSize; + } ecd; + struct oct6100_write_ { + unsigned int ulChipIndex; + unsigned int ulWriteAddress; + unsigned short usWriteData; + } oct6100_write; + struct oct6100_write_swear_ { + unsigned int ulChipIndex; + unsigned int ulWriteAddress; + unsigned short usWriteData; + unsigned int ulWriteLength; + } oct6100_write_swear; + struct oct6100_write_burst_ { + unsigned int ulChipIndex; + unsigned int ulWriteAddress; + unsigned int ulWriteLength; + unsigned int pWriteData; /*unsigned short *pWriteData;*/ + } oct6100_write_burst; + struct oct6100_read_ { + unsigned int ulChipIndex; + unsigned int ulReadAddress; + unsigned short usReadData; + } oct6100_read; + struct oct6100_read_burst_ { + unsigned int ulChipIndex; + unsigned int ulReadAddress; + unsigned int ulReadLength; + unsigned int pReadData; /*unsigned short *pReadData*/ + } oct6100_read_burst; + struct tone_ { + unsigned int fe_chan; + unsigned int type; /* TONE_PRESENT/TONE_STOP */ + unsigned int id; /* TONE*/ + } tone; + } u; +} wan_ec_api_t; + +typedef struct wan_ec_iface_ +{ + int (*action)(void *pcard, int, int); + +} wan_ec_iface_t; + +#if defined(WAN_KERNEL) +/* global interface functions */ +void *wan_ec_config (void *pcard, int max_channels); +int wan_ec_remove(void*, void *pcard); +int wan_ec_ioctl(void*, struct ifreq*, void *pcard); +int wan_ec_dev_ioctl(void*, void *pcard); + +#if defined(__LINUX__) +int wanpipe_ecdev_reg(void *ec, char *ec_name, int ec_chip_no); +int wanpipe_ecdev_unreg(int ec_chip_no); +#endif + +#endif + +#endif /* __SDLA_EC_H */ diff -Nur linux.org/include/linux/sdla_edu.h linux-2.6.17/include/linux/sdla_edu.h --- linux.org/include/linux/sdla_edu.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/sdla_edu.h 2006-08-30 10:07:15.000000000 +0000 @@ -0,0 +1,167 @@ +/************************************************************************* + * sdla_edu.h Sangoma Educatonal Kit definitions + * + * Author: David Rokhvarg + * + * Copyright: (c) 1984-2004 Sangoma Technologies Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the term of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. +=========================================================================== + * + * Sep 18, 2001 David Rokhvarg Initial version. + * + * Jul 30, 2003 David Rokhvarg v 1.0 + * 1. sdla_load() is not used anymore, + * all the loading is done from user mode instead. + * All IOCTLs used for loading are not valid anymore. + * 2. New IOCTLs added for starting and stopping + * the card. + * + * Nov 17, 2004 David Rokhvarg v 2.0 + * 1. Removed globals and put into private area + * 2. New IOCTLs added for TCP/IP handling. + * +=========================================================================== + Organization + - Constants defining the shared memory control block (mailbox) + - IOCTL codes + - Structures for performing IOCTLs + +*************************************************************************/ + +#ifndef _SDLA_EDU_H +# define _SDLA_EDU_H + +/*------------------------------------------------------------------------ + Notes: + + Compiler Platform + ------------------------ + GNU C Linux + +------------------------------------------------------------------------*/ + +enum SDLA_COMMAND{ + + SDLA_CMD_READ_BYTE = 10, + SDLA_CMD_WRITE_BYTE, + + SDLA_CMD_READ_PORT_BYTE, + SDLA_CMD_WRITE_PORT_BYTE, + + SDLA_CMD_READ_BLOCK, + SDLA_CMD_WRITE_BLOCK, + + SDLA_CMD_GET_CARDS, + SDLA_CMD_REGISTER, + SDLA_CMD_DEREGISTER, + SDLA_CMD_PREPARE_TO_LOAD, + SDLA_CMD_LOAD_COMPLETE, + SDLA_CMD_ZERO_WINDOW, + + SDLA_CMD_START_S514, + SDLA_CMD_STOP_S514, + + SDLA_CMD_IS_TX_DATA_AVAILABLE, + SDLA_CMD_COPLETE_TX_REQUEST, + + SDLA_CMD_INDICATE_RX_DATA_AVAILABLE, + SDLA_CMD_GET_PCI_ADAPTER_TYPE +}; + +typedef struct edu_exec_cmd{ + unsigned char ioctl; // the ioctl code + unsigned char return_code; + unsigned short buffer_length; // the data length + unsigned long offset; // offset on the card +}edu_exec_cmd_t; + +#define MAX_TCP_IP_DATA_LEN 800L +#define MAX_TX_RX_DATA_SIZE 2000 +typedef struct{ + //caller's card number. only card 0 can do IP transactions. + unsigned char cardnumber; + //operation status + unsigned char status; + //length of data in 'data' + unsigned long buffer_length; + unsigned char data[MAX_TX_RX_DATA_SIZE]; +}TX_RX_DATA; + +// +//possible 'status' values in 'TX_RX_DATA' structure on completion of: +// 1. SDLA_CMD_COPLETE_TX_REQUEST +// 2. SDLA_CMD_IS_TX_DATA_AVAILABLE +// 3. SDLA_CMD_INDICATE_RX_DATA_AVAILABLE +// +enum TX_RX_STATUS{ + TX_SUCCESS = 1, + TX_ERR_PROTOCOL_DOWN, + TX_ERR_HARDWARE, + TX_RX_REQUEST_INVALID +}; + +#if !defined(BUILD_FOR_UNIX) +#define IOCTL_SDLA CTL_CODE(FILE_DEVICE_UNKNOWN, 0, METHOD_BUFFERED, FILE_ANY_ACCESS) + +typedef struct { + unsigned char cardnumber; + unsigned long offset; + unsigned char value; +} XFER_BYTE_CONTROL; + +#define MAX_CARDS 1 //card 0 and card 1 only + +/* structure used for reading and writing blocks */ +typedef struct { + void* buffer; + unsigned short num_bytes; + unsigned long offset; + unsigned char card_number; +} SDLA_BLOCKOP; + +typedef struct { + unsigned char cardnumber; + unsigned char rcode; +} CARD_TRANSACTION; + + +#define MAX_IOCTL_DATA_LEN 4096 +typedef struct{ + + unsigned long command; + unsigned long buffer_length; + unsigned char return_code; + unsigned char data[MAX_IOCTL_DATA_LEN]; +}SDLA_CTL_BLOCK; + + +typedef struct{ + + void* ndis_adapter; + +}SDLA_DEV_EXTENSION; + +//RESULT MESSAGES + +#define SDLAR_NOT_REGISTERED 0L +#define SDLAR_DEREGISTERED 1L +#define SDLAR_RELEASED 2L +#define SDLAR_REGISTERED 1L +#define SDLAR_ALLOCATED 2L + +#define SDLAR_CARD_BLOCKED 0L +#define SDLAR_PREPARED 2L +#define SDLAR_NOT_PREPARED 0L +#define SDLAR_ERROR_PREPARING 3L + +#define DRV_NAME "EduKit" + +#endif //#if !defined(BUILD_FOR_UNIX) + +#endif //_SDLA_EDU_H + + diff -Nur linux.org/include/linux/sdla_fr.h linux-2.6.17/include/linux/sdla_fr.h --- linux.org/include/linux/sdla_fr.h 2006-06-18 01:49:35.000000000 +0000 +++ linux-2.6.17/include/linux/sdla_fr.h 2006-08-30 10:07:15.000000000 +0000 @@ -23,6 +23,8 @@ #ifndef _SDLA_FR_H #define _SDLA_FR_H +#include + /*---------------------------------------------------------------------------- * Notes: * ------ @@ -70,39 +72,10 @@ unsigned short dlci PACKED; /* DLCI number */ unsigned char attr PACKED; /* FECN, BECN, DE and C/R bits */ unsigned short rxlost1 PACKED; /* frames discarded at int. level */ - unsigned long rxlost2 PACKED; /* frames discarded at app. level */ + unsigned int rxlost2 PACKED; /* frames discarded at app. level */ unsigned char rsrv[2] PACKED; /* reserved for future use */ } fr_cmd_t; -/* 'command' field defines */ -#define FR_WRITE 0x01 -#define FR_READ 0x02 -#define FR_ISSUE_IS_FRAME 0x03 -#define FR_SET_CONFIG 0x10 -#define FR_READ_CONFIG 0x11 -#define FR_COMM_DISABLE 0x12 -#define FR_COMM_ENABLE 0x13 -#define FR_READ_STATUS 0x14 -#define FR_READ_STATISTICS 0x15 -#define FR_FLUSH_STATISTICS 0x16 -#define FR_LIST_ACTIVE_DLCI 0x17 -#define FR_FLUSH_DATA_BUFFERS 0x18 -#define FR_READ_ADD_DLC_STATS 0x19 -#define FR_ADD_DLCI 0x20 -#define FR_DELETE_DLCI 0x21 -#define FR_ACTIVATE_DLCI 0x22 -#define FR_DEACTIVATE_DLCI 0x22 -#define FR_READ_MODEM_STATUS 0x30 -#define FR_SET_MODEM_STATUS 0x31 -#define FR_READ_ERROR_STATS 0x32 -#define FR_FLUSH_ERROR_STATS 0x33 -#define FR_READ_DLCI_IB_MAPPING 0x34 -#define FR_READ_CODE_VERSION 0x40 -#define FR_SET_INTR_MODE 0x50 -#define FR_READ_INTR_MODE 0x51 -#define FR_SET_TRACE_CONFIG 0x60 -#define FR_FT1_STATUS_CTRL 0x80 -#define FR_SET_FT1_MODE 0x81 /* Special UDP drivers management commands */ #define FPIPE_ENABLE_TRACING 0x41 @@ -114,6 +87,11 @@ #define FPIPE_DRIVER_STAT_GEN 0x47 #define FPIPE_FLUSH_DRIVER_STATS 0x48 #define FPIPE_ROUTER_UP_TIME 0x49 +#define FPIPE_TE1_56K_STAT 0x50 /* TE1_56K */ +#define FPIPE_GET_MEDIA_TYPE 0x51 /* TE1_56K */ +#define FPIPE_FLUSH_TE1_PMON 0x52 /* TE1 */ +#define FPIPE_READ_REGISTER 0x53 /* TE1_56K */ +#define FPIPE_TE1_CFG 0x54 /* TE1 */ /* 'result' field defines */ #define FRRES_OK 0x00 /* command executed successfully */ @@ -136,19 +114,6 @@ #define FRATTR_ /*---------------------------------------------------------------------------- - * Frame relay mailbox. - * This structure is located at offset FR50?_MBOX_OFFS into FR_MB_VECTOR. - * For S502 it is also located at offset FR502_RXMB_OFFS into - * FR502_RX_VECTOR. - */ -typedef struct fr_mbox -{ - unsigned char opflag PACKED; /* 00h: execution flag */ - fr_cmd_t cmd PACKED; /* 01h: command block */ - unsigned char data[1] PACKED; /* 10h: variable length data buffer */ -} fr_mbox_t; - -/*---------------------------------------------------------------------------- * S502 frame relay status flags. * This structure is located at offset FR502_FLAG_OFFS into FR_MB_VECTOR. */ @@ -176,7 +141,7 @@ unsigned char rsrv2[11] PACKED; /* 05h: reserved */ unsigned char iflag PACKED; /* 10h: interrupt flag */ unsigned char imask PACKED; /* 11h: interrupt mask */ - unsigned long tse_offs PACKED; /* 12h: Tx status element */ + unsigned int tse_offs PACKED; /* 12h: Tx status element */ unsigned short dlci PACKED; /* 16h: DLCI NUMBER */ } fr508_flags_t; @@ -207,11 +172,11 @@ typedef struct fr_buf_info { unsigned short rse_num PACKED; /* 00h: number of status elements */ - unsigned long rse_base PACKED; /* 02h: receive status array base */ - unsigned long rse_next PACKED; /* 06h: next status element */ - unsigned long buf_base PACKED; /* 0Ah: rotational buffer base */ + unsigned int rse_base PACKED; /* 02h: receive status array base */ + unsigned int rse_next PACKED; /* 06h: next status element */ + unsigned int buf_base PACKED; /* 0Ah: rotational buffer base */ unsigned short reserved PACKED; /* 0Eh: */ - unsigned long buf_top PACKED; /* 10h: rotational buffer top */ + unsigned int buf_top PACKED; /* 10h: rotational buffer top */ } fr_buf_info_t; /*---------------------------------------------------------------------------- @@ -228,7 +193,7 @@ unsigned char attr PACKED; /* 05h: FECN/BECN/DE/CR */ unsigned short tmstamp PACKED; /* 06h: time stamp */ unsigned short rsrv[2] PACKED; /* 08h: */ - unsigned long offset PACKED; /* 0Ch: buffer absolute address */ + unsigned int offset PACKED; /* 0Ch: buffer absolute address */ } fr_rx_buf_ctl_t; typedef struct fr_tx_buf_ctl @@ -239,7 +204,7 @@ unsigned short dlci PACKED; /* 07h: DLCI */ unsigned char attr PACKED; /* 09h: FECN/BECN/DE/CR */ unsigned short rsrv1 PACKED; /* 0Ah: */ - unsigned long offset PACKED; /* 0Ch: buffer absolute address */ + unsigned int offset PACKED; /* 0Ch: buffer absolute address */ } fr_tx_buf_ctl_t; /*---------------------------------------------------------------------------- @@ -306,7 +271,7 @@ unsigned char attr PACKED; /* trace attributes */ unsigned short tmstamp PACKED; /* time stamp */ unsigned char rsrv1[4] PACKED; /* reserved */ - unsigned long offset PACKED; /* buffer absolute address */ + unsigned int offset PACKED; /* buffer absolute address */ } fr_trc_el_t; typedef struct { @@ -324,6 +289,7 @@ /* bit settings for the 'status' byte - note that bits 1, 2 and 3 are used */ /* for returning the number of frames being passed to fpipemon */ +#define TRC_INCOMING_FRM 0x00 #define TRC_OUTGOING_FRM 0x01 #define TRC_ABORT_ERROR 0x10 #define TRC_CRC_ERROR 0x20 @@ -399,12 +365,15 @@ /* 'status' defines */ #define FR_LINK_INOPER 0x00 /* for global status (DLCI == 0) */ #define FR_LINK_OPER 0x01 + +#define FR_DLCI_INOPER 0x00 #define FR_DLCI_DELETED 0x01 /* for circuit status (DLCI != 0) */ #define FR_DLCI_ACTIVE 0x02 #define FR_DLCI_WAITING 0x04 #define FR_DLCI_NEW 0x08 #define FR_DLCI_REPORT 0x40 +#if 0 /*---------------------------------------------------------------------------- * Global Statistics Block. * This structure is returned by the FR_READ_STATISTICS command when @@ -449,19 +418,20 @@ */ typedef struct fr_dlci_stat { - unsigned long tx_frames PACKED; /* 00h: */ - unsigned long tx_bytes PACKED; /* 04h: */ - unsigned long rx_frames PACKED; /* 08h: */ - unsigned long rx_bytes PACKED; /* 0Ch: */ - unsigned long rx_dropped PACKED; /* 10h: */ - unsigned long rx_inactive PACKED; /* 14h: */ - unsigned long rx_exceed_CIR PACKED; /* 18h: */ - unsigned long rx_DE_set PACKED; /* 1Ch: */ - unsigned long tx_throughput PACKED; /* 20h: */ - unsigned long tx_calc_timer PACKED; /* 24h: */ - unsigned long rx_throughput PACKED; /* 28h: */ - unsigned long rx_calc_timer PACKED; /* 2Ch: */ + unsigned int tx_frames PACKED; /* 00h: */ + unsigned int tx_bytes PACKED; /* 04h: */ + unsigned int rx_frames PACKED; /* 08h: */ + unsigned int rx_bytes PACKED; /* 0Ch: */ + unsigned int rx_dropped PACKED; /* 10h: */ + unsigned int rx_inactive PACKED; /* 14h: */ + unsigned int rx_exceed_CIR PACKED; /* 18h: */ + unsigned int rx_DE_set PACKED; /* 1Ch: */ + unsigned int tx_throughput PACKED; /* 20h: */ + unsigned int tx_calc_timer PACKED; /* 24h: */ + unsigned int rx_throughput PACKED; /* 28h: */ + unsigned int rx_calc_timer PACKED; /* 2Ch: */ } fr_dlci_stat_t; +#endif /*---------------------------------------------------------------------------- * Communications error statistics. @@ -498,9 +468,9 @@ unsigned char ar_pln PACKED; /* length of protocol addr */ unsigned short ar_op PACKED; /* ARP opcode */ unsigned short ar_sha PACKED; /* Sender DLCI addr 2 bytes */ - unsigned long ar_sip PACKED; /* Sender IP addr 4 bytes */ + unsigned int ar_sip PACKED; /* Sender IP addr 4 bytes */ unsigned short ar_tha PACKED; /* Target DLCI addr 2 bytes */ - unsigned long ar_tip PACKED; /* Target IP addr 4 bytes */ + unsigned int ar_tip PACKED; /* Target IP addr 4 bytes */ } arphdr_fr_t; /*---------------------------------------------------------------------------- @@ -513,42 +483,7 @@ unsigned char NLPID PACKED; /* SNAP */ unsigned char OUI[3] PACKED; /* Ethertype, etc... */ unsigned short PID PACKED; /* ARP, IP, etc... */ - } arphdr_1490_t; - -/* UDP/IP packet (for UDP management) layout */ - -/* The embedded control block for UDP mgmt - This is essentially a mailbox structure, without the large data field */ - -typedef struct { - unsigned char opp_flag PACKED; /* the opp flag */ - unsigned char command PACKED; /* command code */ - unsigned short length PACKED; /* length of data buffer */ - unsigned char result PACKED; /* return code */ - unsigned short dlci PACKED; /* DLCI number */ - unsigned char attr PACKED; /* FECN, BECN, DE and C/R bits */ - unsigned short rxlost1 PACKED; /* frames discarded at int. level */ - unsigned long rxlost2 PACKED; /* frames discarded at app. level */ - unsigned char rsrv[2] PACKED; /* reserved for future use */ -} cblock_t; - - -/* UDP management packet layout (data area of ip packet) */ - -typedef struct { - unsigned char control PACKED; - unsigned char NLPID PACKED; -} fr_encap_hdr_t; - -typedef struct { -// fr_encap_hdr_t fr_encap_hdr PACKED; - ip_pkt_t ip_pkt PACKED; - udp_pkt_t udp_pkt PACKED; - wp_mgmt_t wp_mgmt PACKED; - cblock_t cblock PACKED; - unsigned char data[4080] PACKED; -} fr_udp_pkt_t; - +} arphdr_1490_t; /* valid ip_protocol for UDP management */ #define UDPMGMT_UDP_PROTOCOL 0x11 @@ -562,52 +497,52 @@ #define UDP_OFFSET 12 typedef struct { - unsigned long if_send_entry; - unsigned long if_send_skb_null; - unsigned long if_send_broadcast; - unsigned long if_send_multicast; - unsigned long if_send_critical_ISR; - unsigned long if_send_critical_non_ISR; - unsigned long if_send_busy; - unsigned long if_send_busy_timeout; - unsigned long if_send_DRVSTATS_request; - unsigned long if_send_FPIPE_request; - unsigned long if_send_wan_disconnected; - unsigned long if_send_dlci_disconnected; - unsigned long if_send_no_bfrs; - unsigned long if_send_adptr_bfrs_full; - unsigned long if_send_bfrs_passed_to_adptr; - unsigned long if_send_consec_send_fail; + unsigned int if_send_entry; + unsigned int if_send_skb_null; + unsigned int if_send_broadcast; + unsigned int if_send_multicast; + unsigned int if_send_critical_ISR; + unsigned int if_send_critical_non_ISR; + unsigned int if_send_busy; + unsigned int if_send_busy_timeout; + unsigned int if_send_DRVSTATS_request; + unsigned int if_send_FPIPE_request; + unsigned int if_send_wan_disconnected; + unsigned int if_send_dlci_disconnected; + unsigned int if_send_no_bfrs; + unsigned int if_send_adptr_bfrs_full; + unsigned int if_send_bfrs_passed_to_adptr; + unsigned int if_send_consec_send_fail; } drvstats_if_send_t; typedef struct { - unsigned long rx_intr_no_socket; - unsigned long rx_intr_dev_not_started; - unsigned long rx_intr_DRVSTATS_request; - unsigned long rx_intr_FPIPE_request; - unsigned long rx_intr_bfr_not_passed_to_stack; - unsigned long rx_intr_bfr_passed_to_stack; + unsigned int rx_intr_no_socket; + unsigned int rx_intr_dev_not_started; + unsigned int rx_intr_DRVSTATS_request; + unsigned int rx_intr_FPIPE_request; + unsigned int rx_intr_bfr_not_passed_to_stack; + unsigned int rx_intr_bfr_passed_to_stack; } drvstats_rx_intr_t; typedef struct { - unsigned long UDP_FPIPE_mgmt_kmalloc_err; - unsigned long UDP_FPIPE_mgmt_direction_err; - unsigned long UDP_FPIPE_mgmt_adptr_type_err; - unsigned long UDP_FPIPE_mgmt_adptr_cmnd_OK; - unsigned long UDP_FPIPE_mgmt_adptr_cmnd_timeout; - unsigned long UDP_FPIPE_mgmt_adptr_send_passed; - unsigned long UDP_FPIPE_mgmt_adptr_send_failed; - unsigned long UDP_FPIPE_mgmt_not_passed_to_stack; - unsigned long UDP_FPIPE_mgmt_passed_to_stack; - unsigned long UDP_FPIPE_mgmt_no_socket; - unsigned long UDP_DRVSTATS_mgmt_kmalloc_err; - unsigned long UDP_DRVSTATS_mgmt_adptr_cmnd_OK; - unsigned long UDP_DRVSTATS_mgmt_adptr_cmnd_timeout; - unsigned long UDP_DRVSTATS_mgmt_adptr_send_passed; - unsigned long UDP_DRVSTATS_mgmt_adptr_send_failed; - unsigned long UDP_DRVSTATS_mgmt_not_passed_to_stack; - unsigned long UDP_DRVSTATS_mgmt_passed_to_stack; - unsigned long UDP_DRVSTATS_mgmt_no_socket; + unsigned int UDP_FPIPE_mgmt_kmalloc_err; + unsigned int UDP_FPIPE_mgmt_direction_err; + unsigned int UDP_FPIPE_mgmt_adptr_type_err; + unsigned int UDP_FPIPE_mgmt_adptr_cmnd_OK; + unsigned int UDP_FPIPE_mgmt_adptr_cmnd_timeout; + unsigned int UDP_FPIPE_mgmt_adptr_send_passed; + unsigned int UDP_FPIPE_mgmt_adptr_send_failed; + unsigned int UDP_FPIPE_mgmt_not_passed_to_stack; + unsigned int UDP_FPIPE_mgmt_passed_to_stack; + unsigned int UDP_FPIPE_mgmt_no_socket; + unsigned int UDP_DRVSTATS_mgmt_kmalloc_err; + unsigned int UDP_DRVSTATS_mgmt_adptr_cmnd_OK; + unsigned int UDP_DRVSTATS_mgmt_adptr_cmnd_timeout; + unsigned int UDP_DRVSTATS_mgmt_adptr_send_passed; + unsigned int UDP_DRVSTATS_mgmt_adptr_send_failed; + unsigned int UDP_DRVSTATS_mgmt_not_passed_to_stack; + unsigned int UDP_DRVSTATS_mgmt_passed_to_stack; + unsigned int UDP_DRVSTATS_mgmt_no_socket; } drvstats_gen_t; typedef struct { diff -Nur linux.org/include/linux/sdla_front_end.h linux-2.6.17/include/linux/sdla_front_end.h --- linux.org/include/linux/sdla_front_end.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/sdla_front_end.h 2006-08-30 10:07:15.000000000 +0000 @@ -0,0 +1,473 @@ +/* + ************************************************************************************* + * * + * FRNT_END.H - the 'C' header file for the Sangoma S508/S514 adapter front-end API. * + * * + ************************************************************************************* +*/ +#ifndef _SDLA_FRONT_END_H_ +#define _SDLA_FRONT_END_H_ + +/* +************************************************************************* +* DEFINES AND MACROS * +************************************************************************* +*/ +/* Front-End media type */ +#define WAN_MEDIA_NONE 0x00 +#define WAN_MEDIA_T1 0x01 +#define WAN_MEDIA_E1 0x02 +#define WAN_MEDIA_56K 0x03 +#define WAN_MEDIA_DS3 0x04 +#define WAN_MEDIA_E3 0x05 +#define WAN_MEDIA_STS1 0x06 +#define WAN_MEDIA_J1 0x07 +#define WAN_MEDIA_FXOFXS 0x08 + +/*The line code */ +#define WAN_LCODE_AMI 0x01 /* T1/E1/DS3/E3 */ +#define WAN_LCODE_B8ZS 0x02 /* T1 */ +#define WAN_LCODE_HDB3 0x03 /* E1/E3 */ +#define WAN_LCODE_B3ZS 0x04 /* DS3 */ + +/* Framing modes */ +#define WAN_FR_ESF 0x01 +#define WAN_FR_D4 0x02 +#define WAN_FR_ESF_JAPAN 0x03 +#define WAN_FR_CRC4 0x04 +#define WAN_FR_NCRC4 0x05 +#define WAN_FR_UNFRAMED 0x06 +#define WAN_FR_E3_G751 0x07 +#define WAN_FR_E3_G832 0x08 +#define WAN_FR_DS3_Cbit 0x09 +#define WAN_FR_DS3_M13 0x10 + +/* Clocking Master/Normal */ +#define WAN_NORMAL_CLK 0x01 +#define WAN_MASTER_CLK 0x02 + +/* Front-End DEBUG flags */ +#define WAN_FE_DEBUG_RBS_RX_ENABLE 0x01 +#define WAN_FE_DEBUG_RBS_TX_ENABLE 0x02 +#define WAN_FE_DEBUG_RBS_RX_DISABLE 0x03 +#define WAN_FE_DEBUG_RBS_TX_DISABLE 0x04 +#define WAN_FE_DEBUG_RBS_READ 0x05 +#define WAN_FE_DEBUG_RBS_SET 0x06 +#define WAN_FE_DEBUG_RBS_PRINT 0x07 +#define WAN_FE_DEBUG_RBS_DECODE(mode) \ + ((mode) == WAN_FE_DEBUG_RBS_RX_ENABLE) ? "Enable RBS RX" : \ + ((mode) == WAN_FE_DEBUG_RBS_TX_ENABLE) ? "Enable RBS TX" : \ + ((mode) == WAN_FE_DEBUG_RBS_RX_DISABLE) ? "Disable RBS RX" : \ + ((mode) == WAN_FE_DEBUG_RBS_TX_DISABLE) ? "Disable RBS TX" : \ + ((mode) == WAN_FE_DEBUG_RBS_READ) ? "Read RBS" : \ + ((mode) == WAN_FE_DEBUG_RBS_SET) ? "Set RBS" : \ + ((mode) == WAN_FE_DEBUG_RBS_PRINT) ? "Print RBS" : "Unknown" + +#define WAN_FE_DEBUG_ALARM_AIS_ENABLE 0x01 +#define WAN_FE_DEBUG_ALARM_AIS_DISABLE 0x02 +#define WAN_FE_DEBUG_ALARM_DECODE(mode) \ + ((mode) == WAN_FE_DEBUG_ALARM_AIS_ENABLE) ? "Enable TX AIS" : \ + ((mode) == WAN_FE_DEBUG_ALARM_AIS_DISABLE) ? "Disable TX AIS" : \ + "Unknown" + +#define WAN_FE_DEBUG_NONE 0x00 +#define WAN_FE_DEBUG_RBS 0x01 +#define WAN_FE_DEBUG_ALARM 0x02 + +/* Front-End TX tri-state mode flags */ +#define WAN_FE_TXMODE_ENABLE 0x01 +#define WAN_FE_TXMODE_DISABLE 0x02 + +/* Read alarm flag */ +#define WAN_FE_ALARM_NONE 0x00 +#define WAN_FE_ALARM_READ 0x01 +#define WAN_FE_ALARM_PRINT 0x02 +#define IS_FE_ALARM_READ(action) ((action) & WAN_FE_ALARM_READ) +#define IS_FE_ALARM_PRINT(action) ((action) & WAN_FE_ALARM_PRINT) + +/* Read pmon flag */ +#define WAN_FE_PMON_READ 0x00 +#define WAN_FE_PMON_UPDATE 0x01 +#define WAN_FE_PMON_PRINT 0x02 +#define IS_FE_PMON_UPDATE(action) ((action) & WAN_FE_PMON_UPDATE) +#define IS_FE_PMON_PRINT(action) ((action) & WAN_FE_PMON_PRINT) + +/* FE interrupt action command */ +#define WAN_FE_INTR_ENABLE 0x01 +#define WAN_FE_INTR_MASK 0x02 + +/* FE event action command */ +#define WAN_FE_EVENT_ENABLE 0x01 +#define WAN_FE_EVENT_MASK 0x02 + +/* Alaw/Mulaw */ +#define WAN_TDMV_ALAW 0x01 +#define WAN_TDMV_MULAW 0x02 + +#define FE_MEDIA(fe_cfg) ((fe_cfg)->media) +#define FE_SUBMEDIA(fe_cfg) ((fe_cfg)->sub_media) +#define FE_LCODE(fe_cfg) ((fe_cfg)->lcode) +#define FE_FRAME(fe_cfg) ((fe_cfg)->frame) +#define FE_LINENO(fe_cfg) ((fe_cfg)->line_no) +#define FE_TXTRISTATE(fe_cfg) ((fe_cfg)->tx_tristate_mode) +#define FE_TDMV_LAW(fe_cfg) ((fe_cfg)->tdmv_law) + +#define IS_T1_MEDIA(fe_cfg) (FE_MEDIA(fe_cfg) == WAN_MEDIA_T1) +#define IS_E1_MEDIA(fe_cfg) (FE_MEDIA(fe_cfg) == WAN_MEDIA_E1) +#define IS_J1_MEDIA(fe_cfg) (FE_MEDIA(fe_cfg) == WAN_MEDIA_T1 && \ + FE_SUBMEDIA(fe_cfg) == WAN_MEDIA_J1) +#define IS_TE1_MEDIA(fe_cfg) (IS_T1_MEDIA(fe_cfg) || \ + IS_E1_MEDIA(fe_cfg) || \ + IS_J1_MEDIA(fe_cfg)) +#define IS_56K_MEDIA(fe_cfg) (FE_MEDIA(fe_cfg) == WAN_MEDIA_56K) +#define IS_TE1_56K_MEDIA(fe_cfg)(IS_TE1_MEDIA(fe_cfg) || \ + IS_56K_MEDIA(fe_cfg) +#define IS_DS3_MEDIA(fe_cfg) (FE_MEDIA(fe_cfg) == WAN_MEDIA_DS3) +#define IS_E3_MEDIA(fe_cfg) (FE_MEDIA(fe_cfg) == WAN_MEDIA_E3) +#define IS_FXOFXS_MEDIA(fe_cfg) (FE_MEDIA(fe_cfg) == WAN_MEDIA_FXOFXS) + +#define IS_TXTRISTATE(fe_cfg) (FE_TXTRISTATE(fe_cfg) == WANOPT_YES) + +#define MEDIA_DECODE(fe_cfg) \ + (FE_MEDIA(fe_cfg) == WAN_MEDIA_T1 && \ + FE_SUBMEDIA(fe_cfg)==WAN_MEDIA_J1)?"J1" : \ + (FE_MEDIA(fe_cfg) == WAN_MEDIA_T1) ? "T1" : \ + (FE_MEDIA(fe_cfg) == WAN_MEDIA_E1) ? "E1" : \ + (FE_MEDIA(fe_cfg) == WAN_MEDIA_J1) ? "J1" : \ + (FE_MEDIA(fe_cfg) == WAN_MEDIA_56K) ? "56K" : \ + (FE_MEDIA(fe_cfg) == WAN_MEDIA_DS3) ? "DS3" : \ + (FE_MEDIA(fe_cfg) == WAN_MEDIA_E3) ? "E3" : \ + (FE_MEDIA(fe_cfg) == WAN_MEDIA_FXOFXS) ? "FXO/FXS" : \ + "Unknown" + +#define LCODE_DECODE(fe_cfg) \ + (FE_LCODE(fe_cfg) == WAN_LCODE_AMI) ? "AMI" : \ + (FE_LCODE(fe_cfg) == WAN_LCODE_B8ZS) ? "B8ZS" : \ + (FE_LCODE(fe_cfg) == WAN_LCODE_HDB3) ? "HDB3" : \ + (FE_LCODE(fe_cfg) == WAN_LCODE_B3ZS) ? "B3ZS" : "Unknown" + +#define FRAME_DECODE(fe_cfg) \ + (FE_FRAME(fe_cfg) == WAN_FR_ESF) ? "ESF" : \ + (FE_FRAME(fe_cfg) == WAN_FR_D4) ? "D4" : \ + (FE_FRAME(fe_cfg) == WAN_FR_CRC4) ? "CRC4" : \ + (FE_FRAME(fe_cfg) == WAN_FR_NCRC4) ? "non-CRC4" : \ + (FE_FRAME(fe_cfg) == WAN_FR_UNFRAMED) ? "Unframed" : \ + (FE_FRAME(fe_cfg) == WAN_FR_E3_G751) ? "G.751" : \ + (FE_FRAME(fe_cfg) == WAN_FR_E3_G832) ? "G.832" : \ + (FE_FRAME(fe_cfg) == WAN_FR_DS3_Cbit) ? "C-bit" : \ + (FE_FRAME(fe_cfg) == WAN_FR_DS3_M13) ? "M13" : "Unknown" + + + +/* front-end configuration and access interface commands */ +#define READ_FRONT_END_REGISTER (WAN_FE_CMD_START+0) /* 0x90 read from front-end register */ +#define WRITE_FRONT_END_REGISTER (WAN_FE_CMD_START+1) /* 0x91 write to front-end register */ +#define READ_FRONT_END_STATISTICS (WAN_FE_CMD_START+2) /* 0x92 read the front-end statistics */ +#define FLUSH_FRONT_END_STATISTICS (WAN_FE_CMD_START+3) /* 0x93 flush the front-end statistics */ + + +typedef struct { + unsigned char media; + unsigned char sub_media; + unsigned char lcode; + unsigned char frame; + unsigned int line_no; + unsigned char tx_tristate_mode; + unsigned int tdmv_law; + union { + sdla_te_cfg_t te_cfg; + sdla_te3_cfg_t te3_cfg; + sdla_remora_cfg_t remora; + } cfg; +} sdla_fe_cfg_t; + +typedef struct { + unsigned int alarms; + unsigned int liu_alarms; + unsigned int bert_alarms; + union { + sdla_te_pmon_t te_pmon; + sdla_te3_pmon_t te3_pmon; + } u; +} sdla_fe_stats_t; + +typedef struct { + unsigned char type; + unsigned char mode; + int channel; + unsigned char abcd; +} sdla_fe_debug_t; + + +#ifdef WAN_KERNEL + +#define FE_ASSERT(val) if (val) return; +#define FE_ASSERT1(val) if (val) return 1; + +#define WAN_FECALL(dev, func, x) \ + ((dev)->fe_iface.func) ? (dev)->fe_iface.func x : -EINVAL + +#define IS_T1_FEMEDIA(fe) IS_T1_MEDIA(&((fe)->fe_cfg)) +#define IS_E1_FEMEDIA(fe) IS_E1_MEDIA(&((fe)->fe_cfg)) +#define IS_TE1_FEMEDIA(fe) IS_TE1_MEDIA(&((fe)->fe_cfg)) +#define IS_56K_FEMEDIA(fe) IS_56K_MEDIA(&((fe)->fe_cfg)) +#define IS_J1_FEMEDIA(fe) IS_J1_MEDIA(&((fe)->fe_cfg)) +#define IS_FXOFXS_FEMEDIA(fe) IS_FXOFXS_MEDIA(&((fe)->fe_cfg)) +#define IS_FE_TXTRISTATE(fe) IS_TXTRISTATE(&((fe)->fe_cfg)) + +#define WAN_FE_MEDIA(fe) FE_MEDIA(&((fe)->fe_cfg)) +#define WAN_FE_LCODE(fe) FE_LCODE(&((fe)->fe_cfg)) +#define WAN_FE_FRAME(fe) FE_FRAME(&((fe)->fe_cfg)) +#define WAN_FE_LINENO(fe) FE_LINENO(&((fe)->fe_cfg)) +#define WAN_FE_TXTRISTATE(fe) FE_TXTRISTATE(&((fe)->fe_cfg)) +#define WAN_FE_TDMV_LAW(fe) FE_TDMV_LAW(&((fe)->fe_cfg)) + +#define FE_MEDIA_DECODE(fe) MEDIA_DECODE(&((fe)->fe_cfg)) +#define FE_LCODE_DECODE(fe) LCODE_DECODE(&((fe)->fe_cfg)) +#define FE_FRAME_DECODE(fe) FRAME_DECODE(&((fe)->fe_cfg)) + +#define WAN_FE_MAX_CHANNELS(fe) \ + (IS_TE1_FEMEDIA(fe)) ? GET_TE_CHANNEL_RANGE(fe) : \ + (IS_FXOFXS_FEMEDIA(fe)) ? MAX_FXOFXS_CHANNELS : 0 + +/* Front-End status */ +#if 0 +enum fe_status { + FE_UNITIALIZED = 0x00, + FE_DISCONNECTED, + FE_CONNECTED +}; +#endif + +/* adapter configuration interface commands */ +#define SET_ADAPTER_CONFIGURATION (WAN_INTERFACE_CMD_START+0) /* 0xA0 set adapter configuration */ +#define READ_ADAPTER_CONFIGURATION (WAN_INTERFACE_CMD_START+1) /* 0xA1 read adapter configuration */ + +/* return codes from interface commands */ +#define LGTH_FE_CFG_DATA_INVALID 0x91 /* the length of the FE_RX_DISC_TX_IDLE_STRUCT is invalid */ +#define LGTH_ADAPTER_CFG_DATA_INVALID 0x91 /* the length of the passed configuration data is invalid */ +#define INVALID_FE_CFG_DATA 0x92 /* the passed SET_FE_RX_DISC_TX_IDLE_CFG data is invalid */ +#define ADPTR_OPERATING_FREQ_INVALID 0x92 /* an invalid adapter operating frequency was selected */ +#define PROT_CFG_BEFORE_FE_CFG 0x93 /* set the protocol-level configuration before setting the FE configuration */ + +#define SET_FE_RX_DISC_TX_IDLE_CFG 0x98 /* set the front-end Rx discard/Tx idle configuration */ +#define READ_FE_RX_DISC_TX_IDLE_CFG 0x99 /* read the front-end Rx discard/Tx idle configuration */ +#define SET_TE1_SIGNALING_CFG 0x9A /* set the T1/E1 signaling configuration */ +#define READ_TE1_SIGNALING_CFG 0x9B /* read the T1/E1 signaling configuration */ + + +#define COMMAND_INVALID_FOR_ADAPTER 0x9F /* the command is invalid for the adapter type */ + + +/* --------------------------------------------------------------------------------- + * Constants for the SET_FE_RX_DISC_TX_IDLE_CFG/READ_FE_RX_DISC_TX_IDLE_CFG commands + * --------------------------------------------------------------------------------*/ + +#define NO_ACTIVE_RX_TIME_SLOTS_T1 24 /* T1 - no active time slots used for reception */ +#define NO_ACTIVE_TX_TIME_SLOTS_T1 24 /* T1 - no active time slots used for transmission */ +#define NO_ACTIVE_RX_TIME_SLOTS_E1 32 /* E1 - no active time slots used for reception */ +#define NO_ACTIVE_TX_TIME_SLOTS_E1 31 /* E1 - no active time slots used for transmission (channel 0 reserved for framing) */ + +/* the structure used for the SET_FE_RX_DISC_TX_IDLE_CFG/READ_FE_RX_DISC_TX_IDLE_CFG command */ +#pragma pack(1) +typedef struct { + unsigned short lgth_Rx_disc_bfr; /* the length of the Rx discard buffer */ + unsigned short lgth_Tx_idle_bfr; /* the length of the Tx idle buffer */ + /* the transmit idle data buffer */ + unsigned char Tx_idle_data_bfr[NO_ACTIVE_TX_TIME_SLOTS_E1]; +} FE_RX_DISC_TX_IDLE_STRUCT; +#pragma pack() + + +/* ---------------------------------------------------------------------------- + * Constants for front-end access + * --------------------------------------------------------------------------*/ + +/* the structure used for the READ_FRONT_END_REGISTER/WRITE_FRONT_END_REGISTER command */ +#pragma pack(1) +typedef struct { + unsigned short register_number; /* the register number to be read from or written to */ + unsigned char register_value; /* the register value read/written */ +} FRONT_END_REG_STRUCT; +#pragma pack() + +#pragma pack(1) +typedef struct { + unsigned char opp_flag; /* opp flag */ + + union { + struct { + unsigned char RR8_56k; /* register #8 value - 56K CSU/DSU */ + unsigned char RR9_56k; /* register #9 value - 56K CSU/DSU */ + unsigned char RRA_56k; /* register #A value - 56K CSU/DSU */ + unsigned char RRB_56k; /* register #B value - 56K CSU/DSU */ + unsigned char RRC_56k; /* register #C value - 56K CSU/DSU */ + } stat_56k; + } FE_U; + +} FRONT_END_STATUS_STRUCT; +#pragma pack() + + +/* ----------------------------------------------------------------------------- + * Constants for the READ_FRONT_END_STATISTICS command + * ---------------------------------------------------------------------------*/ + +/* the front-end statistics structure */ +#pragma pack(1) +typedef struct { + unsigned int FE_interrupt_count; /* the number of front-end interrupts generated */ + unsigned int FE_app_timeout_count; /* the number of front-end interrupt application timeouts */ +} FE_STATISTICS_STRUCT; +#pragma pack() + + + +/* -------------------------------------------------------------------------------- + * Constants for the SET_ADAPTER_CONFIGURATION/READ_ADAPTER_CONFIGURATION commands + * -------------------------------------------------------------------------------*/ + +/* the adapter configuration structure */ +#pragma pack(1) +typedef struct { + unsigned short adapter_type; /* type of adapter */ + unsigned short adapter_config; /* miscellaneous adapter configuration options */ + unsigned int operating_frequency; /* adapter operating frequency */ +} ADAPTER_CONFIGURATION_STRUCT; +#pragma pack() + +typedef int (WRITE_FRONT_END_REG_T)(void*, ...); +typedef unsigned char (READ_FRONT_END_REG_T)(void*, ...); + +enum { + AFT_LED_ON, + AFT_LED_OFF, + AFT_LED_TOGGLE +}; + +typedef struct { + char *name; + void *card; + sdla_fe_cfg_t fe_cfg; + /* FIXME: Remove the following parameters from wandev_t */ + unsigned char fe_status; +/* unsigned int fe_alarm; */ + unsigned char fe_chip_id; + unsigned char fe_debug; + /* ^^^ */ + union { +#define te_param fe_param.te +#define rm_param fe_param.remora + sdla_te_param_t te; + sdla_56k_param_t k56_param; + sdla_te3_param_t te3_param; + sdla_remora_param_t remora; + } fe_param; +#define fe_alarm fe_stats.alarms +#define liu_alarm fe_stats.liu_alarms +#define bert_alarm fe_stats.bert_alarms + sdla_fe_stats_t fe_stats; + int (*write_cpld)(void*, unsigned short, unsigned char); + int (*read_cpld)(void*, unsigned short, unsigned char); + int (*write_framer)(void*,unsigned short,unsigned short); + unsigned int (*read_framer)(void*,unsigned short); + WRITE_FRONT_END_REG_T *write_fe_reg; + READ_FRONT_END_REG_T *read_fe_reg; + READ_FRONT_END_REG_T *__read_fe_reg; +} sdla_fe_t; + +/* +** Sangoma Front-End interface structure +*/ +#if 0 +typedef struct { + /* In-Service or Not (T1/E1/56K) */ + unsigned int (*get_fe_service_status)(void*); + /* Print Front-End alarm (T1/E1/56K) */ + void (*print_fe_alarm)(void*,unsigned int); + /* Print Front-End alarm (T1/E1/56K) */ + char* (*print_fe_act_channels)(void*); + /* Set Front-End alarm (T1/E1) */ + void (*set_fe_alarm)(void*,unsigned int); + /* Set extra interrupt type (after link get connected)) */ + int (*set_fe_sigcfg)(void*, unsigned int); +} sdla_fe_iface_t; +#endif + +/* +** Sangoma Front-End interface structure (new version) +** FIXME: replace sdla_fe_iface_t with the new version! */ +typedef struct { + int (*global_config)(void *fe); + int (*global_unconfig)(void *fe); + int (*config)(void *fe); + int (*unconfig)(void *fe); + int (*polling)(sdla_fe_t *fe); + int (*isr)(sdla_fe_t *fe); + int (*process_udp)(sdla_fe_t *fe, void*, unsigned char*); + unsigned int (*read_alarm)(sdla_fe_t *fe, int); + int (*read_pmon)(sdla_fe_t *fe, int); + int (*flush_pmon)(sdla_fe_t *fe); + /* Set Front-End alarm (T1/E1) */ + int (*set_fe_alarm)(sdla_fe_t *fe, unsigned int); + /* Set extra interrupt type (after link get connected)) */ + int (*set_fe_sigctrl)(sdla_fe_t*, int); + /* Print Front-End alarm (T1/E1/56K) */ + char* (*print_fe_act_channels)(sdla_fe_t*); + /* Print Front-End alarm (T1/E1/56K) */ + int (*print_fe_alarm)(sdla_fe_t*,unsigned int); + /* Get front end status */ + int (*get_fe_status)(sdla_fe_t *fe, unsigned char*); + /* Get front end media type */ + unsigned char (*get_fe_media)(sdla_fe_t *fe); + /* Get front end media type string */ + char* (*get_fe_media_string)(void); + /* Set Line-loopback modes */ + int (*set_fe_lbmode)(sdla_fe_t*, unsigned char, unsigned char); + /* Update Alarm Status for proc file system */ + int (*update_alarm_info)(sdla_fe_t*, struct seq_file* m, int* stop_cnt); + /* Update PMON Status for proc file system */ + int (*update_pmon_info)(sdla_fe_t*, struct seq_file* m, int* stop_cnt); + /* AFT T1/E1 cards only */ + int (*led_ctrl)(sdla_fe_t*, int mode); + /* Check RBS bits (T1/E1 cards) */ + int (*check_rbsbits)(sdla_fe_t*, int, unsigned int, int); + /* Read RBS bits (T1/E1 cards) */ + unsigned char (*read_rbsbits)(sdla_fe_t*, int, int); + /* Set RBS bits (T1/E1 cards, voice) */ + int (*set_rbsbits)(sdla_fe_t*, int, unsigned char); + /* Report RBS bits (T1/E1 cards) */ + int (*report_rbsbits)(sdla_fe_t*); + /* Get Front-End SNMP data */ + int (*get_snmp_data)(sdla_fe_t*, void*, void*); + /* Check if the interrupt is for this port */ + int (*check_isr)(sdla_fe_t *fe); +#if defined(__WINDOWS__) + /* Enable TE1 poll timer (WINDOWS ONLY) */ + void (*enable_timer)(sdla_fe_t*, unsigned char, unsigned int); +#endif + /* Set extra T1/E1 configuration */ + int (*post_config)(sdla_fe_t*); + /* Available front-end map */ + unsigned int (*active_map)(sdla_fe_t *fe); + /* Transmit DTMF number */ + int (*set_dtmf)(sdla_fe_t*, int, unsigned char); + /* Enable/Disable FE interrupt */ + int (*intr_ctrl)(sdla_fe_t*, int, int, int, unsigned int); + /* Event Control */ + int (*event_ctrl)(sdla_fe_t*, wan_event_ctrl_t*); +} sdla_fe_iface_t; + +/* +** Sangoma Front-End interface structure (new version) +** FIXME: replace sdla_fe_iface_t with the new version! */ +typedef struct { + + int (*check_hook_state)(sdla_fe_t *, int); + int (*hook_state)(sdla_fe_t *, int, int); + +} sdla_fe_notify_iface_t; + +#endif /* WAN_KERNEL */ + +#endif diff -Nur linux.org/include/linux/sdla_hdlc.h linux-2.6.17/include/linux/sdla_hdlc.h --- linux.org/include/linux/sdla_hdlc.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/sdla_hdlc.h 2006-08-30 10:07:15.000000000 +0000 @@ -0,0 +1,762 @@ +/***************************************************************************** +* sdla_hdlc.h HDLC API header file. +* +* Author: Jaspreet Singh +* +* Copyright: (c) 1998-1997 Sangoma Technologies Inc. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version +* 2 of the License, or (at your option) any later version. +* ============================================================================ +* Oct 14, 1998 Jaspreet Singh o Initial Version. +*****************************************************************************/ + +#ifdef _GNUC_ +# ifndef PACKED +# define PACKED __attribute__((packed)) +# endif /* PACKED */ +#else +# define PACKED +#endif +#ifdef _MSC_ +# pragma pack(1) +#endif + + +/* Status flag for determining whether to perform a check on socket receive * queue. + */ +#define NO_SK_RX_CHECK 0x00 +#define TOP_CHECK_SK_RX_Q 0x01 +#define BTM_CHECK_SK_RX_Q 0x02 + + +#define NO_READ_CMD 0x00 +#define READ_CMD 0x01 + + + + + +/* + * Constants defining the shared memory control block (mailbox) + */ + +/* the base address of the HDLC mailbox structure on the adapter */ +#define HDLC_MB_STRUCT_OFFSET 0x0000 +/* the number of reserved bytes in the mailbox header area */ +#define NUMBER_HDLC_MB_RES_BYTES 0x0A +/* the size of the actual mailbox data area */ +#define SIZEOF_HDLC_MB_DATA_BFR 1008 +#define MAX_NO_DATA_BYTES_IN_I_FRAME 4099 /* maximum length of the HDLC I-field */ + +/* Just the header, excluding the data area */ +#define MAILBOX_SIZE 30 +/* + * the control block mailbox structure for API purposes. + */ +typedef struct { + + unsigned char opp_flag PACKED; /* the opp flag */ + unsigned char command PACKED; /* the command code */ + unsigned short buffer_length PACKED; /* the data length */ + unsigned char return_code PACKED; /* the return code */ + unsigned char PF_bit PACKED; /* the HDLC P/F bit */ + char MB_reserved[NUMBER_HDLC_MB_RES_BYTES] PACKED; /* for later use */ + char data[MAX_NO_DATA_BYTES_IN_I_FRAME] PACKED; /* the data area */ + +} HDLC_MAILBOX_STRUCT; + + +/* The following structure definition is for driver use ONLY */ + +typedef struct { + + unsigned char opp_flag PACKED; /* the opp flag */ + unsigned char command PACKED; /* the command code */ + unsigned short buffer_length PACKED; /* the data length */ + unsigned char return_code PACKED; /* the return code */ + unsigned char PF_bit PACKED; /* the HDLC P/F bit */ + char MB_reserved[NUMBER_HDLC_MB_RES_BYTES] PACKED; /* for later use */ + char data[SIZEOF_HDLC_MB_DATA_BFR] PACKED; /* the data area */ + +} TRUE_HDLC_MAILBOX_STRUCT; + + +typedef struct { + pid_t pid_num PACKED; + HDLC_MAILBOX_STRUCT cmdarea PACKED; + +} CMDBLOCK_STRUCT; + +/* + * Interface commands + */ + +/* + * global interface commands + */ + +#define READ_GLOBAL_EXCEPTION_CONDITION 0x01 /* read a global exception condition from the adapter */ +#define SET_GLOBAL_CONFIGURATION 0x02 /* set the global operational configuration */ +#define READ_GLOBAL_CONFIGURATION 0x03 /* read the global configuration */ +#define READ_GLOBAL_STATISTICS 0x04 /* retrieve the global statistics */ +#define FLUSH_GLOBAL_STATISTICS 0x05 /* flush the global statistics */ +#define SET_MODEM_STATUS 0x06 /* set the status of DTR and/or RTS */ +#define READ_MODEM_STATUS 0x07 /* read the current status of CTS and DCD */ +#define READ_COMMS_ERROR_STATS 0x08 /* read the communication error statistics */ +#define FLUSH_COMMS_ERROR_STATS 0x09 /* flush the communication error statistics */ +#define SET_TRACE_CONFIGURATION 0x0A /* set the line trace configuration */ +#define READ_TRACE_CONFIGURATION 0x0B /* read the line trace configuration */ +#define READ_TRACE_STATISTICS 0x0C /* read the trace statistics */ +#define FLUSH_TRACE_STATISTICS 0x0D /* flush the trace statistics */ +#define FT1_MONITOR_STATUS_CTRL 0x1E /* set the status of the S508/FT1 monitoring */ +#define SET_FT1_MODE 0x1F /* set the operational mode of the S508/FT1 module */ + +/* + * HDLC-level interface commands + */ + +#define READ_HDLC_CODE_VERSION 0x20 /* read the HDLC code version */ +#define READ_HDLC_EXCEPTION_CONDITION 0x21 /* read an HDLC exception condition from the adapter */ +#define SET_HDLC_CONFIGURATION 0x22 /* set the HDLC operational configuration */ +#define READ_HDLC_CONFIGURATION 0x23 /* read the current HDLC operational configuration */ +#define ENABLE_HDLC_COMMUNICATIONS 0x24 /* enable HDLC communications */ +#define DISABLE_HDLC_COMMUNICATIONS 0x25 /* disable HDLC communications */ +#define HDLC_CONNECT 0x26 /* enter the HDLC ABM state */ +#define HDLC_DISCONNECT 0x27 /* enter the HDLC disconnected state */ +#define READ_HDLC_LINK_STATUS 0x28 /* read the HDLC link status */ +#define READ_HDLC_OPERATIONAL_STATS 0x29 /* retrieve the HDLC operational statistics */ +#define FLUSH_HDLC_OPERATIONAL_STATS 0x2A /* flush the HDLC operational statistics */ +#define SET_HDLC_BUSY_CONDITION 0x2B /* force the HDLC code into a busy condition */ +#define SEND_UI_FRAME 0x2C /* transmit an Unnumbered Information frame */ +#define SET_HDLC_INTERRUPT_TRIGGERS 0x30 /* set the HDLC application interrupt triggers */ +#define READ_HDLC_INTERRUPT_TRIGGERS 0x31 /* read the HDLC application interrupt trigger configuration */ + + +#define HDLC_SEND_NO_WAIT 0xE0 /* send I frames : Poll */ +#define HDLC_SEND_WAIT 0xE1 /* send I frames : Interrupt*/ +#define HDLC_READ_NO_WAIT 0xE2 /* receive I frames : Poll */ +#define HDLC_READ_WAIT 0xE3 /* receive I frames : Interrupt*/ +#define HDLC_READ_TRACE_DATA 0xE4 /* receive Trace data */ + + +/* + * Return codes from interface commands + */ + +#define OK 0x00 /* the interface command was successfull */ + +/* + * return codes from global interface commands + */ + +#define NO_GLOBAL_EXCEP_COND_TO_REPORT 0x01 /* there is no HDLC exception condition to report */ +#define LGTH_GLOBAL_CFG_DATA_INVALID 0x01 /* the length of the passed global configuration data is invalid */ +#define LGTH_TRACE_CFG_DATA_INVALID 0x01 /* the length of the passed trace configuration data is invalid */ +#define IRQ_TIMEOUT_VALUE_INVALID 0x02 /* an invalid application IRQ timeout value was selected */ +#define TRACE_CONFIG_INVALID 0x02 /* the passed line trace configuration is invalid */ +#define ADAPTER_OPERATING_FREQ_INVALID 0x03 /* an invalid adapter operating frequency was selected */ +#define TRC_DEAC_TMR_INVALID 0x03 /* the trace deactivation timer is invalid */ +#define S508_FT1_ADPTR_NOT_PRESENT 0x0E /* the S508/FT1 adapter is not present */ +#define S508_FT1_MODE_SELECTION_BUSY 0x0F /* the S508/FT1 adapter is busy selecting the operational mode */ + +/* + * return codes from command READ_GLOBAL_EXCEPTION_CONDITION + */ +#define EXCEP_MODEM_STATUS_CHANGE 0x10 /* a modem status change occurred */ +#define EXCEP_TRC_DISABLED 0x11 /* the trace has been disabled */ + +/* + * return codes from HDLC-level interface commands + */ +#define NO_HDLC_EXCEP_COND_TO_REPORT 0x21 /* there is no HDLC exception condition to report */ +#define HDLC_COMMS_DISABLED 0x21 /* communications are not currently enabled */ +#define HDLC_COMMS_ENABLED 0x21 /* communications are currently enabled */ +#define DISABLE_HDLC_COMMS_BEFORE_CFG 0x21 /* HDLC communications must be disabled before setting the configuration */ +#define ENABLE_HDLC_COMMS_BEFORE_CONN 0x21 /* communications must be enabled before using the HDLC_CONNECT conmmand */ +#define HDLC_CFG_BEFORE_COMMS_ENABLED 0x22 /* perform a SET_HDLC_CONFIGURATION before enabling comms */ +#define SET_TRACE_CFG 0x22 /* perform a SET_TRACE_CONFIGURATION */ +#define LGTH_HDLC_CFG_DATA_INVALID 0x22 /* the length of the passed HDLC configuration data is invalid */ +#define LGTH_HDLC_INT_DATA_INVALID 0x22 /* the length of the passed interrupt trigger data is invalid */ +#define HDLC_LINK_NOT_IN_ABM 0x22 /* the HDLC link is not currently in the ABM */ +#define HDLC_LINK_CURRENTLY_IN_ABM 0x22 /* the HDLC link is currently in the ABM */ +#define NO_TX_BFRS_AVAILABLE 0x23 /* no buffers available for transmission */ +#define INVALID_HDLC_APP_IRQ_SELECTED 0x23 /* in invalid IRQ was selected in the SET_HDLC_INTERRUPT_TRIGGERS */ +#define INVALID_HDLC_CFG_DATA 0x23 /* the passed HDLC configuration data is invalid */ +#define UI_FRM_TX_BFR_IN_USE 0x23 /* the buffer used for UI frame transmission is currently in use */ +#define T3_LESS_THAN_T1 0x24 /* the configured T3 value is less than T1 */ +#define HDLC_IRQ_TMR_VALUE_INVALID 0x24 /* an invalid application IRQ timer value was selected */ +#define UI_FRM_TX_LGTH_INVALID 0x24 /* the length of the UI frame to be transmitted is invalid */ +#define T4_LESS_THAN_T1 0x25 /* the configured T4 value is less than T1 */ +#define BFR_LGTH_EXCESSIVE_FOR_BFR_CFG 0x26 /* the configured buffer length is excessive for the configuration */ +#define INVALID_HDLC_COMMAND 0x4F /* the defined HDLC interface command is invalid */ + +/* + * return codes from command READ_HDLC_EXCEPTION_CONDITION + */ +#define EXCEP_SABM_RX 0x30 /* a SABM frame was recvd in the ABM */ +#define EXCEP_DISC_RX 0x31 /* a DISC frame was recvd in the ABM */ +#define EXCEP_DM_RX 0x32 /* a DM frame was recvd in the ABM */ +#define EXCEP_UA_RX 0x33 /* a UA frame was recvd in the ABM */ +#define EXCEP_FRMR_RX 0x34 /* a FRMR frame was recvd in the ABM */ +#define EXCEP_UI_RX 0x37 /* a UI frame was received */ +#define EXCEP_SABM_TX_DM_RX 0x38 /* a SABM frame was transmitted due to the reception of a DM */ +#define EXCEP_SABM_TX_UA_RX 0x39 /* a SABM frame was transmitted due to the reception of a UA */ +/* while the link was in the ABM */ +#define EXCEP_SABM_TX_FRMR_RX 0x3A /* a SABM frame was transmitted due to the reception of a FRMR */ +/* while the link was in the ABM */ +#define EXCEP_SABM_TX_UNSOLIC_RESP_RX 0x3B /* a SABM frame was transmitted due to the reception of an */ +/* unsolicited response with the F bit set */ +#define EXCEP_SABM_TX_N2_EXPIRY 0x3C /* a SABM frame was transmitted due to an N2 count expiry */ +#define EXCEP_FRMR_TX 0x3F /* a FRMR frame was transmitted */ +#define EXCEP_SABM_RETRY_LIM_EXCEEDED 0x40 /* the SABM retry limit was exceeded */ +#define EXCEP_DISC_RETRY_LIM_EXCEEDED 0x41 /* the DISC retry limit was exceeded */ +#define EXCEP_FRMR_RETRY_LIM_EXCEEDED 0x42 /* the FRMR retry limit was exceeded */ +#define EXCEP_T3_TIMEOUT_EXCEEDED 0x45 /* the T3 timeout limit has been exceeded */ + +#define NO_TRACE_BUFFERS 0x60 /* No trace buffers are avail */ +#define TRACE_BUFFER_TOO_BIG 0x61 +#define TRACE_BUFFER_NOT_STORED 0x62 + +/* + * Constants for the SET_GLOBAL_CONFIGURATION/READ_GLOBAL_CONFIGURATION + * commands + */ + +/* + * the global configuration structure + */ +typedef struct { + + unsigned short adapter_config_options; /* configuration options */ + unsigned short app_IRQ_timeout; /* application IRQ timeout */ + unsigned long adapter_operating_frequency; /* operating frequency*/ + +} GLOBAL_CONFIGURATION_STRUCT; + +/* settings for the 'app_IRQ_timeout' */ +#define MAX_APP_IRQ_TIMEOUT_VALUE 5000 /* the maximum permitted IRQ + timeout */ + + + +/* + * Constants for the READ_GLOBAL_STATISTICS command + */ + +/* + * the global statistics structure + */ +typedef struct { + + unsigned short app_IRQ_timeout_count; + +} GLOBAL_STATS_STRUCT; + + + +/* + * Constants for the READ_COMMS_ERROR_STATS command + */ + +/* + * the communications error statistics structure + */ + +typedef struct { + + unsigned char Rx_overrun_err_count; /* receiver overrun error count */ + unsigned char CRC_err_count; /* receiver CRC error count */ + unsigned char Rx_abort_count; /* abort frames received count */ + unsigned char Rx_dis_pri_bfrs_full_count; /* receiver disabled count */ + unsigned char comms_err_stat_reserved_1; /* reserved for later use */ + unsigned char comms_err_stat_reserved_2; /* reserved for later use */ + unsigned char missed_Tx_und_int_count;/* missed tx underrun intr count*/ + unsigned char comms_err_stat_reserved_3; /* reserved for later use */ + unsigned char DCD_state_change_count; /* DCD state change count */ + unsigned char CTS_state_change_count; /* CTS state change count */ + +} COMMS_ERROR_STATS_STRUCT; + + + + +/* + * Constants used for line tracing + */ + +/* + * the trace configuration structure (SET_TRACE_CONFIGURATION/ + * READ_TRACE_CONFIGURATION commands) + */ + +typedef struct { + + unsigned char trace_config PACKED; /* trace configuration */ + unsigned short trace_deactivation_timer PACKED; /* trace deactivation timer */ + unsigned long ptr_trace_stat_el_cfg_struct PACKED; /* a pointer to the line trace element configuration structure */ + +} LINE_TRACE_CONFIG_STRUCT; + +/* 'trace_config' bit settings */ +#define TRACE_INACTIVE 0x00 /* trace is inactive */ +#define TRACE_ACTIVE 0x01 /* trace is active */ +#define TRACE_DELAY_MODE 0x04 /* operate the trace in the + delay mode */ +#define TRACE_I_FRAMES 0x08 /* trace I-frames */ +#define TRACE_SUPERVISORY_FRAMES 0x10 /* trace Supervisory frames */ +#define TRACE_UNNUMBERED_FRAMES 0x20 /* trace Unnumbered frames */ + +/* + * the line trace status element configuration structure + */ + +typedef struct { + + unsigned short number_trace_status_elements PACKED; /* number of line trace elements */ + unsigned long base_addr_trace_status_elements PACKED;/* base address of the trace element list */ + unsigned long next_trace_element_to_use PACKED; /* pointer to the next trace element to be used */ + unsigned long base_addr_trace_buffer PACKED; /* base address of the trace data buffer */ + unsigned long end_addr_trace_buffer PACKED; /* end address of the trace data buffer */ + +} TRACE_STATUS_EL_CFG_STRUCT; + +/* + * the line trace status element structure + */ + +typedef struct { + + unsigned char opp_flag PACKED; /* opp flag */ + unsigned short trace_length PACKED; /* trace length */ + unsigned char trace_type PACKED; /* trace type */ + unsigned short trace_time_stamp PACKED;/* time stamp */ + unsigned short trace_reserved_1 PACKED;/* reserved for later use */ + unsigned long trace_reserved_2 PACKED; /* reserved for later use */ + unsigned long ptr_data_bfr PACKED; /* pointer to the trace data buffer */ + +} TRACE_STATUS_ELEMENT_STRUCT; + +/* + * the line trace statistics structure + */ + +typedef struct { + + unsigned long frames_traced_count; /* number of frames traced*/ + unsigned long trc_frms_not_recorded_count; /* number of trace frames + discarded */ + unsigned short trc_disabled_internally_count; /* number of times the + trace was disabled + internally */ + +} LINE_TRACE_STATS_STRUCT; + + + +/* + * Constants for the SET_HDLC_CONFIGURATION command + */ + +/* + * the HDLC configuration structure + */ + +typedef struct { + + unsigned long baud_rate PACKED; /* the baud rate */ + unsigned short line_config_options PACKED; /* line configuration options */ + unsigned short modem_config_options PACKED; /* modem configuration options */ + unsigned short HDLC_API_options PACKED; /* HDLC API options */ + unsigned short HDLC_protocol_options PACKED; /* HDLC protocol options */ + unsigned short HDLC_buffer_config_options PACKED; /* HDLC buffer configuration options */ + unsigned short HDLC_statistics_options PACKED; /* HDLC operational statistics options */ + unsigned short configured_as_DTE PACKED; /* DTE or DCE configuration */ + unsigned short max_HDLC_I_field_length PACKED; /* the maximum length of the HDLC I-field */ + unsigned short HDLC_I_frame_window PACKED; /* k - the I-frame window (maximum number of outstanding I-frames) */ + unsigned short HDLC_T1_timer PACKED; /* the HDLC T1 timer */ + unsigned short HDLC_T2_timer PACKED; /* the HDLC T2 timer */ + unsigned short HDLC_T3_timer PACKED; /* the HDLC T3 timer */ + unsigned short HDLC_T4_timer PACKED; /* the HDLC T4 timer */ + unsigned short HDLC_N2_counter PACKED; /* the HDLC N2 counter */ + unsigned long ptr_shared_mem_info_struct PACKED;/* a pointer to the shared memory area information structure */ + unsigned long ptr_HDLC_Tx_stat_el_cfg_struct PACKED;/* a pointer to the transmit status element configuration structure */ + unsigned long ptr_HDLC_Rx_stat_el_cfg_struct PACKED;/* a pointer to the receive status element configuration structure */ + +} HDLC_CONFIGURATION_STRUCT; + +/* settings for the 'line_config_options' */ +#define INTERFACE_LEVEL_V35 0x0000 /* use V.35 interface level */ +#define INTERFACE_LEVEL_RS232 0x0001 /* use RS-232 interface level */ + +/* settings for the 'modem_config_options' */ +#define DONT_RAISE_DTR_RTS_ON_EN_COMMS 0x0001 /* don't automatically raise DTR and RTS when performing an */ + +/* ENABLE_HDLC_COMMUNICATIONS command */ + +#define DONT_REPORT_CHG_IN_MODEM_STAT 0x0002 /* don't report changes in modem status to the application */ +#define DISABLE_DCD_CTS_INTERRUPTS 0x0004 /* ignore DCD and CTS interrupts on the adapter */ + +/* bit settings for the 'HDLC_API_options' */ +#define PERMIT_HDLC_CONNECT_IN_ABM 0x0001 /* allow the use of the HDLC_CONNECT command while in the ABM */ + +/* bit settings for the 'HDLC_protocol_options' byte */ +#define MOD_8_SELECTED 0x0000 /* use modulo 8 operation */ +#define MOD_128_SELECTED 0x0001 /* use modulo 128 (extended) operation */ +#define AUTO_MODULO_DETECTION 0x0002 /* use automatic modulus detection */ +#define PASSIVE_LINK_SETUP 0x0004 /* no SABMs should be issued when setting up the link */ +#define ENTER_DISC_PHASE_AFTR_DISC_SNT 0x0008 /* enter the disconnnected phase after issuing a DISC command */ + +/* settings for the 'HDLC_buffer_config_options' */ +#define HDLC_I_FRM_RX_HYSTERESIS 0x000F /* the HDLC I-frame receive hysteresis */ +#define HDLC_I_FRM_BFRS_3rd_LVL_PROT 0x0010 /* the HDLC I-frame buffers are to be used by a 3rd level protocol */ + +/* settings for the 'HDLC_statistics_options' */ +#define HDLC_TX_I_FRM_BYTE_COUNT_STAT 0x0001 /* compute the number of I-frame bytes transmitted */ +#define HDLC_RX_I_FRM_BYTE_COUNT_STAT 0x0002 /* compute the number of I-frame bytes received */ +#define HDLC_TX_THROUGHPUT_STAT 0x0004 /* compute the I-frame transmit throughput */ +#define HDLC_RX_THROUGHPUT_STAT 0x0008 /* compute the I-frame receive throughput */ + +/* permitted minimum and maximum values for setting the HDLC configuration */ +#define MAX_BAUD_RATE 2666000 /* maximum baud rate */ +#define MIN_NO_DATA_BYTES_IN_I_FRAME 300 /* minimum length of the configured HDLC I-field */ +#define MIN_PERMITTED_k_VALUE 0 /* minimum I-frame window size */ +#define MAX_PERMITTED_k_VALUE 127 /* maximum I-frame window size */ +#define MIN_PERMITTED_T1_VALUE 1 /* minimum T1 */ +#define MAX_PERMITTED_T1_VALUE 60000 /* maximum T1 */ +#define MIN_PERMITTED_T2_VALUE 0 /* minimum T2 */ +#define MAX_PERMITTED_T2_VALUE 60000 /* maximum T2 */ +#define MIN_PERMITTED_T3_VALUE 0 /* minimum T3 */ +#define MAX_PERMITTED_T3_VALUE 60000 /* maximum T3 */ +#define MIN_PERMITTED_T4_VALUE 0 /* minimum T4 */ +#define MAX_PERMITTED_T4_VALUE 60000 /* maximum T4 */ +#define MIN_PERMITTED_N2_VALUE 1 /* minimum N2 */ +#define MAX_PERMITTED_N2_VALUE 30 /* maximum N2 */ + + +/* + * Constants for the READ_HDLC_LINK_STATUS command + */ + +/* + * the HDLC status structure + */ + +typedef struct { + + unsigned char HDLC_link_status; /* HDLC link status (disconnect/ABM) */ + unsigned char modulus_type; /* configured modulus type */ + unsigned char no_I_frms_for_app;/* number of I-frames available for the application */ + unsigned char receiver_status; /* receiver status (enabled/disabled) */ + unsigned char LAPB_state; /* internal LAPB state */ + unsigned char rotating_SUP_frm_count; /* count of Supervisory frames received */ + +} HDLC_LINK_STATUS_STRUCT; + +/* settings for the 'HDLC_link_status' variable */ +#define HDLC_LINK_DISCONNECTED 0x00 /* the HDLC link is disconnected */ +#define HDLC_LINK_IN_AB 0x01 /* the HDLC link is in the ABM (connected) */ + + + + +/* + * Constants for the READ_HDLC_OPERATIONAL_STATS command + */ + +/* + * the HDLC operational statistics structure + */ + +typedef struct { + + /* Information frame transmission statistics */ + unsigned long I_frames_Tx_ack_count; /* I-frames transmitted (and acknowledged) count */ + unsigned long I_bytes_Tx_ack_count; /* I-bytes transmitted (and acknowledged) count */ + unsigned long I_frm_Tx_throughput; /* I-frame transmit throughput */ + unsigned long no_ms_for_HDLC_Tx_thruput_comp;/* millisecond time used for Tx throughput computation */ + unsigned long I_frames_retransmitted_count; /* I-frames re-transmitted count */ + unsigned long I_bytes_retransmitted_count; /* I-bytes re-transmitted count */ + unsigned short I_frms_not_Tx_lgth_err_count; /* number of I-frames not transmitted (length error) */ + unsigned short Tx_I_frms_disc_st_chg_count; /* the number of I-frames discarded (change in the LAPB state) */ + unsigned long reserved_I_frm_Tx_stat; /* reserved for later use */ + + /* Information frame reception statistics */ + unsigned long I_frames_Rx_buffered_count; /* I-frames received (and buffered) count */ + unsigned long I_bytes_Rx_buffered_count; /* I-bytes received (and buffered) count */ + unsigned long I_frm_Rx_throughput; /* I-frame receive throughput */ + unsigned long no_ms_for_HDLC_Rx_thruput_comp;/* millisecond time used for Rx throughput computation */ + unsigned short I_frms_Rx_too_long_count; /* I-frames received of excessive length count */ + unsigned short I_frms_Rx_seq_err_count; /* out of sequence I-frames received count */ + unsigned long reserved_I_frm_Rx_stat1; /* reserved for later use */ + unsigned long reserved_I_frm_Rx_stat2; /* reserved for later use */ + unsigned long reserved_I_frm_Rx_stat3; /* reserved for later use */ + + /* Supervisory frame transmission/reception statistics */ + unsigned short RR_Tx_count; /* RR frames transmitted count */ + unsigned short RR_Rx_count; /* RR frames received count */ + unsigned short RNR_Tx_count; /* RNR frames transmitted count */ + unsigned short RNR_Rx_count; /* RNR frames received count */ + unsigned short REJ_Tx_count; /* REJ frames transmitted count */ + unsigned short REJ_Rx_count; /* REJ frames received count */ + + /* Unnumbered frame transmission/reception statistics */ + unsigned short SABM_Tx_count; /* SABM frames transmitted count */ + unsigned short SABM_Rx_count; /* SABM frames received count */ + unsigned short SABME_Tx_count; /* SABME frames transmitted count */ + unsigned short SABME_Rx_count; /* SABME frames received count */ + unsigned short DISC_Tx_count; /* DISC frames transmitted count */ + unsigned short DISC_Rx_count; /* DISC frames received count */ + unsigned short DM_Tx_count; /* DM frames transmitted count */ + unsigned short DM_Rx_count; /* DM frames received count */ + unsigned short UA_Tx_count; /* UA frames transmitted count */ + unsigned short UA_Rx_count; /* UA frames received count */ + unsigned short FRMR_Tx_count; /* FRMR frames transmitted count */ + unsigned short FRMR_Rx_count; /* FRMR frames received count */ + unsigned short UI_Tx_count; /* UI frames transmitted count */ + unsigned short UI_Rx_buffered_count;/* UI frames received and buffered count */ + unsigned long reserved_Sup_Unnum_stat1; /* reserved for later use */ + unsigned long reserved_Sup_Unnum_stat2; /* reserved for later use */ + + /* Incomming frames with a format error statistics */ + unsigned short Rx_frm_shorter_32_bits_count; /* frames received of less than 32 bits in length count */ + unsigned short Rx_I_fld_Sup_Unnum_frm_count; /* Supervisory/Unnumbered frames received with */ + + /* illegal I-fields count */ + unsigned short Rx_frms_invld_HDLC_addr_count;/* frames received with an invalid HDLC address count */ + unsigned short Rx_invld_HDLC_ctrl_fld_count; /* frames received of an invalid/unsupported */ + /* control field count */ + unsigned long reserved_frm_format_err1; /* reserved for later use */ + unsigned long reserved_frm_format_err2; /* reserved for later use */ + + /* FRMR/UI reception error statistics */ + unsigned short Rx_FRMR_frms_discard_count;/* incomming FRMR frames discarded count */ + unsigned short Rx_UI_frms_discard_count;/* incomming UI frames discarded count */ + unsigned short UI_frms_Rx_invld_lgth_count;/* UI frames of invalid length received count */ + unsigned short reserved_Rx_err_stat1; /* reserved for later use */ + unsigned long reserved_Rx_err_stat2; /* reserved for later use */ + unsigned long reserved_Rx_err_stat3; /* reserved for later use */ + + /* HDLC timeout/retry statistics */ + unsigned short T1_timeout_count; /* T1 timeouts count */ + unsigned short T3_timeout_count; /* T3 timeouts count */ + unsigned short T4_timeout_count; /* T4 timeouts count */ + unsigned short reserved_timeout_stat; /* reserved for later use */ + unsigned short N2_threshold_reached_count;/* N2 threshold reached count */ + unsigned short reserved_threshold_stat; /* reserved for later use */ + unsigned long To_retry_reserved_stat; /* reserved for later use */ + + /* miscellaneous statistics */ + unsigned long reserved_misc_stat1; /* reserved for later use */ + unsigned long reserved_misc_stat2; /* reserved for later use */ + unsigned long reserved_misc_stat3; /* reserved for later use */ + unsigned long reserved_misc_stat4; /* reserved for later use */ + +} HDLC_OPERATIONAL_STATS_STRUCT; + + + + +/* + * Constants for the SEND_UI_FRAME command + */ + +#define MAX_LENGTH_UI_DATA 512 /* maximum UI frame data length */ + +/* + * the structure used for UI frame transmission/reception + */ + +typedef struct { + unsigned char HDLC_address; /* HDLC address in the frame */ + unsigned char UI_reserved; /* reserved for internal use */ + char data[MAX_LENGTH_UI_DATA]; /* UI data area */ +} UI_FRAME_STRUCT; + + + + +/* + * Constants for using application interrupts + */ + +/* + * the structure used for the SET_HDLC_INTERRUPT_TRIGGERS/ + * READ_HDLC_INTERRUPT_TRIGGERS command + */ + +typedef struct { + + unsigned char HDLC_interrupt_triggers; /* HDLC interrupt trigger configuration */ + unsigned char IRQ; /* IRQ to be used */ + unsigned short interrupt_timer; /* interrupt timer */ + +} HDLC_INT_TRIGGERS_STRUCT; + +/* 'HDLC_interrupt_triggers' bit settings */ +#define APP_INT_ON_RX_FRAME 0x01 /* interrupt on I-frame reception */ +#define APP_INT_ON_TX_FRAME 0x02 /* interrupt when an I-frame may be transmitted */ +#define APP_INT_ON_COMMAND_COMPLETE 0x04 /* interrupt when an interface command is complete */ +#define APP_INT_ON_TIMER 0x08 /* interrupt on a defined millisecond timeout */ +#define APP_INT_ON_GLOBAL_EXCEP_COND 0x10 /* interrupt on a global exception condition */ +#define APP_INT_ON_HDLC_EXCEP_COND 0x20 /* interrupt on an HDLC exception condition */ +#define APP_INT_ON_TRACE_DATA_AVAIL 0x80 /* interrupt when trace data is available */ + + +/* + * the HDLC interrupt information structure + */ +typedef struct { + + unsigned char interrupt_type PACKED; /* type of interrupt triggered */ + unsigned char interrupt_permission PACKED; /* interrupt permission mask */ + unsigned char int_info_reserved[14] PACKED; /* reserved */ + +} HDLC_INTERRUPT_INFO_STRUCT; + +/* interrupt types indicated at 'interrupt_type' byte of the + HDLC_INTERRUPT_INFO_STRUCT */ +#define NO_APP_INTS_PEND 0x00 /* no interrups are pending */ +#define RX_APP_INT_PEND 0x01 /*receive interrupt is pending */ +#define TX_APP_INT_PEND 0x02 /* a transmit interrupt is pending */ +#define COMMAND_COMPLETE_APP_INT_PEND 0x04 /* a 'command complete' interrupt is pending */ +#define TIMER_APP_INT_PEND 0x08 /* a timer interrupt is pending */ +#define GLOBAL_EXCEP_COND_APP_INT_PEND 0x10 /* a global exception condition interrupt is pending */ +#define HDLC_EXCEP_COND_APP_INT_PEND 0x20 /* an HDLC exception condition interrupt is pending */ +#define TRACE_DATA_AVAIL_APP_INT_PEND 0x80 /* a trace data available interrupt is pending */ + + + +/* + * Constants for Information frame transmission + */ + +/* + * the I-frame transmit status element configuration structure + */ + +typedef struct { + + unsigned short number_Tx_status_elements PACKED; /* number of transmit status elements */ + unsigned long base_addr_Tx_status_elements PACKED; /* base address of the transmit element list */ + unsigned long next_Tx_status_element_to_use PACKED; /* pointer to the next transmit element to be used */ + +} HDLC_TX_STATUS_EL_CFG_STRUCT; + +/* + * the I-frame transmit status element structure + */ +typedef struct { + + unsigned char opp_flag PACKED; /* opp flag */ + unsigned short I_frame_length PACKED; /* length of the frame*/ + unsigned char P_bit PACKED; /* P-bit setting in the frame */ + unsigned long reserved_1 PACKED; /* reserved for internal use */ + unsigned long reserved_2 PACKED; /* reserved for internal use */ + unsigned long ptr_data_bfr PACKED; /* pointer to the data area */ + +} HDLC_I_FRM_TX_STATUS_EL_STRUCT; + + + +/* + * Constants for Information frame reception + */ + +/* + * the I-frame receive status element configuration structure + */ + +typedef struct { + + unsigned short number_Rx_status_elements PACKED; /* number of receive status elements */ + unsigned long base_addr_Rx_status_elements PACKED; /* base address of the receive element list */ + unsigned long next_Rx_status_element_to_use PACKED; /* pointer to the next receive element to be used */ + unsigned long base_addr_Rx_buffer PACKED; /* base address of the receive data buffer */ + unsigned long end_addr_Rx_buffer PACKED; /* end address of the receive data buffer */ +} HDLC_RX_STATUS_EL_CFG_STRUCT; + +/* + * the I-frame receive status element structure + */ +typedef struct { + + unsigned char opp_flag PACKED; /* opp flag */ + unsigned short I_frame_length PACKED; /*length of the recvd frame */ + unsigned char P_bit PACKED; /* P-bit setting in the frame */ + unsigned long reserved_1 PACKED; /* reserved for internal use */ + unsigned long reserved_2 PACKED; /* reserved for internal use */ + unsigned long ptr_data_bfr PACKED; /* pointer to the data area */ + +} HDLC_I_FRM_RX_STATUS_EL_STRUCT; + + + +/* + * Constants defining the shared memory information area + */ + + + +/* + * the global information structure + */ + +typedef struct { + + unsigned char global_status PACKED; /* global status */ + unsigned char modem_status PACKED;/* current modem status*/ + unsigned char global_excep_conditions PACKED; /* global exception conditions */ + unsigned char glob_info_reserved[5] PACKED; /* reserved */ + unsigned char code_name[4] PACKED; /* code name */ + unsigned char code_version[4] PACKED; /* code version */ + +} GLOBAL_INFORMATION_STRUCT; + + +/* + * the S508/FT1 information structure + */ + +typedef struct { + + unsigned char parallel_port_A_input PACKED; /* input - parallel port A */ + unsigned char parallel_port_B_input PACKED; /* input - parallel port B */ + unsigned char FT1_info_reserved[14] PACKED; /* reserved */ + +} FT1_INFORMATION_STRUCT; + +/* + * the HDLC information structure + */ + +typedef struct { + + unsigned char HDLC_status PACKED; /* HDLC status */ + unsigned char HDLC_excep_frms_Rx PACKED; /* HDLC exception conditions - received frames */ + unsigned char HDLC_excep_frms_Tx PACKED; /* HDLC exception conditions - transmitted frames */ + unsigned char HDLC_excep_miscellaneous PACKED; /* HDLC exception conditions - miscellaneous */ + unsigned char rotating_SUP_frm_count PACKED; /* rotating Supervisory frame count */ + unsigned char LAPB_status PACKED; /* internal LAPB status */ + unsigned char internal_HDLC_status PACKED; /* internal HDLC status */ + unsigned char HDLC_info_reserved[9] PACKED; /* reserved */ + +} HDLC_INFORMATION_STRUCT; + + + + +/* + * the HDLC shared memory area information structure + */ + +typedef struct { + + GLOBAL_INFORMATION_STRUCT global_info PACKED; /* the global information structure */ + FT1_INFORMATION_STRUCT FT1_info PACKED; /* the S508/FT1 information structure */ + HDLC_INFORMATION_STRUCT HDLC_info PACKED; /* the HDLC information structure */ + HDLC_INTERRUPT_INFO_STRUCT HDLC_interrupt_info PACKED; /* the HDLC interrupt information structure */ + +} HDLC_SHARED_MEMORY_INFO_STRUCT; diff -Nur linux.org/include/linux/sdla_mp_fr.h linux-2.6.17/include/linux/sdla_mp_fr.h --- linux.org/include/linux/sdla_mp_fr.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/sdla_mp_fr.h 2006-08-30 10:07:15.000000000 +0000 @@ -0,0 +1,276 @@ +#ifndef __WANPIPE_MFR__ +#define __WANPIPE_MFR__ + +#define HDLC_PROT_ONLY +#include +#include + + +#undef wan_udphdr_data +#define wan_udphdr_data wan_udphdr_u.data + +#undef wan_udp_data +#define wan_udp_data wan_udp_hdr.wan_udphdr_data + +#undef MAX_FR_CHANNELS +#undef HIGHEST_VALID_DLCI + +#define MAX_FR_CHANNELS 1023 +#define HIGHEST_VALID_DLCI MAX_FR_CHANNELS-1 + +typedef struct { + unsigned ea1 : 1; + unsigned cr : 1; + unsigned dlcih: 6; + + unsigned ea2 : 1; + unsigned de : 1; + unsigned becn : 1; + unsigned fecn : 1; + unsigned dlcil: 4; +}__attribute__ ((packed)) fr_hdr; + + +#define FR_HEADER_LEN 8 + +#define LINK_STATE_RELIABLE 0x01 +#define LINK_STATE_REQUEST 0x02 /* full stat sent (DCE) / req pending (DTE) */ +#define LINK_STATE_CHANGED 0x04 /* change in PVCs state, send full report */ +#define LINK_STATE_FULLREP_SENT 0x08 /* full report sent */ + +#define FR_UI 0x03 +#define FR_PAD 0x00 + +#define NLPID_IP 0xCC +#define NLPID_IPV6 0x8E +#define NLPID_SNAP 0x80 +#define NLPID_PAD 0x00 +#define NLPID_Q933 0x08 + + + +/* 'status' defines */ +#define FR_LINK_INOPER 0x00 /* for global status (DLCI == 0) */ +#define FR_LINK_OPER 0x01 + +#if 0 +#define FR_DLCI_INOPER 0x00 +#define FR_DLCI_DELETED 0x01 /* for circuit status (DLCI != 0) */ +#define FR_DLCI_ACTIVE 0x02 +#define FR_DLCI_WAITING 0x04 +#define FR_DLCI_NEW 0x08 +#define FR_DLCI_REPORT 0x40 +#endif + +#define PVC_STATE_NEW 0x01 +#define PVC_STATE_ACTIVE 0x02 +#define PVC_STATE_FECN 0x08 /* FECN condition */ +#define PVC_STATE_BECN 0x10 /* BECN condition */ + + +#define LMI_ANSI_DLCI 0 +#define LMI_LMI_DLCI 1023 + +#define LMI_PROTO 0x08 +#define LMI_CALLREF 0x00 /* Call Reference */ +#define LMI_ANSI_LOCKSHIFT 0x95 /* ANSI lockshift */ +#define LMI_REPTYPE 1 /* report type */ +#define LMI_CCITT_REPTYPE 0x51 +#define LMI_ALIVE 3 /* keep alive */ +#define LMI_CCITT_ALIVE 0x53 +#define LMI_PVCSTAT 7 /* pvc status */ +#define LMI_CCITT_PVCSTAT 0x57 +#define LMI_FULLREP 0 /* full report */ +#define LMI_INTEGRITY 1 /* link integrity report */ +#define LMI_SINGLE 2 /* single pvc report */ +#define LMI_STATUS_ENQUIRY 0x75 +#define LMI_STATUS 0x7D /* reply */ + +#define LMI_REPT_LEN 1 /* report type element length */ +#define LMI_INTEG_LEN 2 /* link integrity element length */ + +#define LMI_LENGTH 13 /* standard LMI frame length */ +#define LMI_ANSI_LENGTH 14 + +#define HDLC_MAX_MTU 1500 /* Ethernet 1500 bytes */ +#define HDLC_MAX_MRU (HDLC_MAX_MTU + 10) /* max 10 bytes for FR */ + +#define MAX_TRACE_QUEUE 100 +#define TRACE_QUEUE_LIMIT 1001 +#define MAX_TRACE_TIMEOUT (HZ*10) + +static __inline__ u16 status_to_dlci(u8 *status, u8 *state) +{ + *state &= ~(PVC_STATE_ACTIVE | PVC_STATE_NEW); + if (status[2] & 0x08) + *state |= PVC_STATE_NEW; + else if (status[2] & 0x02) + *state |= PVC_STATE_ACTIVE; + + return ((status[0] & 0x3F)<<4) | ((status[1] & 0x78)>>3); +} + + + +static __inline__ u16 q922_to_dlci(u8 *hdr) +{ + return ((hdr[0] & 0xFC)<<2) | ((hdr[1] & 0xF0)>>4); +} + + +static inline u8 fr_lmi_nextseq(u8 x) +{ + x++; + return x ? x : 1; +} + +static __inline__ void dlci_to_q922(u8 *hdr, u16 dlci) +{ + hdr[0] = (dlci>>2) & 0xFC; + hdr[1] = ((dlci<<4) & 0xF0) | 0x01; +} + + + +#if 0 +/* Special UDP drivers management commands */ +#define FPIPE_ENABLE_TRACING 0x41 +#define FPIPE_DISABLE_TRACING 0x42 +#define FPIPE_GET_TRACE_INFO 0x43 +#define FPIPE_FT1_READ_STATUS 0x44 +#define FPIPE_DRIVER_STAT_IFSEND 0x45 +#define FPIPE_DRIVER_STAT_INTR 0x46 +#define FPIPE_DRIVER_STAT_GEN 0x47 +#define FPIPE_FLUSH_DRIVER_STATS 0x48 +#define FPIPE_ROUTER_UP_TIME 0x49 +#define FPIPE_TE1_56K_STAT 0x50 /* TE1_56K */ +#define FPIPE_GET_MEDIA_TYPE 0x51 /* TE1_56K */ +#define FPIPE_FLUSH_TE1_PMON 0x52 /* TE1 */ +#define FPIPE_READ_REGISTER 0x53 /* TE1_56K */ +#define FPIPE_TE1_CFG 0x54 /* TE1 */ + + +/* UDP management packet layout (data area of ip packet) */ + +typedef struct { + unsigned char control PACKED; + unsigned char NLPID PACKED; +} fr_encap_hdr_t; + +typedef struct { + ip_pkt_t ip_pkt PACKED; + udp_pkt_t udp_pkt PACKED; + wp_mgmt_t wp_mgmt PACKED; + cblock_t cblock PACKED; + unsigned char data[4080] PACKED; +} fr_udp_pkt_t; + + +/*---------------------------------------------------------------------------- + * Global Statistics Block. + * This structure is returned by the FR_READ_STATISTICS command when + * dcli == 0. + */ +typedef struct fr_link_stat +{ + unsigned short rx_too_long PACKED; /* 00h: */ + unsigned short rx_dropped PACKED; /* 02h: */ + unsigned short rx_dropped2 PACKED; /* 04h: */ + unsigned short rx_bad_dlci PACKED; /* 06h: */ + unsigned short rx_bad_format PACKED; /* 08h: */ + unsigned short retransmitted PACKED; /* 0Ah: */ + unsigned short cpe_tx_FSE PACKED; /* 0Ch: */ + unsigned short cpe_tx_LIV PACKED; /* 0Eh: */ + unsigned short cpe_rx_FSR PACKED; /* 10h: */ + unsigned short cpe_rx_LIV PACKED; /* 12h: */ + unsigned short node_rx_FSE PACKED; /* 14h: */ + unsigned short node_rx_LIV PACKED; /* 16h: */ + unsigned short node_tx_FSR PACKED; /* 18h: */ + unsigned short node_tx_LIV PACKED; /* 1Ah: */ + unsigned short rx_ISF_err PACKED; /* 1Ch: */ + unsigned short rx_unsolicited PACKED; /* 1Eh: */ + unsigned short rx_SSN_err PACKED; /* 20h: */ + unsigned short rx_RSN_err PACKED; /* 22h: */ + unsigned short T391_timeouts PACKED; /* 24h: */ + unsigned short T392_timeouts PACKED; /* 26h: */ + unsigned short N392_reached PACKED; /* 28h: */ + unsigned short cpe_SSN_RSN PACKED; /* 2Ah: */ + unsigned short current_SSN PACKED; /* 2Ch: */ + unsigned short current_RSN PACKED; /* 2Eh: */ + unsigned short curreny_T391 PACKED; /* 30h: */ + unsigned short current_T392 PACKED; /* 32h: */ + unsigned short current_N392 PACKED; /* 34h: */ + unsigned short current_N393 PACKED; /* 36h: */ +} fr_link_stat_t; + +/*---------------------------------------------------------------------------- + * DLCI statistics. + * This structure is returned by the FR_READ_STATISTICS command when + * dlci != 0. + */ +typedef struct fr_dlci_stat +{ + unsigned long tx_frames PACKED; /* 00h: */ + unsigned long tx_bytes PACKED; /* 04h: */ + unsigned long rx_frames PACKED; /* 08h: */ + unsigned long rx_bytes PACKED; /* 0Ch: */ + unsigned long rx_dropped PACKED; /* 10h: */ + unsigned long rx_inactive PACKED; /* 14h: */ + unsigned long rx_exceed_CIR PACKED; /* 18h: */ + unsigned long rx_DE_set PACKED; /* 1Ch: */ + unsigned long tx_throughput PACKED; /* 20h: */ + unsigned long tx_calc_timer PACKED; /* 24h: */ + unsigned long rx_throughput PACKED; /* 28h: */ + unsigned long rx_calc_timer PACKED; /* 2Ch: */ +} fr_dlci_stat_t; + +/*---------------------------------------------------------------------------- + * Communications error statistics. + * This structure is returned by the FR_READ_ERROR_STATS command. + */ +typedef struct fr_comm_stat +{ + unsigned char rx_overruns PACKED; /* 00h: */ + unsigned char rx_bad_crc PACKED; /* 01h: */ + unsigned char rx_aborts PACKED; /* 02h: */ + unsigned char rx_too_long PACKED; /* 03h: */ + unsigned char tx_aborts PACKED; /* 04h: */ + unsigned char tx_underruns PACKED; /* 05h: */ + unsigned char tx_missed_undr PACKED; /* 06h: */ + unsigned char dcd_dropped PACKED; /* 07h: */ + unsigned char cts_dropped PACKED; /* 08h: */ +} fr_comm_stat_t; + +#endif + +typedef struct { + + struct tasklet_struct wanpipe_task; + unsigned long tq_working; + netdevice_t *dlci_to_dev_map[MAX_FR_CHANNELS]; + unsigned char global_dlci_map[MAX_FR_CHANNELS]; + wan_fr_conf_t cfg; + unsigned char station; + struct sk_buff_head rx_free; + struct sk_buff_head rx_used; + struct sk_buff_head lmi_queue; + struct sk_buff_head trace_queue; + unsigned long last_rx_poll; + unsigned int txseq, rxseq; + unsigned char state; + unsigned long n391cnt; + unsigned int last_errors; + struct timer_list timer; + unsigned short lmi_dlci; + netdevice_t *tx_dev; + + fr_link_stat_t link_stats; + void *update_dlci; + unsigned long tracing_enabled; + int max_trace_queue; + unsigned long trace_timeout; + + unsigned int max_rx_queue; +} fr_prot_t; + +#endif diff -Nur linux.org/include/linux/sdlapci.h linux-2.6.17/include/linux/sdlapci.h --- linux.org/include/linux/sdlapci.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/sdlapci.h 2006-08-30 10:07:15.000000000 +0000 @@ -0,0 +1,144 @@ +/***************************************************************************** +* sdlapci.h WANPIPE(tm) Multiprotocol WAN Link Driver. +* Definitions for the SDLA PCI adapter. +* +* Author: Gideon Hack +* +* Copyright: (c) 1999-2000 Sangoma Technologies Inc. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version +* 2 of the License, or (at your option) any later version. +* ============================================================================ +* Jun 02, 1999 Gideon Hack Initial version. +*****************************************************************************/ +#ifndef _SDLAPCI_H +#define _SDLAPCI_H + +/****** Defines *************************************************************/ + +/* Definitions for identifying and finding S514 PCI adapters */ +#define V3_VENDOR_ID 0x11B0 /* V3 vendor ID number */ +#define V3_DEVICE_ID 0x0002 /* V3 device ID number */ +#define SANGOMA_SUBSYS_VENDOR 0x4753 /* ID for Sangoma */ +#define PCI_DEV_SLOT_MASK 0x1F /* mask for slot numbering */ +#define PCI_IRQ_NOT_ALLOCATED 0xFF /* interrupt line for no IRQ */ + +/* Definition for identifying and finding XILINX PCI adapters */ +#define SANGOMA_PCI_VENDOR 0x1923 /* Old value -> 0x11B0 */ +#define SANGOMA_PCI_VENDOR_OLD 0x10EE /* Old value -> 0x11B0 */ +#define SANGOMA_PCI_DEVICE 0x0300 /* Old value -> 0x0200 */ +#define SANGOMA_PCI_4_DEVICE 0x0400 /* */ + +/* Definition for identifying and finding PLX PCI bridge adapters */ +#define PLX_VENDOR_ID 0x10b5 /* PLX vendor ID number */ +#define PLX_DEVICE_ID 0x8111 /* PLX device ID number */ + +#define A101_1TE1_SUBSYS_VENDOR 0xA010 /* A101 with T1/E1 1 line */ +#define A101_2TE1_SUBSYS_VENDOR 0xA011 /* A101 with T1/E1 2 lines */ +#define A104_4TE1_SUBSYS_VENDOR 0xA013 /* A104 with T1/E1 4 lines */ +#define A300_UTE3_SUBSYS_VENDOR 0xA020 /* A300 with T3/E3 (unchannelized) */ +#define A305_CT3_SUBSYS_VENDOR 0xA030 /* A305 with T3 (channelized) */ + +#define A104_1TE1_SHARK_SUBSYS_VENDOR 0xA111 /* A101-SHARK T1/E1 1 lines */ +#define A104_2TE1_SHARK_SUBSYS_VENDOR 0xA112 /* A102-SHARK T1/E1 2 lines */ +#define A104_4TE1_SHARK_SUBSYS_VENDOR 0xA113 /* A104-SHARK T1/E1 4 lines */ +#define A104_8TE1_SHARK_SUBSYS_VENDOR 0xA114 /* A108-SHARK T1/E1 8 lines */ +#define A300_UTE3_SHARK_SUBSYS_VENDOR 0xA115 /* A300-SHARK with T3/E3 (unchannelized) */ +#define A305_CTE3_SHARK_SUBSYS_VENDOR 0xA116 /* A305-SHARK with T3 (channelized) */ +#define A200_REMORA_SHARK_SUBSYS_VENDOR 0xA200 /* AFT-REMORA SHARK analog board */ + +#define AFT_CORE_ID_MASK 0x00FF +#define AFT_CORE_REV_MASK 0xFF00 +#define AFT_CORE_REV_SHIFT 8 +#define AFT_HDLC_CORE_ID 0x00 /* HDLC core */ +#define AFT_ATM_CORE_ID 0x01 /* ATM core */ +#define AFT_SS7_CORE_ID 0x02 /* SS7 core */ +#define AFT_HDLC_EC_CORE_ID 0x10 /* HDLC core with EC */ +#define AFT_CORE_ID(subsys_id) (subsys_id & AFT_CORE_ID_MASK) +#define AFT_CORE_REV(subsys_id) ((subsys_id >> AFT_CORE_REV_SHIFT) & 0xFF) +#define AFT_CORE_ID_DECODE(core_id) \ + (core_id == AFT_HDLC_CORE_ID) ? "HDLC" : \ + (core_id == AFT_ATM_CORE_ID) ? "ATM" : \ + (core_id == AFT_SS7_CORE_ID) ? "SS7" : \ + (core_id == AFT_HDLC_EC_CORE_ID) ? "HDLC" : \ + "Unknown" + +#define AFT_CHIP_UNKNOWN 0x0000 +#define AFT_CHIP_OLD_X300 0x0300 +#define AFT_CHIP_OLD_X400 0x0400 +#define AFT_CHIP_X200 0x0020 +#define AFT_CHIP_X300 0x0030 +#define AFT_CHIP_X400 0x0040 +#define AFT_CHIP_X1000 0x0100 + +#define AFT_PCI_MEM_SIZE 0x2FF +#define XILINX_PCI_LATENCY 0x0000FF00 + +#define AFT4_PCI_MEM_SIZE 0xFFFF +#define AFT8_PCI_MEM_SIZE 0x1FFFF + +#define XILINX_PCI_CMD_REG 0x04 +#define XILINX_PCI_LATENCY_REG 0x0C + +/* Local PCI register offsets */ +#define PCI_VENDOR_ID_WORD 0x00 /* vendor ID */ +#define PCI_DEVICE_ID_WORD 0x02 /* device ID */ +#define PCI_REVISION_ID_BYTE 0x08 /* revision ID */ +#define PCI_SUBCLASS_ID_BYTE 0x0a /* subclass ID byte */ +#define PCI_IO_BASE_DWORD 0x10 /* IO base */ +#define PCI_MEM_BASE0_DWORD 0x14 /* memory base - apperture 0 */ +#define PCI_MEM_BASE1_DWORD 0x18 /* memory base - apperture 1 */ +#define PCI_SUBSYS_VENDOR_WORD 0x2C /* subsystem vendor ID */ +#define PCI_SUBSYS_ID_WORD 0x2E /* subsystem ID */ +#define PCI_INT_LINE_BYTE 0x3C /* interrupt line */ +#define PCI_INT_PIN_BYTE 0x3D /* interrupt pin */ +#define PCI_MAP0_DWORD 0x40 /* PCI to local bus address 0 */ +#define PCI_MAP1_DWORD 0x44 /* PCI to local bus address 1 */ +#define PCI_INT_STATUS 0x48 /* interrupt status */ +#define PCI_INT_CONFIG 0x4C /* interrupt configuration */ + +/* Local PCI register usage */ +#define PCI_MEMORY_ENABLE 0x00000003 /* enable PCI memory */ +#define PCI_CPU_A_MEM_DISABLE 0x00000002 /* disable CPU A memory */ +#define PCI_CPU_B_MEM_DISABLE 0x00100002 /* disable CPU B memory */ +#define PCI_ENABLE_IRQ_CPU_A 0x005A0004 /* enable IRQ for CPU A */ +#define PCI_ENABLE_IRQ_CPU_B 0x005A0008 /* enable IRQ for CPU B */ +#define PCI_ENABLE_IRQ_DMA0 0x01000000 /* enable IRQ for DMA 0 */ +#define PCI_ENABLE_IRQ_DMA1 0x02000000 /* enable IRQ for DMA 1 */ +#define PCI_DISABLE_IRQ_CPU_A 0x00000004 /* disable IRQ for CPU A */ +#define PCI_DISABLE_IRQ_CPU_B 0x00000008 /* disable IRQ for CPU B */ +#define PCI_DISABLE_IRQ_DMA0 0x01000000 /* disable IRQ for DMA 0 */ +#define PCI_DISABLE_IRQ_DMA1 0x02000000 /* disable IRQ for DMA 1 */ + +/* Setting for the Interrupt Status register */ +#define IRQ_DMA0 0x01000000 /* IRQ for DMA0 */ +#define IRQ_DMA1 0x02000000 /* IRQ for DMA1 */ +#define IRQ_LOCAL_CPU_A 0x00000004 /* IRQ for CPU A */ +#define IRQ_LOCAL_CPU_B 0x00000008 /* IRQ for CPU B */ +#define IRQ_CPU_A 0x04 /* IRQ for CPU A */ +#define IRQ_CPU_B 0x08 /* IRQ for CPU B */ + +/* The maximum size of the S514 memory */ +#define MAX_SIZEOF_S514_MEMORY (256 * 1024) + +/* S514 control register offsets within the memory address space */ +#define S514_CTRL_REG_BYTE 0x80000 + +/* S514 adapter control bytes */ +#define S514_CPU_HALT 0x00 +#define S514_CPU_START 0x01 + +/* The maximum number of S514 adapters supported */ +#define MAX_S514_CARDS 20 + +/* ADSL Hardware Defines */ +#define GSI_PCI_MEMORY_SIZE (8 * (4 * 2 * 1024)) +#define PCI_VENDOR_ID_GSI 0x14BC +#define PCI_DEVICE_ID_GSI_PULSAR 0xD002 +#define PCI_DEVICE_ID_GSI_ADSL PCI_DEVICE_ID_GSI_PULSAR + + +#endif /* _SDLAPCI_H */ + diff -Nur linux.org/include/linux/sdla_pos.h linux-2.6.17/include/linux/sdla_pos.h --- linux.org/include/linux/sdla_pos.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/sdla_pos.h 2006-08-30 10:07:15.000000000 +0000 @@ -0,0 +1,221 @@ +/***************************************************************************** +* POSAPI.H - Sangoma POS Adapter. Application Program Interface definitions. +* (c) Sangoma Technologies Inc., 1993-1994 +* ---------------------------------------------------------------------------- +* Date: Revision: By: +* May 25, 1994 2.32 - CONFIGSTRUC has been changed. If half_duplex is +* non-zero then half-duplex ASYNCH mode is +* selected. Zero selects full-duplex mode. Default +* mode is half-duplex (defined as DFT_HALFDUPLEX). EK +* +* Jan.19, 1994 2.10 - POSSETUPSTRUC has been changed to accomodate EK +* 2-byte address field. +* +* Jan.11, 1994 2.00 - Initial. EK +*****************************************************************************/ + +/****** GENERAL DATA TYPES DEFINITIONS **************************************/ + +#ifndef __SDLA_POS_H_ +#define __SDLA_POS_H_ + +#pragma pack(1) + +/*----- General Purpose Constants ------------------------------------------*/ +#define TRUE 1 /* values for BOOL data type */ +#define FALSE 0 +#ifndef NULL +#define NULL 0 +#endif + +/*----- POS and ASYNC Mode Definitions -------------------------------------*/ +#define SDLC_ALL 0 /* Pass all received frames */ +#define SDLC_INFO 1 /* Pass all I-frames (default) */ +#define SDLC_SELECT 2 /* Pass only I-frames with matching address */ +#define ASYNC_4800 0 /* RS485 line speed: 4800 bps */ +#define ASYNC_9600 1 /* RS485 line speed: 9600 bps */ +#define ASYNC_19200 2 /* RS485 line speed: 19200 bps */ +#define ASYNC_38400 3 /* RS485 line speed: 38400 bps */ +#define ASYNC_MAXSPEED ASYNC_38400 +#define PRIMARY_ATTR 0 /* frame belongs to primary station */ +#define SECONDARY_ATTR 1 /* frame belongs to secondary station */ + +/*----- Default Configuration and Setup Parameters -------------------------*/ +#define WINDOW_SIZE 0x2000 /* size of shared memory window */ +#define TIME_OUT 2 /* board response time-out, sec */ +#define MAX_DATA 1030 /* maximum I-frame data field length */ +#define MIN_DATA 128 /* minimum I-frame data field length */ +#define DFT_POSDATA 265 /* default I-frame data field length */ +#define DFT_SDLCLINES 1 /* default number of monitored POS lines */ +#define DFT_SDLCMODE SDLC_INFO +#define DFT_ASYNCLINES 1 /* default number of monitored asynch lines */ +#define DFT_ASYNCSPEED ASYNC_19200 +#define DFT_HALFDUPLEX TRUE /* default asynch mode */ + +/*----- Mailbox interface constants ----------------------------------------*/ +#define CLEAR 0x00 /* no activity */ +#define EXE_CMD 0x01 /* execute mailbox command flag */ +#define SDLC1_RXRDY 0x01 /* bit 0 - POS#1 frames available */ +#define SDLC2_RXRDY 0x02 /* bit 1 - POS#2 frames available */ +#define ASYNC1_RXRDY 0x01 /* bit 0 - ASYNC#1 data available */ +#define ASYNC1_TXRDY 0x02 /* bit 1 - ASYNC#1 transmit buffer empty */ +#define ASYNC2_RXRDY 0x04 /* bit 2 - ASYNC#2 data available */ +#define ASYNC2_TXRDY 0x08 /* bit 3 - ASYNC#2 transmit buffer empty */ + +/*----- POS Commands -------------------------------------------------------*/ +#define CONFIGURE 0x01 /* Configure POS */ +#define SEND_ASYNC 0x02 /* Send block of data through ASYNC port */ +#define RECEIVE_ASYNC 0x03 /* Receive block of bata through ASYNC port */ +#define ENABLE_POS 0x04 /* Start listening on a POS loop */ +#define DISABLE_POS 0x05 /* Stop listening on a POS loop */ +#define RECEIVE_POS 0x06 /* Receive a frame buffered from POS loop */ +#define READ_ERR_STATS 0x07 /* Retrieve POS communic. error statistics */ +#define FLUSH_ERRORS 0x08 /* Reset all error counters */ +#define SEND_RECV_STATE 0x09 /* Get transmit/receive buffers state */ +#define POS_SETUP 0x0A /* Set POS loop monitoring mode */ +#define RESET_CARD 0x0B /* Clear all buffers, set all default modes */ + +/*----- POS Return Codes ---------------------------------------------------*/ +#define POS_OK 0x00 /* Command executed successfully */ +#define POS_BADPORT 0x01 /* Invalid port number */ +#define POS_WASDONE 0x02 /* Command has already been executed */ +#define POS_DISABLED 0x03 /* Port is disabled */ +#define POS_DENIED 0x33 /* Board temporarily unaccessable */ +#define INVALID_CMD 0x80 /* Unrecognized command code */ +#define INVALID_PAR 0x81 /* Invalid parameter value */ +#define POS_FAULT 0x0A /* Board hung */ +#define POS_INIT_OK 0xF0 /* Board initialized */ + +#define BYTE unsigned char +#define WORD unsigned short +/****** DATA STRUCTURES *****************************************************/ + +/*----- Command Control Block ------------------------------------------------ + * This structure is used for microcode command execution. + *--------------------------------------------------------------------------*/ + +typedef struct { + BYTE command; /* disp.00h: Command code */ + WORD buf_len; /* disp.01h: Length of data buffer */ + BYTE ret_code; /* disp.03h: Result of previous command */ + BYTE port_num; /* disp.04h: Port number (0 - general) */ + BYTE prim_sec; /* disp.05h: Primary/Secondary attribute */ + BYTE reserved [10]; /* disp.06h .. 0Fh: reserved for later use */ + BYTE data [MAX_DATA]; /* disp.10h: data transfer buffer */ +} PIPCBSTRUC; + + +/*----- Mailbox Structure --------------------------------------------------- + * This structure is used for microcode application program interface. + *--------------------------------------------------------------------------*/ + +typedef struct { + BYTE exe_flag; /* disp.00h: '1' - enable command execution */ + BYTE sdlc_flags; /* disp.01h: POS SDLC channels status */ + BYTE async_flags; /* disp.02h: ASYNC channels status */ + BYTE reserved [13]; /* disp.03 .. 0Fh - reserved for later use */ + PIPCBSTRUC pipcb; /* disp.10h: PIP Control Block */ +} POSMBSTRUC; + + +/*----- Card Configuration Data Block ---------------------------------------- + * Used for CONFIGURE command. + *--------------------------------------------------------------------------*/ + +typedef struct { + BYTE sdlc_lines; /* disp.00h: number of active SDLC lines */ + WORD sdlc_maxdata; /* disp.01h: maximum length of the I-frame */ + BYTE async_lines; /* disp.03h: number of active ASYNC lines */ + BYTE async_speed; /* disp.04h: asynchronous line(s) speed */ + BYTE half_duplex; /* disp.05h: half/full-duplex configuration */ +} CONFIGSTRUC; + + +/*----- SDLC Communications Error Statistics Data Block ---------------------- + * Used for READ_ERR_STATS command. + *--------------------------------------------------------------------------*/ + +typedef struct { + WORD overrun_err; /* disp.00h: receiver overrun error count */ + WORD CRC_err; /* disp.02h: receiver CRC error count */ + WORD abort_err; /* disp.04h: aborted frames count */ + WORD lost_err; /* disp.06h: buffer overflow error count */ + WORD excess_err; /* disp.08h: excessive frame length count */ +} ERRSTATSTRUC; + + +/*----- POS Send/Receive State Data Block ------------------------------------ + * Used for SEND_RECV_STATE command. + *--------------------------------------------------------------------------*/ + +typedef struct { + WORD POS1_received; /* disp.00h: POS#1 queued frames count */ + WORD POS2_received; /* disp.02h: POS#2 queued frames count */ + WORD async1_recvd; /* disp.04h: bytes in ASYNC#1 receive buffer*/ + WORD async1_transm; /* disp.06h: free in ASYNC#1 transmit buffer*/ + WORD async2_recvd; /* disp.08h: bytes in ASYNC#2 receive buffer*/ + WORD async2_transm; /* disp.0Ah: free in ASYNC#2 transmit buffer*/ +} POSSTATESTRUC; + + +/*----- POS Setup Data Block ------------------------------------------------- + * Used for POS_SETUP command. + *--------------------------------------------------------------------------*/ + +typedef struct { + BYTE mode; /* disp.00h: POS operation mode */ + WORD addr; /* disp.01h: address to search for */ +} POSSETUPSTRUC; + +#pragma pack() + + +/************************************************************** + * + * TEMPLATE + * + *************************************************************/ + +#define CONFIGURATION_STRUCT CONFIGSTRUC + +#define WANCONFIG_FRMW WANCONFIG_ATM + +#define OK 0 +#define COMMAND_OK OK + +enum { + ROUTER_UP_TIME = 0x50, + FT1_READ_STATUS, + ENABLE_TRACING, + FT1_MONITOR_STATUS_CTRL, + ENABLE_READ_FT1_STATUS, + ENABLE_READ_FT1_OP_STATS +}; + +#define DCD_HIGH 0x08 +#define CTS_HIGH 0x20 + +#define MIN_WP_PRI_MTU 1500 +#define MAX_WP_PRI_MTU MIN_WP_PRI_MTU +#define DEFAULT_WP_PRI_MTU MIN_WP_PRI_MTU + +#define MIN_WP_SEC_MTU 1500 +#define MAX_WP_SEC_MTU MIN_WP_SEC_MTU +#define DEFAULT_WP_SEC_MTU MIN_WP_SEC_MTU + + +/* reasons for enabling the timer interrupt on the adapter */ +#define TMR_INT_ENABLED_UDP 0x01 +#define TMR_INT_ENABLED_UPDATE 0x02 +#define TMR_INT_ENABLED_CONFIG 0x10 +#define TMR_INT_ENABLED_TE 0x20 + +#define SIOC_WANPIPE_EXEC_CMD SIOC_WANPIPE_DEVPRIVATE +#define SIOC_WANPIPE_POS_STATUS_CMD SIOC_WANPIPE_DEVPRIVATE+1 + +#ifdef __KERNEL__ + +#define PRI_BASE_ADDR_MB_STRUCT 0xE000 + +#endif +#endif diff -Nur linux.org/include/linux/sdla_ppp.h linux-2.6.17/include/linux/sdla_ppp.h --- linux.org/include/linux/sdla_ppp.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/sdla_ppp.h 2006-08-30 10:07:15.000000000 +0000 @@ -0,0 +1,374 @@ +/***************************************************************************** +* sdla_ppp.h Sangoma PPP firmware API definitions. +* +* Author: Nenad Corbic +* +* Copyright: (c) 1995-1997 Sangoma Technologies Inc. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version +* 2 of the License, or (at your option) any later version. +* ============================================================================ +* Feb 24, 2000 Nenad Corbic v2.1.2 +* Jan 06, 1997 Gene Kozin v2.0 +* Apr 11, 1996 Gene Kozin Initial version. +*****************************************************************************/ +#ifndef _SDLA_PPP_H +#define _SDLA_PPP_H + +/*---------------------------------------------------------------------------- + * Notes: + * ------ + * 1. All structures defined in this file are byte-alined. + * + * Compiler Platform + * -------- -------- + * GNU C Linux + */ + +#ifndef PACKED +# define PACKED __attribute__((packed)) +#endif /* PACKED */ + + +#include + +/* Adapter memory layout and important constants */ +#define PPP508_MB_VECT 0xE000 /* mailbox window vector */ +#define PPP508_MB_OFFS 0 /* mailbox offset */ +#define PPP508_FLG_OFFS 0x1000 /* status flags offset */ +#define PPP508_BUF_OFFS 0x1100 /* buffer info block offset */ +#define PPP514_MB_OFFS 0xE000 /* mailbox offset */ +#define PPP514_FLG_OFFS 0xF000 /* status flags offset */ +#define PPP514_BUF_OFFS 0xF100 /* buffer info block offset */ + +#define PPP_MAX_DATA 1008 /* command block data buffer length */ + +/****** Data Structures *****************************************************/ +/*---------------------------------------------------------------------------- + * PPP Command Block. + */ +typedef struct ppp_cmd{ + unsigned char command PACKED; /* command code */ + unsigned short length PACKED; /* length of data buffer */ + unsigned char result PACKED; /* return code */ + unsigned char rsrv[11] PACKED; /* reserved for future use */ +} ppp_cmd_t; + +typedef struct { + unsigned char status PACKED; + unsigned char data_avail PACKED; + unsigned short real_length PACKED; + unsigned short time_stamp PACKED; + unsigned char data[1] PACKED; +} trace_pkt_t; + + +typedef struct { + unsigned char opp_flag PACKED; + unsigned char trace_type PACKED; + unsigned short trace_length PACKED; + unsigned short trace_data_ptr PACKED; + unsigned short trace_time_stamp PACKED; +} trace_element_t; + + + +/* 'result' field defines */ +#define PPPRES_OK 0x00 /* command executed successfully */ +#define PPPRES_INVALID_STATE 0x09 /* invalid command in this context */ + +#if 0 +/*---------------------------------------------------------------------------- + * PPP Mailbox. + * This structure is located at offset PPP???_MB_OFFS into PPP???_MB_VECT + */ +typedef struct ppp_mbox +{ + unsigned char flag PACKED; /* 00h: command execution flag */ + ppp_cmd_t cmd PACKED; /* 01h: command block */ + unsigned char data[1] PACKED; /* 10h: variable length data buffer */ +} ppp_mbox_t; +#endif +/*---------------------------------------------------------------------------- + * PPP Status Flags. + * This structure is located at offset PPP???_FLG_OFFS into + * PPP???_MB_VECT. + */ +typedef struct ppp_flags +{ + unsigned char iflag PACKED; /* 00: interrupt flag */ + unsigned char imask PACKED; /* 01: interrupt mask */ + unsigned char resrv PACKED; + unsigned char mstatus PACKED; /* 03: modem status */ + unsigned char lcp_state PACKED; /* 04: LCP state */ + unsigned char ppp_phase PACKED; /* 05: PPP phase */ + unsigned char ip_state PACKED; /* 06: IPCP state */ + unsigned char ipx_state PACKED; /* 07: IPXCP state */ + unsigned char pap_state PACKED; /* 08: PAP state */ + unsigned char chap_state PACKED; /* 09: CHAP state */ + unsigned short disc_cause PACKED; /* 0A: disconnection cause */ +} ppp_flags_t; + +/* 'iflag' defines */ +#define PPP_INTR_RXRDY 0x01 /* Rx ready */ +#define PPP_INTR_TXRDY 0x02 /* Tx ready */ +#define PPP_INTR_MODEM 0x04 /* modem status change (DCD, CTS) */ +#define PPP_INTR_CMD 0x08 /* interface command completed */ +#define PPP_INTR_DISC 0x10 /* data link disconnected */ +#define PPP_INTR_OPEN 0x20 /* data link open */ +#define PPP_INTR_DROP_DTR 0x40 /* DTR drop timeout expired */ +#define PPP_INTR_TIMER 0x80 /* timer interrupt */ + + +/* 'mstatus' defines */ +#define PPP_MDM_DCD 0x08 /* mdm_status: DCD */ +#define PPP_MDM_CTS 0x20 /* mdm_status: CTS */ + +/* 'disc_cause' defines */ +#define PPP_LOCAL_TERMINATION 0x0001 /* Local Request by PPP termination phase */ +#define PPP_DCD_CTS_DROP 0x0002 /* DCD and/or CTS dropped. Link down */ +#define PPP_REMOTE_TERMINATION 0x0800 /* Remote Request by PPP termination phase */ + +/* 'misc_config_bits' defines */ +#define DONT_RE_TX_ABORTED_I_FRAMES 0x01 +#define TX_FRM_BYTE_COUNT_STATS 0x02 +#define RX_FRM_BYTE_COUNT_STATS 0x04 +#define TIME_STAMP_IN_RX_FRAMES 0x08 +#define NON_STD_ADPTR_FREQ 0x10 +#define INTERFACE_LEVEL_RS232 0x20 +#define AUTO_LINK_RECOVERY 0x100 +#define DONT_TERMINATE_LNK_MAX_CONFIG 0x200 + +/* 'authentication options' defines */ +#define NO_AUTHENTICATION 0x00 +#define INBOUND_AUTH 0x80 +#define PAP_AUTH 0x01 +#define CHAP_AUTH 0x02 + +/* 'ip options' defines */ +#define L_AND_R_IP_NO_ASSIG 0x00 +#define L_IP_LOCAL_ASSIG 0x01 +#define L_IP_REMOTE_ASSIG 0x02 +#define R_IP_LOCAL_ASSIG 0x04 +#define R_IP_REMOTE_ASSIG 0x08 +#define ENABLE_IP 0x80 + +/* 'ipx options' defines */ +#define ROUTING_PROT_DEFAULT 0x20 +#define ENABLE_IPX 0x80 +#define DISABLE_IPX 0x00 + +/*---------------------------------------------------------------------------- + * PPP Buffer Info. + * This structure is located at offset PPP508_BUF_OFFS into + * PPP508_MB_VECT. + */ +typedef struct ppp508_buf_info +{ + unsigned short txb_num PACKED; /* 00: number of transmit buffers */ + unsigned int txb_ptr PACKED; /* 02: pointer to the buffer ctl. */ + unsigned int txb_nxt PACKED; + unsigned char rsrv1[22] PACKED; + unsigned short rxb_num PACKED; /* 20: number of receive buffers */ + unsigned int rxb_ptr PACKED; /* 22: pointer to the buffer ctl. */ + unsigned int rxb1_ptr PACKED; /* 26: pointer to the first buf.ctl. */ + unsigned int rxb_base PACKED; /* 2A: pointer to the buffer base */ + unsigned char rsrv2[2] PACKED; + unsigned int rxb_end PACKED; /* 30: pointer to the buffer end */ +} ppp508_buf_info_t; + +/*---------------------------------------------------------------------------- + * Transmit/Receive Buffer Control Block. + */ +typedef struct ppp_buf_ctl +{ + unsigned char flag PACKED; /* 00: 'buffer ready' flag */ + unsigned short length PACKED; /* 01: length of data */ + unsigned char reserved1[1] PACKED; /* 03: */ + unsigned char proto PACKED; /* 04: protocol */ + unsigned short timestamp PACKED; /* 05: time stamp (Rx only) */ + unsigned char reserved2[5] PACKED; /* 07: */ + union + { + unsigned short o_p[2]; /* 1C: buffer offset & page (S502) */ + unsigned int ptr; /* 1C: buffer pointer (S508) */ + } buf PACKED; +} ppp_buf_ctl_t; + +/*---------------------------------------------------------------------------- + * S508 Adapter Configuration Block (passed to the PPP_SET_CONFIG command). + */ +typedef struct ppp508_conf +{ + unsigned int line_speed PACKED; /* 00: baud rate, bps */ + unsigned short txbuf_percent PACKED; /* 04: % of Tx buffer */ + unsigned short conf_flags PACKED; /* 06: configuration bits */ + unsigned short mtu_local PACKED; /* 08: local MTU */ + unsigned short mtu_remote PACKED; /* 0A: remote MTU */ + unsigned short restart_tmr PACKED; /* 0C: restart timer */ + unsigned short auth_rsrt_tmr PACKED; /* 0E: authentication timer */ + unsigned short auth_wait_tmr PACKED; /* 10: authentication timer */ + unsigned short mdm_fail_tmr PACKED; /* 12: modem failure timer */ + unsigned short dtr_drop_tmr PACKED; /* 14: DTR drop timer */ + unsigned short connect_tmout PACKED; /* 16: connection timeout */ + unsigned short conf_retry PACKED; /* 18: max. retry */ + unsigned short term_retry PACKED; /* 1A: max. retry */ + unsigned short fail_retry PACKED; /* 1C: max. retry */ + unsigned short auth_retry PACKED; /* 1E: max. retry */ + unsigned char auth_options PACKED; /* 20: authentication opt. */ + unsigned char ip_options PACKED; /* 21: IP options */ + unsigned int ip_local PACKED; /* 22: local IP address */ + unsigned int ip_remote PACKED; /* 26: remote IP address */ + unsigned char ipx_options PACKED; /* 2A: IPX options */ + unsigned char ipx_netno[4] PACKED; /* 2B: IPX net number */ + unsigned char ipx_local[6] PACKED; /* 2F: local IPX node number*/ + unsigned char ipx_remote[6] PACKED; /* 35: remote IPX node num.*/ + unsigned char ipx_router[48] PACKED; /* 3B: IPX router name*/ + unsigned int alt_cpu_clock PACKED; /* 6B: */ +} ppp508_conf_t; + +/*---------------------------------------------------------------------------- + * S508 Adapter Read Connection Information Block + * Returned by the PPP_GET_CONNECTION_INFO command + */ +typedef struct ppp508_connect_info +{ + unsigned short mru PACKED; /* 00-01 Remote Max Rec' Unit */ + unsigned char ip_options PACKED; /* 02: Negotiated ip options */ + unsigned int ip_local PACKED; /* 03-06: local IP address */ + unsigned int ip_remote PACKED; /* 07-0A: remote IP address */ + unsigned char ipx_options PACKED; /* 0B: Negotiated ipx options */ + unsigned char ipx_netno[4] PACKED; /* 0C-0F: IPX net number */ + unsigned char ipx_local[6] PACKED; /* 10-1F: local IPX node # */ + unsigned char ipx_remote[6] PACKED; /* 16-1B: remote IPX node # */ + unsigned char ipx_router[48] PACKED; /* 1C-4B: IPX router name */ + unsigned char auth_status PACKED; /* 4C: Authentication Status */ + unsigned char inbd_auth_peerID[1] PACKED; /* 4D: variable length inbound authenticated peer ID */ +} ppp508_connect_info_t; + +/* 'line_speed' field */ +#define PPP_BITRATE_1200 0x01 +#define PPP_BITRATE_2400 0x02 +#define PPP_BITRATE_4800 0x03 +#define PPP_BITRATE_9600 0x04 +#define PPP_BITRATE_19200 0x05 +#define PPP_BITRATE_38400 0x06 +#define PPP_BITRATE_45000 0x07 +#define PPP_BITRATE_56000 0x08 +#define PPP_BITRATE_64000 0x09 +#define PPP_BITRATE_74000 0x0A +#define PPP_BITRATE_112000 0x0B +#define PPP_BITRATE_128000 0x0C +#define PPP_BITRATE_156000 0x0D + +/* Defines for the 'conf_flags' field */ +#define PPP_IGNORE_TX_ABORT 0x01 /* don't re-transmit aborted frames */ +#define PPP_ENABLE_TX_STATS 0x02 /* enable Tx statistics */ +#define PPP_ENABLE_RX_STATS 0x04 /* enable Rx statistics */ +#define PPP_ENABLE_TIMESTAMP 0x08 /* enable timestamp */ + +/* 'ip_options' defines */ +#define PPP_LOCAL_IP_LOCAL 0x01 +#define PPP_LOCAL_IP_REMOTE 0x02 +#define PPP_REMOTE_IP_LOCAL 0x04 +#define PPP_REMOTE_IP_REMOTE 0x08 + +/* 'ipx_options' defines */ +#define PPP_REMOTE_IPX_NETNO 0x01 +#define PPP_REMOTE_IPX_LOCAL 0x02 +#define PPP_REMOTE_IPX_REMOTE 0x04 +#define PPP_IPX_ROUTE_RIP_SAP 0x08 +#define PPP_IPX_ROUTE_NLSP 0x10 +#define PPP_IPX_ROUTE_DEFAULT 0x20 +#define PPP_IPX_CONF_COMPLETE 0x40 +#define PPP_IPX_ENABLE 0x80 + +/*---------------------------------------------------------------------------- + * S508 Adapter Configuration Block (returned by the PPP_READ_CONFIG command). + */ +typedef struct ppp508_get_conf +{ + unsigned int bps PACKED; /* 00: baud rate, bps */ + ppp508_conf_t conf PACKED; /* 04: requested config. */ + unsigned short txb_num PACKED; /* 6F: number of Tx buffers */ + unsigned short rxb_num PACKED; /* 71: number of Rx buffers */ +} ppp508_get_conf_t; + +/*---------------------------------------------------------------------------- + * S508 Operational Statistics (returned by the PPP_READ_STATISTIC command). + */ +typedef struct ppp508_stats +{ + unsigned short reserved1 PACKED; /* 00: */ + unsigned short rx_bad_len PACKED; /* 02: */ + unsigned short reserved2 PACKED; /* 04: */ + unsigned int tx_frames PACKED; /* 06: */ + unsigned int tx_bytes PACKED; /* 0A: */ + unsigned int rx_frames PACKED; /* 0E: */ + unsigned int rx_bytes PACKED; /* 12: */ +} ppp508_stats_t; + +/*---------------------------------------------------------------------------- + * Adapter Error Statistics (returned by the PPP_READ_ERROR_STATS command). + */ +typedef struct ppp_err_stats +{ + unsigned char rx_overrun PACKED; /* 00: Rx overrun errors */ + unsigned char rx_bad_crc PACKED; /* 01: Rx CRC errors */ + unsigned char rx_abort PACKED; /* 02: Rx aborted frames */ + unsigned char rx_lost PACKED; /* 03: Rx frames lost */ + unsigned char tx_abort PACKED; /* 04: Tx aborted frames */ + unsigned char tx_underrun PACKED; /* 05: Tx underrun errors */ + unsigned char tx_missed_intr PACKED; /* 06: Tx underruns missed */ + unsigned char reserved PACKED; /* 07: Tx underruns missed */ + unsigned char dcd_trans PACKED; /* 08: DCD transitions */ + unsigned char cts_trans PACKED; /* 09: CTS transitions */ +} ppp_err_stats_t; + +/* Data structure for SET_TRIGGER_INTR command + */ + +typedef struct ppp_intr_info{ + unsigned char i_enable PACKED; /* 0 Interrupt enable bits */ + unsigned char irq PACKED; /* 1 Irq number */ + unsigned short timer_len PACKED; /* 2 Timer delay */ +} ppp_intr_info_t; + + +#define FT1_MONITOR_STATUS_CTRL 0x80 +#define SET_FT1_MODE 0x81 + + + +/* Special UDP drivers management commands */ +#define PPIPE_ENABLE_TRACING 0x20 +#define PPIPE_DISABLE_TRACING 0x21 +#define PPIPE_GET_TRACE_INFO 0x22 +#define PPIPE_GET_IBA_DATA 0x23 +#define PPIPE_KILL_BOARD 0x24 +#define PPIPE_FT1_READ_STATUS 0x25 +#define PPIPE_DRIVER_STAT_IFSEND 0x26 +#define PPIPE_DRIVER_STAT_INTR 0x27 +#define PPIPE_DRIVER_STAT_GEN 0x28 +#define PPIPE_FLUSH_DRIVER_STATS 0x29 +#define PPIPE_ROUTER_UP_TIME 0x30 +#define PPIPE_TE1_56K_STAT 0x40 /* TE1_56K */ +#define PPIPE_GET_MEDIA_TYPE 0x41 /* TE1_56K */ +#define PPIPE_FLUSH_TE1_PMON 0x42 /* TE1 */ +#define PPIPE_READ_REGISTER 0x43 /* TE1_56K */ +#define PPIPE_TE1_CFG 0x44 /* TE1 */ + +#define DISABLE_TRACING 0x00 +#define TRACE_SIGNALLING_FRAMES 0x01 +#define TRACE_DATA_FRAMES 0x02 + +#define UDPMGMT_SIGNATURE "PTPIPEAB" +#define UDPDRV_SIGNATURE "DRVSTATS" +#define UDPMGMT_UDP_PROTOCOL 0x11 + +#ifdef _MSC_ +# pragma pack() +#endif +#endif /* _SDLA_PPP_H */ diff -Nur linux.org/include/linux/sdla_remora.h linux-2.6.17/include/linux/sdla_remora.h --- linux.org/include/linux/sdla_remora.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/sdla_remora.h 2006-08-30 10:07:15.000000000 +0000 @@ -0,0 +1,259 @@ +/******************************************************************************* +** sdla_remora.h +** +** Author: Alex Feldman +** +** Copyright: (c) 2005 Sangoma Technologies Inc. +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of the GNU General Public License +** as published by the Free Software Foundation; either version +** 2 of the License, or (at your option) any later version. +** ============================================================================ +** Oct 6, 2005 Alex Feldman Initial version. +*******************************************************************************/ + +#ifndef __SDLA_REMORA_H +# define __SDLA_REMORA_H + +#ifdef __SDLA_REMORA_SRC +# define EXTERN +#else +# define EXTERN extern +#endif + +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) +# include +#else +# include +#endif + +/******************************************************************************* +** DEFINES and MACROS +*******************************************************************************/ + +#define IS_FXOFXS_CARD(card) IS_FXOFXS_FEMEDIA(&(card)->fe) + +#define MAX_REMORA_MODULES 24 +#define MAX_FXOFXS_CHANNELS MAX_REMORA_MODULES + +#define MOD_TYPE_NONE 0 +#define MOD_TYPE_FXS 1 +#define MOD_TYPE_FXO 2 +#define MOD_TYPE_TEST 3 +#define WP_REMORA_DECODE_TYPE(type) \ + (type == MOD_TYPE_FXS) ? "FXS" : \ + (type == MOD_TYPE_FXO) ? "FXO" : \ + (type == MOD_TYPE_TEST) ? "TST" : \ + "Unknown" + +/* SPI interface */ +#define MOD_CHAIN_DISABLED 0 +#define MOD_CHAIN_ENABLED 1 + +#define SPI_INTERFACE_REG 0x54 + +#define MOD_SPI_ADDR_FXS_READ 0x80 +#define MOD_SPI_ADDR_FXS_WRITE 0x00 + +#define MOD_SPI_CS_FXS_CHIP_0 0x01 +#define MOD_SPI_CS_FXS_CHIP_1 0x02 + +#define MOD_SPI_CS_FXO_CHIP_1 0x08 +#define MOD_SPI_CS_FXO_WRITE 0x00 +#define MOD_SPI_CS_FXO_READ 0x40 + +#define MOD_SPI_CTRL_V3_START 0x08 /* bit 27 used as START in version 1-2-3 */ +#define MOD_SPI_CTRL_START 0x80 +#define MOD_SPI_CTRL_FXS 0x10 +#define MOD_SPI_CTRL_CHAIN 0x20 + +#define MOD_SPI_RESET 0x40000000 +#define MOD_SPI_BUSY 0x80000000 +#define MOD_SPI_V3_STAT 0x08000000 /* bit 27 used as START in version 1-2-3 */ +#define MOD_SPI_START 0x08000000 + +#define WAN_FXS_NUM_REGS 109 +#define WAN_FXS_NUM_INDIRECT_REGS 105 + +#define WAN_FXO_NUM_REGS 59 + +#define WAN_REMORA_READREG 0x01; + +#define RM_FE_MAGIC 0x150D + +#define WAN_RM_OPERMODE_LEN 20 + +/* Front-End UDP command */ +#define WAN_FE_TONES (WAN_FE_UDP_CMD_START + 0) +#define WAN_FE_RING (WAN_FE_UDP_CMD_START + 1) +#define WAN_FE_REGDUMP (WAN_FE_UDP_CMD_START + 2) + +#define WAN_RM_SET_ECHOTUNE _IOW (ZT_CODE, 63, struct wan_rm_echo_coefs) + +/* FE interrupt types */ +#define WAN_RM_INTR_NONE 0x00 +#define WAN_RM_INTR_GLOBAL 0x01 + +/******************************************************************************* +** TYPEDEF STRUCTURE +*******************************************************************************/ +typedef struct sdla_remora_cfg_ { + int not_used; + int opermode; + char opermode_name[WAN_RM_OPERMODE_LEN]; +/* int tdmv_law;*/ /* WAN_TDMV_ALAW or WAN_TDMV_MULAW */ + int reversepolarity; +} sdla_remora_cfg_t; + +typedef struct { + unsigned char direct[WAN_FXS_NUM_REGS]; + unsigned short indirect[WAN_FXS_NUM_INDIRECT_REGS]; +} wan_remora_fxs_regs_t; + +typedef struct { + unsigned char direct[WAN_FXO_NUM_REGS]; +} wan_remora_fxo_regs_t; + +typedef struct { + int mod_no; + int type; + + union { + wan_remora_fxs_regs_t regs_fxs; + wan_remora_fxo_regs_t regs_fxo; + } u; +} wan_remora_udp_t; + +struct wan_rm_echo_coefs { + unsigned char acim; + unsigned char coef1; + unsigned char coef2; + unsigned char coef3; + unsigned char coef4; + unsigned char coef5; + unsigned char coef6; + unsigned char coef7; + unsigned char coef8; +}; + + + +#if defined(WAN_KERNEL) + +#define NUM_CAL_REGS 12 + +#if !defined(WAN_DEBUG_FE) +# define WRITE_RM_FXS_REG(mod_no,chain,reg,val) \ + fe->write_fe_reg(fe->card,(int)mod_no,(int)MOD_TYPE_FXS,(int)chain,(int)reg,(int)val) +# define READ_RM_FXS_REG(mod_no,chain,reg) \ + fe->read_fe_reg(fe->card, (int)mod_no,(int)MOD_TYPE_FXS,(int)chain,(int)reg) +# define WRITE_RM_FXO_REG(mod_no,chain,reg,val) \ + fe->write_fe_reg(fe->card,(int)mod_no,(int)MOD_TYPE_FXO,(int)chain,(int)reg,(int)val) +# define READ_RM_FXO_REG(mod_no,chain,reg) \ + fe->read_fe_reg(fe->card, (int)mod_no,(int)MOD_TYPE_FXO,(int)chain,(int)reg) +# define WRITE_RM_REG(mod_no,reg,val) \ + fe->write_fe_reg( fe->card, \ + (int)mod_no, \ + fe->rm_param.mod[mod_no].type, \ + fe->rm_param.mod[mod_no].chain, \ + (int)reg, (int)val) +# define READ_RM_REG(mod_no,reg) \ + fe->read_fe_reg( fe->card, \ + (int)mod_no, \ + fe->rm_param.mod[mod_no].type, \ + fe->rm_param.mod[mod_no].chain, \ + (int)reg) +#else +# define WRITE_RM_FXS_REG(mod_no,chain,reg,val) \ + fe->write_fe_reg(fe->card,(int)mod_no,(int)MOD_TYPE_FXS,(int)chain,(int)reg,(int)val,__FILE__,(int)__LINE__) +# define READ_RM_FXS_REG(mod_no,chain,reg) \ + fe->read_fe_reg(fe->card, (int)mod_no,(int)MOD_TYPE_FXS,(int)chain,(int)reg,__FILE__,__LINE__) +# define WRITE_RM_FXO_REG(mod_no,chain,reg,val) \ + fe->write_fe_reg(fe->card,(int)mod_no,(int)MOD_TYPE_FXO,(int)chain,(int)reg,(int)val,__FILE__,(int)__LINE__) +# define READ_RM_FXO_REG(mod_no,chain,reg) \ + fe->read_fe_reg(fe->card, (int)mod_no,(int)MOD_TYPE_FXO,(int)chain,(int)reg,__FILE__,(int)__LINE__) +# define WRITE_RM_REG(mod_no,reg,val) \ + fe->write_fe_reg( fe->card, \ + (int)mod_no, \ + fe->rm_param.mod[mod_no].type, \ + fe->rm_param.mod[mod_no].chain, \ + (int)reg, (int)val,__FILE__,(int)__LINE__) +# define READ_RM_REG(mod_no,reg) \ + fe->read_fe_reg( fe->card, \ + (int)mod_no, \ + fe->rm_param.mod[mod_no].type, \ + fe->rm_param.mod[mod_no].chain, \ + (int)reg,__FILE__,(int)__LINE__) +#endif +#define __READ_RM_REG(mod_no,reg) \ + fe->__read_fe_reg( fe->card, \ + (int)mod_no, \ + fe->rm_param.mod[mod_no].type, \ + fe->rm_param.mod[mod_no].chain, \ + (int)reg) + + +enum proslic_power_warn { + PROSLIC_POWER_UNKNOWN = 0, + PROSLIC_POWER_ON, + PROSLIC_POWER_WARNED, +}; + +typedef struct { + unsigned char vals[NUM_CAL_REGS]; +} callregs_t; + +typedef struct { + int ready; + +} wp_remora_fxo_t; + +typedef struct { + int ready; + int idletxhookstate; + int oldrxhook; + enum proslic_power_warn proslic_power; + callregs_t callregs; + unsigned char imask1; /* interrupt mask 1 */ + unsigned char imask2; + unsigned char imask3; +} wp_remora_fxs_t; + +typedef struct { + int type; + int chain; + unsigned char events; + union { + wp_remora_fxo_t fxo; + wp_remora_fxs_t fxs; + } u; + +} wp_remora_module_t; + +typedef struct sdla_remora_param { + int not_used; + + wp_remora_module_t mod[MAX_REMORA_MODULES]; + + unsigned long module_map; /* Map of available module */ + int max_fe_channels; /* Number of available modules */ + + unsigned char critical; + wan_timer_t timer; + unsigned char timer_cmd; + int timer_mod_no; + + int intcount; +} sdla_remora_param_t; + + +#endif /* WAN_KERNEL */ + +/******************************************************************************* +** FUNCTION PROTOTYPES +*******************************************************************************/ +extern int wp_remora_iface_init(void*); + +#undef EXTERN +#endif /* __SDLA_REMORA_H */ diff -Nur linux.org/include/linux/sdla_remora_proslic.h linux-2.6.17/include/linux/sdla_remora_proslic.h --- linux.org/include/linux/sdla_remora_proslic.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/sdla_remora_proslic.h 2006-08-30 10:07:15.000000000 +0000 @@ -0,0 +1,190 @@ +/* ProSlic Header File */ + +typedef struct { + unsigned char address; + unsigned char altaddr; + char *name; + unsigned short initial; +} alpha; + +typedef struct { + unsigned char chip_number; + unsigned char DTMF_digit; + unsigned char interrupt_line; + unsigned char hook_status; + unsigned long half_pulses[20]; /* Contains the time stamps of incomming half pulses. */ + unsigned char half_pulses_detected; /* Contains the number of half pulses detected. */ + unsigned char Pulse_digit; + unsigned long On_Hook_time; + unsigned long Off_Hook_time; +} chipStruct; + +/* Defines */ +#define LPT 0X378 + +#define IDA_LO 28 +#define IDA_HI 29 + +#define IAA 30 +#define ID_ACCES_STATUS 31 +#define IAS_BIT 1 + +#define I_STATUS 31 + +#define SPI_MODE 0 +#define PCM_MODE 1 +#define PCM_XMIT_START_COUNT_LSB 2 +#define PCM_XMIT_START_COUNT_MSB 3 +#define PCM_RCV_START_COUNT_LSB 4 +#define PCM_RCV_START_COUNT_MSB 5 +#define DIO 6 + +#define AUDIO_LOOPBACK 8 +#define AUDIO_GAIN 9 +#define LINE_IMPEDANCE 10 +#define HYBRID 11 +#define RESERVED12 12 +#define RESERVED13 13 +#define PWR_DOWN1 14 +#define PWR_DOWN2 15 +#define RESERVED16 16 +#define RESERVED17 17 +#define INTRPT_STATUS1 18 +#define INTRPT_STATUS2 19 +#define INTRPT_STATUS3 20 +#define INTRPT_MASK1 21 +#define INTRPT_MASK2 22 +#define INTRPT_MASK3 23 +#define DTMF_DIGIT 24 +#define RESERVED25 25 +#define RESERVED26 26 +#define RESERVED27 27 +#define I_DATA_LOW 28 +#define I_DATA_HIGH 29 +#define I_ADDRESS 30 +#define I_STATUS 31 +#define OSC1 32 +#define OSC2 33 +#define RING_OSC_CTL 34 +#define PULSE_OSC 35 +#define OSC1_ON__LO 36 +#define OSC1_ON_HI 37 +#define OSC1_OFF_LO 38 +#define OSC1_OFF_HI 39 +#define OSC2_ON__LO 40 +#define OSC2_ON_HI 41 +#define OSC2_OFF_LO 42 +#define OSC2_OFF_HI 43 +#define PULSE_ON__LO 44 +#define PULSE_ON_HI 45 +#define PULSE_OFF_LO 46 +#define PULSE_OFF_HI 47 +#define RING_ON__LO 48 +#define RING_ON_HI 49 +#define RING_OFF_LO 50 +#define RING_OFF_HI 51 +#define RESERVED52 52 +#define RESERVED53 53 +#define RESERVED54 54 +#define RESERVED55 55 +#define RESERVED56 56 +#define RESERVED57 57 +#define RESERVED58 58 +#define RESERVED59 59 +#define RESERVED60 60 +#define RESERVED61 61 +#define RESERVED62 62 +#define RESERVED63 63 +#define LINE_STATE 64 +#define ACTIVATE_LINE 0x11 +#define RING_LINE 0x44 +#define BIAS_SQUELCH 65 +#define BAT_FEED 66 +#define AUTO_STATE 67 +#define LOOP_STAT 68 +#define LOOP_DEBOUCE 69 +#define RT_DEBOUCE 70 +#define LOOP_I_LIMIT 71 +#define OFF_HOOK_V 72 +#define COMMON_V 73 +#define BAT_V_HI 74 +#define BAT_V_LO 75 +#define PWR_STAT_DEV 76 +#define PWR_STAT 77 +#define LOOP_V_SENSE 78 +#define LOOP_I_SENSE 79 +#define TIP_V_SENSE 80 +#define RING_V_SENSE 81 +#define BAT_V_HI_SENSE 82 +#define BAT_V_LO_SENSE 83 +#define IQ1 84 +#define IQ2 85 +#define IQ3 86 +#define IQ4 87 +#define IQ5 88 +#define IQ6 89 +#define RESERVED90 90 +#define RESERVED91 91 +#define DCDC_PWM_OFF 92 +#define DCDC 93 +#define DCDC_PW_OFF 94 +#define RESERVED95 95 +#define CALIBR1 96 +#define CALIBRATE_LINE 0x78 +#define NORMAL_CALIBRATION_COMPLETE 0x20 +#define CALIBR2 97 +#define RING_GAIN_CAL 98 +#define TIP_GAIN_CAL 99 +#define DIFF_I_CAL 100 +#define COMMON_I_CAL 101 +#define I_LIMIT_GAIN_CAL 102 +#define ADC_OFFSET_CAL 103 +#define DAC_ADC_OFFSET 104 +#define DAC_OFFSET_CAL 105 +#define COMMON_BAL_CAL 106 +#define DC_PEAK_CAL 107 + +/* Indirect Register (decimal) */ +#define DTMF_ROW_0_PEAK 0 +#define DTMF_ROW_1_PEAK 1 +#define DTMF_ROW2_PEAK 2 +#define DTMF_ROW3_PEAK 3 +#define DTMF_COL1_PEAK 4 +#define DTMF_FWD_TWIST 5 +#define DTMF_RVS_TWIST 6 +#define DTMF_ROW_RATIO_THRESH 7 +#define DTMF_COL_RATIO_THRESH 8 +#define DTMF_ROW_2ND_HARM 9 +#define DTMF_COL_2ND_HARM 10 +#define DTMF_PWR_MIN_THRESH 11 +#define DTMF_HOT_LIM_THRESH 12 +#define OSC1_COEF 13 +#define OSC1X 14 +#define OSC1Y 15 +#define OSC2_COEF 16 +#define OSC2X 17 +#define OSC2Y 18 +#define RING_V_OFF 19 +#define RING_OSC_COEF 20 +#define RING_X 21 +#define RING_Y 22 +#define PULSE_ENVEL 23 +#define PULSE_X 24 +#define PULSE_Y 25 +#define RECV_DIGITAL_GAIN 26 +#define XMIT_DIGITAL_GAIN 27 +#define LOOP_CLOSE_THRESH 28 +#define RING_TRIP_THRESH 29 +#define COMMON_MIN_THRESH 30 +#define COMMON_MAX_THRESH 31 +#define PWR_ALARM_Q1Q2 32 +#define PWR_ALARM_Q3Q4 33 +#define PWR_ALARM_Q5Q6 34 +#define LOOP_CLOSURE_FILTER 35 +#define RING_TRIP_FILTER 36 +#define THERM_LP_POLE_Q1Q2 37 +#define THERM_LP_POLE_Q3Q4 38 +#define THERM_LP_POLE_Q5Q6 39 +#define CM_BIAS_RINGING 40 +#define DCDC_MIN_V 41 +#define DCDC_XTRA 42 diff -Nur linux.org/include/linux/sdla_sdlc.h linux-2.6.17/include/linux/sdla_sdlc.h --- linux.org/include/linux/sdla_sdlc.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/sdla_sdlc.h 2006-08-30 10:07:15.000000000 +0000 @@ -0,0 +1,1250 @@ +/************************************************************************* + * wanpipe_sdlc.h Sangoma SDLC firmware API definitions + * + * Author: Nenad Corbic + * + * Copyright: (c) 2002 Sangoma Technologies Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the term of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + *=========================================================================== + * Jul 24, 2002 Nenad Corbic Initial Version + *======================================================================= + * + * Organization + * - Compatibility notes + * - Constants defining the shared memory control block (mailbox) + * - Interface commands + * - Return code from interface commands + * - Constants for the commands (structures for casting data) + * - UDP Management constants and structures + * + **************************************************************************/ + +/* + *************************************************************** + * * + * SDLCHDR.C is the 'C' header file for the Sangoma SDLC code. * + * * + *************************************************************** +*/ + + +/* + * $Log$ + * Revision 1.3 2004/09/28 21:47:30 sangoma + * *** empty log message *** + * + * Revision 1.2 2004/06/07 15:53:08 sangoma + * *** empty log message *** + * + * Revision 1.1.1.1 2002/11/25 09:20:00 ncorbic + * Wanpipe Linux Development + * + * Revision 1.1 2002/11/08 05:15:00 ncorbic + * *** empty log message *** + * + * + * Rev 1.1 25 Feb 1998 11:27:26 gideon + * Added the command READ_STATION_INFO_STRUCT and the + * 'general_operational_config_option' of DISABLE_RX_WHEN_TX. + * The code version is now 1.02. + * + * + * Rev 1.0 08 Aug 1996 10:58:00 gideon + * Initial revision. + * + * + */ + + +/* + Reserved data areas for this code are as follows: + 0x0010 - the adapter configuration data + byte passed by the loader + 0x4700 to 0x477F - primary receive buffer status table (128 bytes) + + 0x4780 - P0_ADDR_LAST_READ_RR0_BYTE (used by the external + status interrupt handler) + + 0x4781 - address of the CTS status (used by the external + status interrupt handler) + + 0x4800 to 0x57FF - primary receive buffer (this buffer is of size + 4096 bytes which is large enough to accomodate + at least four frames of maximum permitted length, + plus header length) + + 0xE000 to 0xE22F - SEND mailbox (560 bytes) + 0xE230 to 0xE45F - RECEIVE mailbox (560 bytes) + 0xE460 to 0xEEDF - reserved for later use (2688 bytes) + 0xEEE0 to 0xEEEF - general status interface bytes (16 bytes) + 0xEEE0 - number of received I-frames queued for the application + 0xEEE1 - global transmit buffer status + 0xEEE2 to 0xEEE3 - current exception conditions + 0xEEE4 - current modem status + 0xEEE5 - trace data available byte + 0xEEF0 to 0xEEFF - interrupt interface bytes (16 bytes) + 0xEEF0 - interrupt reporting byte + 0xEEF1 - interrupt permission byte + 0xEF00 to 0xEFFF - status bytes on a per station basis (256 bytes) + 0xF000 to 0xFFFF - trace buffer (4096 bytes) +*/ + +#ifndef _WANPIPE_SDLC_ +#define _WANPIPE_SDLC_ + +#pragma pack(1) + +/* absolute addresses of buffers and variables on the board */ +#define ADDR_DOWNLOADED_CONFIG_DATA 0x0010 /* the offset of the downloaded configuration data on the adapter */ +#define P0_OFF_PRI_RX_BFR_STATUS_TABLE 0x4700 /* Port 0 - the address of the primary status element table */ +#define P0_ADDR_LAST_READ_RR0_BYTE 0x4780 /* Port 0 - the address of the previously read status of RR0 */ +#define P0_ADDR_CTS_STATUS_BYTE 0x4781 /* Port 0 - address of the CTS status */ +#define BASE_ADDR_PRI_RX_BFR 0x4800 /* the base address of the primary receive DMA buffer */ +#define END_ADDR_PRI_RX_BFR 0x57FF /* the end address of the primary receive DMA buffer */ +#define BASE_ADDR_OF_MB_STRUCTS 0xE000 /* the base address of the mailbox area */ +#define ADDR_GLOBAL_NO_RX_I_FRMS_FOR_APP 0xEEE0 /* the address of the global number of I-frames available */ + /* for the application */ +#define ADDR_GLOBAL_TX_BFR_STATUS_BYTE 0xEEE1 /* the address of the global transmit buffer status byte */ +#define ADDR_EXCEPTION_COND_INTERFACE_WORD 0xEEE2 /* the address of the exception condition interface word */ +#define ADDR_CURR_MODEM_STAT_INTERFACE_BYTE 0xEEE4 /* the address of the current modem status interface byte */ +#define ADDR_TRACE_DATA_AVAILABLE_BYTE 0xEEE5 /* the address of the byte indicating the availablity of trace */ + /* data */ +#define ADDR_INTERRUPT_REPORT_INTERFACE_BYTE 0xEEF0 /* the address of the interrupt type reporting interface byte */ +#define ADDR_INTERRUPT_PERMIT_INTERFACE_BYTE 0xEEF1 /* the address of the interrupt permission interface byte */ +#define BASE_ADDR_STATION_INFO_INTERFACE_BYTES 0xEF00 /* the base address of the per-station status bytes */ +#define BASE_ADDR_TRACE_BFR 0xF000 /* the base address of the trace buffer */ +#define END_ADDR_TRACE_BFR 0xFFFF /* the end address of the trace buffer */ + + + +/* interface commands */ +#define SDLC_READ 0x00 /* receive an SDLC I-frame */ +#define SDLC_WRITE 0x01 /* transmit an SDLC I-frame */ +#define SET_SDLC_CONFIGURATION 0x10 /* set the SDLC operational configuration */ +#define READ_SDLC_CONFIGURATION 0x11 /* read the current SDLC configuration */ +#define SET_ADAPTER_OPERATING_FREQUENCY 0x12 /* set the adapter operating frequency */ +#define ENABLE_COMMUNICATIONS 0x13 /* enable communications */ +#define DISABLE_COMMUNICATIONS 0x14 /* disable communications */ +#define ADD_STATION 0x15 /* add and configure and SDLC station */ +#define DELETE_STATION 0x16 /* delete an SDLC station */ +#define ACTIVATE_STATION 0x17 /* activate an SDLC station */ +#define DEACTIVATE_STATION 0x18 /* deactivate an SDLC station */ +#define FLUSH_I_FRAME_BUFFERS 0x19 /* flush the I-frame buffers */ +#define READ_STATION_STATUS 0x20 /* read the status of a station */ +#define LIST_ADDED_STATIONS 0x21 /* return a list of 'added' stations */ +#define LIST_STATIONS_IN_NRM 0x22 /* return a list of stations currently in the NRM */ +#define LIST_STATIONS_WITH_I_FRMS_AVAILABLE 0x23 /* return a list of stations with I-frames available for the */ + /* application */ +#define READ_OPERATIONAL_STATISTICS 0x24 /* retrieve the operational statistics */ +#define FLUSH_OPERATIONAL_STATISTICS 0x25 /* flush the operational statistics */ +#define READ_STATION_INFO_STRUCT 0x26 /* return the STATION_INFORMATION structure to the application */ +#define SEND_TEST_FRAME 0x30 /* send a TEST frame */ +#define SEND_SIM_RIM_FRAME 0x31 /* send a SIM or a RIM frame */ +#define SEND_XID_RESPONSE_FRAME 0x32 /* send an XID response frame */ +#define SET_PRI_STATION_XID_I_FIELD 0x33 /* set the XID field for a primary SDLC station */ +#define LIST_PRI_STATIONS_ISSUING_XID_FRAMES 0x34 /* return a list of primary stations issuing XID frames */ +#define SET_MODEM_STATUS 0x40 /* set the DTR/RTS state */ +#define READ_MODEM_STATUS 0x41 /* read the current modem status (CTS and DCD status) */ +#define READ_COMMS_ERR_STATISTICS 0x42 /* read the communication error statistics */ +#define FLUSH_COMMS_ERR_STATISTICS 0x43 /* flush the communication error statistics */ +#define SET_INTERRUPT_TRIGGERS 0x50 /* set the interrupt triggers */ +#define READ_INTERRUPT_TRIGGERS 0x51 /* read the interrupt trigger configuration */ +#define SET_TRACE_CONFIGURATION 0x60 /* set the trace configuration */ +#define READ_TRACE_DATA 0x61 /* read trace data */ +#define READ_TRACE_STATISTICS 0x62 /* read the trace statistics */ +#define READ_CODE_VERSION 0x70 /* read the SDLC code version */ +#define READ_EXCEPTION_CONDITION 0x71 /* read any exception conditions from the adapter */ +#define DISCARD_INCOMMING_INFORMATION_FRAMES 0x72 /* discard incomming I-frames */ +#define BRIDGE_RECEIVER_AND_TRANSMITTER 0x73 /* bridge the receiver and transmitter */ +#define SET_APPLICATION_IRQ_TIMEOUT 0x74 /* set a timeout for the application to respond to an IRQ */ +#define READ_SDLC_ADAPTER_CONFIGURATION 0xA0 /* read the adapter type and operating speed */ +#define DUMMY_MB_COMMAND 0xFF /* a dummy command used internally */ + + + +/* return codes */ +#define COMMAND_OK 0x00 +#define OK 0x00 /* the interface call was successfull */ +#define SET_SDLC_CONFIG_BEFORE_ADD_STATION 0x01 /* set the SDLC configuration before a station is added */ +#define SET_SDLC_CONFIG_BEFORE_ENABLE_COMMS 0x01 /* set the configuration before communications are enabled */ +#define SET_SDLC_CONFIG_BEFORE_SET_INTS 0x01 /* set the configuration before enabling interrupts */ +#define INVALID_CONFIGURATION_DATA 0x01 /* the passed configuration data is invalid */ +#define COMMUNICATIONS_NOT_ENABLED 0x01 /* communications are not enabled */ +#define INVALID_SDLC_ADDRESS 0x02 /* the passed SDLC address is invalid */ +#define INVALID_TRACE_CONFIGURATION 0x02 /* the trace configuration data is invalid */ +#define TRACE_HAS_NOT_BEEN_ACTIVATED 0x02 /* the trace has not yet been activated */ +#define STATION_NOT_ADDED 0x03 /* the station has not been added */ +#define STATION_ALREADY_ADDED 0x03 /* the station has already been added */ +#define STATION_ALREADY_ACTIVATED 0x04 /* the station has already been activated */ +#define STATION_ALREADY_DEACTIVATED 0x04 /* the station has already been deactivated */ +#define STATION_DISCONNECTED 0x04 /* the station is currently disconnected */ +#define POLL_INTERVAL_INVALID 0x04 /* the set poll interval is invalid */ +#define INVALID_INTERRUPT_TMR_VALUE_SELECTED 0x04 /* the selected interrupt timer value is invalid */ +#define NO_RX_I_FRAMES_AVAILABLE_FOR_APP 0x05 /* no frames are available for the application */ +#define INVALID_FRAME_LENGTH 0x05 /* the passed transmit buffer length is invalid */ +#define NO_TRACE_DATA_AVAILABLE 0x05 /* no trace data is available for the application */ +#define I_FRM_NOT_QUEUED_FOR_TX 0x06 /* the I-frame has not been queued for transmission */ +#define CMND_INVALID_FOR_SECONDARY_STATION 0x06 /* the command is invalid for a secondary SDLC station */ +#define CMND_INVALID_FOR_PRIMARY_STATION 0x06 /* the command is invalid for a primary SDLC station */ +#define TEST_FRM_BFR_CURRENTLY_IN_USE 0x07 /* the TEST frame buffer is currently in use */ +#define XID_FRM_BFR_CURRENTLY_IN_USE 0x07 /* the XID frame buffer is currently in use */ +#define XID_I_FIELD_BFRS_FULL 0x07 /* the XID Information field buffers are all occupied */ +#define NO_XID_CMND_RECEIVED_FROM_PRI 0x08 /* no XID command has been received from the primary station */ +#define CMND_INVALID_FOR_CURRENT_SDLC_STATE 0x08 /* the command is invalid for the current SDLC state */ +#define PRI_STATION_ALREADY_HAS_XID_DEFINED 0x09 /* the primary station already has an XID field defined */ +#define ILLEGAL_COMMAND 0x10 /* the interface command used is invalid */ +#define BUSY_WITH_BAUD_CALIBRATION 0x40 /* the adapter is busy with a baud rate calibration */ +#define BAUD_CALIBRATION_FAILED 0x41 /* the adapter failed the baud rate calibration */ + + +/* miscellaneous constants used when executing mailbox commands */ + +/* for the SET_CONFIGURATION command */ +#define LGTH_CONFIG_DATA 0x1F /* the length of the configuration data */ +#define SECONDARY_STATION 0x00 /* the station is configured as a primary */ +#define PRIMARY_STATION 0x01 /* the station is configured as a secondary */ + +/* offset within the data area of various configuration parameters */ +#define OFF_STATION_CONFIG_IN_CFG_DATA 0x00 /* the offset of the station configuration */ +#define OFF_BAUD_RATE_IN_CFG_DATA 0x01 /* the offset of the baud rate */ +#define OFF_MAX_I_FIELD_LGTH_IN_CFG_DATA 0x05 /* the offset of the maximum I-field length */ +#define OFF_GENL_OP_CFG_BITS_IN_CFG_DATA 0x07 /* the offset of the operational configuration bits */ +#define OFF_PRI_STATION_SLOW_POLL_INTERVAL_IN_CFG_DATA 0x11 /* the offset of the primary station slow poll interval */ +#define OFF_SEC_STATION_RESPONSE_TO_IN_CFG_DATA 0x13 /* the offset of the secondary station response timeout */ +#define OFF_NO_CONSEC_SEC_TOs_IN_NRM_IN_CFG_DATA 0x15 /* the offset of the permitted number of consecutive */ + /* secondary stations timeouts */ +#define OFF_MAX_LGTH_I_FLD_PRI_XID_FRM_IN_CFG_DATA 0x17 /* the offset of the maximum length of the XID data */ + /* field for a primary station */ +#define OFF_OP_FLG_BIT_DELAY_IN_CFG_DATA 0x19 /* the offset of the opening flag bit delay within the data area */ +#define OFF_RTS_DROP_DELAY_IN_CFG_DATA 0x1B /* the offset of the RTS dropping delay within the data area */ +#define OFF_CTS_TIMEOUT_IN_CFG_DATA 0x1D /* the offset of the permitted CTS timeout within the data area */ + +/* minimum and maximum values for the configuration parameters */ +#define MAX_PERMITTED_BAUD_RATE 200000 /* the maximum permitted baud rate */ +#define MIN_PERMITTED_I_FIELD_LENGTH 1 /* the minimum permitted I-frame length */ +#define MAX_PERMITTED_I_FIELD_LENGTH 544 /* the maximum permitted I-frame length */ +#define MAX_ADD_OP_FLG_BIT_DELAY_COUNT 200 /* the maximum permitted opening flag bit delay */ +#define MAX_ADD_DROP_RTS_BIT_DELAY 200 /* the maximum permitted DRT drop bit delay */ +#define MIN_CTS_DELAY_1000THS_SEC 10 /* the minimum permitted CTS timeout bit delay (1/100ths second) */ +#define MAX_CTS_DELAY_1000THS_SEC 2000 /* the maximum permitted CTS timeout bit delay (1/100ths second) */ +#define MIN_PRI_STATION_SLOW_POLL_INTERVAL 1 /* the minimum slow poll interval */ +#define MAX_PRI_STATION_SLOW_POLL_INTERVAL 60000 /* the maximum slow poll interval */ +#define MIN_SEC_STATION_RESPONSE_TO 1 /* the minimum secondary station response timeout */ +#define MAX_SEC_STATION_RESPONSE_TO 15000 /* the maximum secondary station response timeout */ +#define MIN_NO_CONSEC_SEC_TOs_IN_NRM 0 /* the minimum number of consecutive secondary timeouts */ +#define MAX_NO_CONSEC_SEC_TOs_IN_NRM 200 /* the maximum number of consecutive secondary timeouts */ +#define MAX_LGTH_I_FLD_PRI_XID_FRAME 255 /* the maximum length of a primary station XID data field */ + +/* 'general_operational_config_bits' settings used by the SET_CONFIGURATION command */ +#define SWITCHED_CTS_RTS 0x0001 /* switched CTS/RTS */ +#define IDLE_FLAGS 0x0002 /* the line idle condition is flags (and not ones) */ +#define NRZI_ENCODING 0x0010 /* NRZI encoding */ +#define FM0_ENCODING 0x0020 /* FM0 encoding (used in a 4 wire, V.35 configuration) */ +#define APP_REQUESTS_PASSING_EXCEPT_COND 0x0100 /* exception conditions are only passed to the application on a */ + /* READ_EXCEPTION_CONDITION command */ +#define DISABLE_RX_WHEN_TX 0x0200 /* disable the receiver while transmitting a frame */ +#define INTERFACE_LEVEL_V35 0x8000 /* V.35 interface */ + + + +/************************************************************************ + * 'protocol_config_bits' + * settings used by the SET_CONFIGURATION command + ************************************************************************/ + +#define APP_TO_ISSUE_DISC_AFTER_RX_RD 0x0001 +/* the application is responsible for issuing a DISC when + * notified that an RD frame has been received */ + +#define APP_TO_ISSUE_SIM_AFTER_RX_RIM 0x0002 +/* the application is responsible for issuing a SIM when + * notified that an RIM frame has been received */ + +#define NRM_TIMEOUT_FOR_SECONDARY 0x0004 +/* the secondary will timeout while in the NRM (and + * automatically enter the NDM) if not polled by the + * primary at the configured poll rate */ + +#define PERMANENT_SEC_DISC_MODE 0x0008 +/* on reception of a DISC command, the secondary + * permanently enters the disconnected mode, and + * will issue DMs in response to incomming SNRMs + * (i.e, will not re-enter ABM until an ACTIVATE_STATION + * command is performed by the application) */ + +#define ISSUE_SNRM_AFTER_RX_DM_IN_NRM 0x0010 +/* a primary station should automatically issue + * a SNRM and attempt to re-enter the ABM after + * receiving a DM while in the NRM */ + +#define ISSUE_DISC_AFTER_RX_FRMR 0x0020 +/* a primary station should automatically issue a + * DISC (and not a SNRM) after receiving a FRMR + * while in the NRM */ + +/************************************************************ + * 'exception_condition_reporting_config' + * settings used by the SET_CONFIGURATION command + ************************************************************/ + + +#define DONT_REPORT_STATIONS_GOING_ACTIVE 0x01 +/* don't report stations going active */ + +#define DONT_REPORT_STATIONS_GOING_INACTIVE 0x02 +/* don't report stations going inactive */ + + +/************************************************************ + * 'modem_config_bits' + * settings used by the SET_CONFIGURATION command + ************************************************************/ + +#define DONT_RAISE_DTR_RTS_ON_EN_COMMS 0x01 +/* don't automatically raise DTR and RTS when + * performing an ENABLE_COMMUNICATIONS + * command and the ADD_STATION command */ + +#define MAX_POLL_INTERVAL 60000 +/* the maximum permitted poll interval + * for the READ_STATUS command */ + +#define LGTH_STATUS_DATA 0x06 +/* the number of bytes included in the status + * data (READ_STATUS) */ + +#define OFF_COMMS_STAT_IN_STATS_DATA 0x00 +/* the offset of the communications status + * within the data area */ + +#define OFF_NO_FRMS_TO_TX_IN_STATS_DATA 0x01 +/* the offset of the number of queued outgoing + * frames */ + +#define OFF_INT_REPORT_BYTE_IN_STATS_DATA 0x05 +/* the offset of the interrupt status byte + * within the data area */ + +/**************************************************** + * for the SET_INTERRUPT_TRIGGERS command + ***************************************************/ + +#define LGTH_INTERRUPT_TRIGGER_DATA 0x03 +/* the length of the interrupt trigger + * configuration data */ + +#define OFF_TRIGGER_BITS_IN_SET_INT_DATA 0x00 +/* offset of the interrupt trigger map within + * the data area */ + +#define OFF_TX_FRM_LGTH_IN_SET_INT_DATA 0x01 +/* offset of the transmit frame length within + * the data area */ + +#define OFF_INT_TIMER_VALUE_IN_SET_INT_DATA 0x01 +/* offset of the interrupt timer value within + * the data area */ + +#define MAX_INTERRUPT_TIMER_VALUE 60000 +/* the maximum permitted interrupt timer value */ + +/************************************************ + * for the OPERATE_DATALINE_MONITOR command + ************************************************/ + +#define OFF_LN_TRC_SETUP 0x00 +/* the offset within the mailbox structure data + * area of the line trace setup parameter */ + +#define OFF_TRC_DEACTIVATION_TMR_BYTE 0x01 +/* the offset within the mailbox of the trace + * deactivation timer */ + + +/************************************************ + * for the SET_APPLICATION_IRQ_TIMEOUT command + ************************************************/ + +#define OFF_IRQ_TO_IN_SET_APP_IRQ_TO_CMND 0x00 +/* offset of the IRQ timeout within the data area */ + +#define MIN_IRQ_TIMEOUT_VALUE 0x00 +/* the minimum permitted IRQ timeout */ + +#define MAX_IRQ_TIMEOUT_VALUE 5000 +/* the maximum permitted IRQ timeout */ + +/* miscellaneous commands */ +#define OFF_TX_BFR_SIZE_IN_DATA_AREA 0x0A +/* READ_CONFIGURATION - the offset of the + * transmit buffer size within the data area */ + +#define LGTH_COMMS_ERR_STAT_DATA 0x0A +/* READ_COMMS_ERR_STATISTICS - the number of + * bytes included in the communication error data */ + +#define LGTH_GLOBAL_OP_STATS 42 +/* the length of the global operational statistic data */ + +#define LGTH_SPECIFIC_STATION_STATUS 0x03 +/* the length of the station-specific status information */ + +#define LGTH_GLOBAL_STATION_STATUS 0x05 +/* the length of the general station information */ + +#define LGTH_CODE_VERSION_STRING 0x04 +/* READ_CODE_VERSION - the length of the code version string */ + +#define OFF_DISCARD_MODE_IN_DATA_AREA 0x00 +/* DISCARD_INCOMMING_INFORMATION_FRAMES - the + * offset of the discard mode parameter within + * the data area */ + +#define OFF_BRIDGE_MODE_IN_DATA_AREA 0x00 +/* BRIDGE_RECEIVER_AND_TRANSMITTER - the offset 00 + * of the bridging bridging mode parameter within + * the data area */ + + +/**************************************************** + * exception conditions reported to the application + ***************************************************/ + +#define EXCEPTION_CONDITION_BASE_VALUE 0x20 +/* a base value used for reporting exception conditions */ + +#define EXCEP_COND_STATE_CHANGE 0x20 +/* the SDLC station changed state */ + +#define EXCEP_COND_TIMEOUT_NRM 0x21 +/* a timeout occurred while the stations was in the NRM */ + +#define EXCEP_COND_RD_FRM_RX_WHILE_IN_NRM 0x22 +/* a RD was received while the link was in the NRM */ + +#define EXCEP_COND_DM_FRM_RX_WHILE_IN_NRM 0x23 +/* a DM was received while the link was in the NRM */ + +#define EXCEP_COND_SNRM_FRM_RX_WHILE_IN_NRM 0x24 +/* a SNRM was received while the link was in the NRM */ + +#define EXCEP_COND_RIM_FRM_RX 0x25 +/* a RIM was received */ + +#define EXCEP_COND_XID_FRM_RX 0x26 +/* an XID frame was received */ + +#define EXCEP_COND_TEST_FRM_RX 0x27 +/* a TEST frame was received */ + +#define EXCEP_COND_FRMR_FRM_RX_TX 0x28 +/* a FRMR condition occurred */ + +#define EXCEP_COND_CHANGE_IN_MODEM_STATUS 0x30 +/* a modem status change occurred */ + + +/**************************************************** + * clocking types + ****************************************************/ + +#define EXTERNAL_CLOCKING 0x00 /* external clocking */ +#define INTERNAL_CLOCKING 0x01 /* internal clocking */ + + + + +/* bit settings of RTS and DTR used for WR5 of the + * ESCC and channel 0 of the ASCI + * (SET_MODEM_STATUS command) */ +#define DTR_LOW_RTS_LOW 0x00 /* DTR low, RTS low */ +#define RTS_HIGH 0x02 /* RTS high */ +#define DTR_HIGH 0x80 /* RTS high */ + +/* modem status changes */ +#define DCD_HIGH 0x08 +#define CTS_HIGH 0x20 + +/**************************************************** + * definitions for triggering interrupts + **************************************************/ + +/* 'interrupt_triggers' bit mapping set by a + * SET_INTERRUPT_TRIGGERS command */ + +#define INTERRUPT_ON_RX_FRAME 0x01 +/* interrupt when an incomming frame is available + * for reception by the application */ + +#define INTERRUPT_ON_TX_FRAME 0x02 /* interrupt when a frame may be transmitted */ +#define INTERRUPT_ON_COMMAND_COMPLETE 0x08 /* interrupt when an interface command is complete */ +#define INTERRUPT_ON_EXCEPTION_CONDITION 0x10 /* interrupt on an exception condition */ +#define INTERRUPT_ON_TIMER 0x20 /* interrupt on a timer */ +#define INTERRUPT_ON_TRACE_DATA_AVAILABLE 0x40 /* interrupt if trace data is available for the application */ + +/* interrupt types indicated at 'ptr_interrupt_interface_byte' */ +#define NO_INTERRUPTS_PENDING 0x00 /* no interrups are currently pending */ +#define RX_INTERRUPT_PENDING 0x01 /* a receive interrupt is pending */ +#define TX_INTERRUPT_PENDING 0x02 /* a transmit interrupt is pending */ +#define COMMAND_COMPLETE_INTERRUPT_PENDING 0x08 /* a 'command complete' interrupt is pending */ +#define EXCEPTION_CONDITION_INTERRUPT_PENDING 0x10 /* an exception condition interrupt is pending */ +#define TIMER_INTERRUPT_PENDING 0x20 /* a timer interrupt is pending */ +#define TRACE_INTERRUPT_PENDING 0x40 /* a trace interrupt is pending */ + +/* bit mappings used for the transmit and receive interface bytes */ +#define NO_FRAMES_QUEUED_FOR_TRANSMISSION 0x00 /* no frames are currently queued for transmission */ +#define AT_LEAST_ONE_FRAME_QUEUED_FOR_TRANSMISSION 0x01 /* at least one frame is currently queued for transmission */ +#define NO_FRAMES_AVAILABLE_FOR_RECEPTION 0x00 /* no frames are currently queued for reception */ +#define AT_LEAST_ONE_FRAME_AVAILABLE_FOR_RECEPTION 0x01 /* at least one frame is currently queued for reception */ + + + +/* definitions for the interrupt level receive buffers */ +#define NUMBER_RX_INT_LVL_BUFFERS 4 /* the number of interrupt level receive buffers */ +#define SIZEOF_INT_LVL_RX_BFR_STRUCT 556 /* the size of each interrupt level receive structure */ +#define FIRST_INT_LVL_RX_STRUCTURE 0x00 /* the first interrupt level receive structure number */ +#define MAX_FRM_LGTH_INCL_HDR_CRC_BYTES 548 /* the maximum permitted frame length (including headed and CRC */ + /* bytes) */ + + + +/* for modem status initialization and reporting */ +#define LINE_LOW 0x00 /* the initial CTS and DCD status */ +#define OFF_MODEM_STAT 0x00 /* the offset within the mailbox structure data area of the modem */ + /* status byte in a READ_MODEM_STAT command */ +#define DCD_CTS_MASK 0x28 /* a mask to show bits 5 and 3 (CTS and DCD) when reading the */ + /* modem status in RR0 of the SCC */ + + +/* mailbox definitions */ +#define SIZEOF_MB_STRUCTS 560 /* the size of the mailbox structures */ +#define SIZEOF_MB_DATA_AREA 544 /* the size of the mailbox data area */ +#define NO_RESERVED_BYTES_IN_MB 0x06 /* the number of reserved bytes in the mailbox structure */ +#define SEND_MAILBOX 0x00 /* SEND mailbox structure */ +#define RECEIVE_MAILBOX 0x01 /* RECEIVE mailbox structure */ + + + +/* transmit and receive I-frame buffering */ +#define SIZEOF_RX_I_FRM_STORAGE_BFR_AREA 10000 /* the size of the I-frame receive buffer area */ +#define SIZEOF_TX_I_FRM_STORAGE_BFR_AREA 10000 /* the size of the I-frame transmit buffer area */ +#define MAX_NO_RX_I_FRM_STORAGE_BUFFERS 35 /* the maximum number of receive I-frame storage buffers */ +#define MAX_NO_TX_I_FRM_STORAGE_BUFFERS 35 /* the maximum number of transmit I-frame storage buffers */ + + + +/* SDLC control field types */ +#define RR 0x01 +#define RNR 0x05 +#define REJ 0x09 +#define INFORMATION 0x00 +#define UI 0x03 +#define SIM 0x07 +#define RIM 0x07 +#define DM 0x0F +#define UP 0x23 +#define DISC 0x43 +#define RD 0x43 +#define UA 0x63 +#define SNRM 0x83 +#define FRMR 0x87 +#define XID 0xAF +#define CFGR 0xC7 +#define TEST 0xE3 +#define BCN 0xEF + + + +/* constants for the formation and interpretation of SDLC frames */ +#define OFF_PF_BIT 0x04 /* offset of the P/F bit in the SDLC control field */ +#define OFF_Nr_FIELD 0x05 /* offset of the Nr bits in the SDLC control field */ +#define OFF_Ns_FIELD 0x01 /* offset of the Ns bits in the SDLC control field */ +#define REM_PF_BIT_MASK 0xEF /* mask to remove the P/F bit from an SDLC control field */ +#define SET_PF_BIT_MASK 0x10 /* mask to include the P/F bit in an SDLC control field */ +#define REM_rrr_MASK 0x1F /* mask to remove the rrr bits from an SDLC control field */ +#define REM_sss_MASK 0xF1 /* mask to remove the sss bits from an SDLC control field */ +#define EXTRACT_rrr_MASK 0xE0 /* mask to extract the rrr bits from an SDLC control field */ +#define EXTRACT_sss_MASK 0x0E /* mask to extract the sss bits from an SDLC control field */ +#define BIT_0_SET 0x01 /* used to test the received frame control field type */ +#define OFF_ADDR_FLD 0x00 /* the offset of the SDLC address field in the receiver buffer area */ +#define OFF_CNTRL_FLD 0x01 /* the offset of the SDLC control field in the receiver buffer area */ +#define OFF_INFO_FLD 0x02 /* the offset of the SDLC information field in the receiver buffer */ +#define SDLC_HDR_LGTH 0x02 /* the number of bytes in the SDLC address and control fields */ +#define CRC_LGTH 0x02 /* the number of bytes in the CRC field */ +#define BROADCAST_ADDRESS 0xFF /* the SDLC broadcast address */ + + + +/* overall SDLC states */ +#define NDM 0x00 /* the device is currently in the NDM */ +#define NRM 0x01 /* the device is in the NRM (information transfer mode) */ + + + +/* definitions for constructing the I-field for FRMR frames */ +#define LGTH_FRMR_I_FLD 0x03 /* the length of a FRMR I-field */ +#define OFF_C_FLD_FRMR 0x02 /* the offset within the FRMR I-field of the control field of the */ + /* rejected command */ +#define OFF_Nr_Ns_FLD_FRMR 0x03 /* the offset within the FRMR I-field of the Nr and Ns counts of */ + /* the station reporting the frame reject */ +#define OFF_STATUS_FLD_FRMR 0x04 /* the offset within the FRMR I-field of the FRMR status field */ +#define FRMR_STAT_CTRL_FLD_INVALID 0x01 /* the control field of the received frame was invalid */ +#define FRMR_STAT_I_FLD_PRESENT 0x02 /* the received frame was invalid as it contained an I-field */ + /* which is not permitted with the command */ +#define FRMR_STAT_I_FLD_TOO_LONG 0x04 /* the I-field in the received frame exceeded the configured */ + /* maximum */ +#define FRMR_STAT_RX_Nr_INVALID 0x08 /* the received Nr count is invalid */ +#define FRMR_STAT_REPEAT_ORG_FRMR 0x80 /* a bit setting if the original FRMR must be retransmitted */ + + + +/* definitions for the SDLC state machine */ + +/* state when setting up to transmit a frame */ +#define SENDING_I_FRAME 0x00 /* sending an I-frame */ +#define SENDING_RR0 0x01 /* sending an RR (P/F bit reset) */ +#define SENDING_RR1 0x02 /* sending an RR (P/F bit set) */ +#define SENDING_RNR0 0x03 /* sending an RNR (P/F bit reset) */ +#define SENDING_RNR1 0x04 /* sending an RNR (P/F bit set) */ +#define SENDING_REJ0 0x05 /* sending an REJ (P/F bit reset) */ +#define SENDING_REJ1 0x06 /* sending an REJ (P/F bit set) */ +#define SENDING_SNRM 0x10 /* sending a SNRM */ +#define SENDING_UA 0x11 /* sending a UA */ +#define SENDING_DISC_RD 0x12 /* sending a DISC or RD */ +#define SENDING_DM 0x13 /* sending a DM */ +#define SENDING_SIM_RIM 0x14 /* sending a SIM or RIM */ +#define SENDING_XID 0x15 /* sending an XID */ +#define SENDING_TEST 0x16 /* sending a TEST frame */ +#define SENDING_FRMR 0x17 /* sending a FRMR */ + +/* waiting to receive a frame */ +#define AWAITING_INCOMMING_FRAME 0x20 /* awaiting an incomming frame */ +#define WAITING_TO_POLL_SECONDARY 0x21 /* waiting to poll a secondary device */ + +/* states after transmitting a frame */ +#define I_FRAME_TRANSMITTED 0x30 /* an I-frame has been transmitted */ +#define RR1_TRANSMITTED 0x31 /* an RR (P/F bit set) has been transmitted */ +#define RNR1_TRANSMITTED 0x32 /* an RNR (P/F bit set) has been transmitted */ +#define REJ1_TRANSMITTED 0x33 /* an REJ (P/F bit set) has been transmitted */ +#define SNRM_TRANSMITTED 0x34 /* a SNRM has been transmitted */ +#define DISC_TRANSMITTED 0x35 /* a DISC frame has been transmitted */ +#define SIM_TRANSMITTED 0x36 /* a SIM has been transmitted */ +#define TEST_TRANSMITTED 0x37 /* a TEST frame has been transmitted */ +#define XID_TRANSMITTED 0x38 /* an XID frame has been transmitted */ + + + +/* definitions for the 'status' variable in the STATION_INFORMATION structure */ +#define STATION_UNINITIALIZED 0x0000 /* the station is uninitialized */ +#define STATION_ADDED 0x0001 /* the station has been added */ +#define STATION_ACTIVATED 0x0002 /* the station has been activated */ +#define STATION_IN_NRM 0x0004 /* the station is in the NRM */ +#define STATION_IN_FRMR_MODE 0x0008 /* the station is in the FRMR mode */ +#define PRI_STATION_HAS_XID_DEFINED 0x0010 /* the primary station has an XID defined */ +#define SEC_STATION_HAS_RX_XID_CMND 0x0010 /* the secondary station has received an XID command */ +#define REMOTE_STATION_FLOW_CTRL_BLOCKED 0x0100 /* the remote station is flow control blocked */ +#define LOCAL_STATION_FLOW_CTRL_BLOCKED 0x0200 /* the local station is flow control blocked */ +#define LOCAL_STATION_SENDING_REJ 0x0400 /* the local station is issuing a REJ */ +#define APP_CMND_SND_SIM_RIM_FRM 0x0800 /* the station must issue a SIM or RIM frame */ +#define APP_CMND_SND_TEST_FRM 0x1000 /* the station must issue a TEST frame */ +#define APP_CMND_SND_XID_FRM 0x2000 /* the station must issue an XID frame */ +#define APP_CMND_SND_SNRM_FRMR_FRM 0x4000 /* the station must issue a SNRM or FRMR frame */ +#define APP_CMND_SND_DISC_RD_FRM 0x8000 /* the station must issue a DISC or RD frame */ + +/* a test value to see if an asynchronous frame must be issued at this station */ +#define ISSUE_APP_DRIVEN_FRAME (APP_CMND_SND_TEST_FRM | APP_CMND_SND_XID_FRM | APP_CMND_SND_SNRM_FRMR_FRM | APP_CMND_SND_DISC_RD_FRM | APP_CMND_SND_SIM_RIM_FRM) + + + +/* definitions for the setting of the 'exception_cond_for_app' word */ +#define STATIONS_CHANGED_STATE 0x0001 +/* the station has changed state */ + +#define RESERVED_FOR_STATIONS_GOING_INACTIVE 0x0002 +/* used when the station becomes inactive */ + +#define REMOTE_STATION_TIMEOUT_NRM 0x0010 +/* a timeout occurred while the link was in the NRM */ + +#define RD_RX_FROM_SEC_WHILE_IN_NRM 0x0020 +/* a RD frame has been received from the secondary station */ + +#define DM_RX_FROM_SEC_WHILE_IN_NRM 0x0040 +/* a DM frame has been received from the secondary station */ + +#define RIM_FRM_RECEIVED_FROM_SECONDARY 0x0080 +/* a RIM frame has been received from the secondary station */ + +#define XID_FRM_AVAILABLE_FOR_APPLICATION 0x0100 +/* a XID frame is available for the application */ + +#define TEST_FRM_AVAILABLE_FOR_APPLICATION 0x0200 +/* a TEST frame is available for the application */ + +#define FRMR_CONDITION_TO_REPORT 0x0400 +/* there is a FRMR condition to report */ + +#define SNRM_RX_FROM_PRI_WHILE_IN_NRM 0x0800 +/* a SNRM was received from the primary station + * while the link was in the NRM */ + +#define CHANGE_IN_MODEM_STATUS 0x8000 +/* a change in modem status occurred */ + + + +/* definitions for TEST/trace receive error buffer usage */ +#define MAX_LGTH_TEST_FRAME 265 +/* the maximum length of a TEST frame */ + +#define TEST_TRC_RX_ERR_FRM_BFR_NOT_IN_USE 0x0000 +/* the buffer is available for use */ + +#define TEST_TRC_RX_ERR_FRM_BFR_IN_USE 0x8000 +/* the buffer is in use */ + + + +/* definitions for XID buffer usage */ +#define SIZEOF_XID_I_FIELD_STORAGE_BFR 1000 +/* the size of the XID data storage buffer */ + +#define MAX_NUMBER_XID_I_FIELDS_STORED 100 +/* the maximum number of XID data fields stored at any one time */ + +#define MAX_LGTH_XID_FRAME 265 +/* the maximum length of an XID frame */ + +#define XID_FRM_BFR_NOT_IN_USE 0x0000 +/* the buffer is available for use */ + +#define XID_FRM_BFR_IN_USE 0x8000 +/* the buffer is in use */ + + + +/* flags used by the 'send_Supervisory_or_I_frame()' + * procedure to see if an I-frame may be transmitted */ +#define I_FRAME_TRANSMISSION_FORBIDDEN 0x00 +/* I-frame transmission is forbidden */ + +#define I_FRAME_TRANSMISSION_PERMITTED 0x01 +/* I-frame transmission is permitted */ + + + +/* bit mappings for the user interface byte on a + * per station basis */ +#define STATION_IS_IN_NRM 0x01 +/* the station is in the NRM */ + +#define STATION_HAS_I_FRM_FOR_APP 0x10 +/* the station has incomming I-frames available */ + +#define TX_WINDOW_OPEN_FOR_STATION 0x20 +/* the transmit window is open for this station */ + +#define SET_ALL_STATION_INTERFACE_BITS 0xFF +/* set all interface bits for this station */ + + + +/* bit settings for the interface byte + * ADDR_GLOBAL_TX_BFR_STATUS_BYTE */ + +#define NO_SPACE_AVAILABLE_IN_TX_BFR 0x00 +/* no space is available in the global transmit buffer */ + +#define SPACE_AVAILABLE_IN_TX_BFR 0x01 +/* space is currently available in the global transmit buffer */ + + + +/* definitions for line tracing bit settings for the + * 'line_trace_config' variable */ + +#define TRACE_ACTIVE 0x01 /* the trace is active */ +#define TRACE_TIMER_ACTIVE 0x02 /* the trace timer is active */ +#define TRACE_DELAY_MODE 0x04 /* enable the trace delay mode */ +#define FLUSH_TRACE_STATISTICS 0x08 /* flush the trace statistics */ +#define TRACE_I_FRMS 0x10 /* trace SDLC I-frames */ +#define TRACE_SUPERVISORY_FRMS 0x20 /* trace Supervisory frames */ +#define TRACE_UNNUM_FRMS 0x40 /* trace Unnumbered frames */ +#define RETURN_TRC_SETUP 0x80 /* return the current line trace setup to the user */ + +/* the 'trc_deactivation_tmr' */ +#define MAX_DEACTIVATION_TMR_VALUE 0x80 /* the maximum timer value */ +#define HIGH_FOUR_BITS_OF_DEAC_TMR 0xF0 /* mask for preserving the high 4 bits of this timer */ + +/* trace types */ +#define TRC_INCOMMING_FRAME 0x00 /* trace an incomming frame */ +#define TRC_OUTGOING_FRAME 0x01 /* trace an outgoing frame */ +#define TRC_FRAME_ERROR 0x02 /* trace a frame error */ + +/* trace error types */ +#define NO_TRC_ERR 0x00 /* no trace error has occured */ +#define TRC_RX_ABORT_ERR 0x12 /* trace a received abort frame */ +#define TRC_RX_CRC_ERR 0x22 /* trace a received frame with a CRC error */ +#define TRC_RX_OVRN_ERR 0x32 /* trace a received frame with a receiver overrun error */ +#define TRC_RX_EX_FRM_LGTH 0x42 /* trace a received frame of excessive length */ +#define TRC_TX_ABORT_TX_INT 0x72 /* trace an outgoing frame aborted due to a missed transmit */ + /* interrupt */ +#define TRC_TX_ABORT_UND_INT 0x82 +/* trace an outgoing frame aborted due to + * a missed transmit underrun interrupt */ + +/* general parameters for line tracing */ +#define LGTH_LNE_TRC_STR_HDR 14 +/* the header length of the structure used for line tracing */ + +#define DUMMY_CRC_TX_TRC 0xFFFF +/* the CRC used for outgoing frames */ + +#define RX_STATUS_BYTE_TRACE_ACTIVE 0x80 +/* bit setting of the 'rx_status_byte' to indicate + * that the trace is active */ + +#define LGTH_TRACE_STATISTIC_DATA 0x08 +/* the length of the trace statistic data */ + +/* bit settings for the interface byte + * ADDR_TRACE_DATA_AVAILABLE_BYTE */ + +#define NO_TRACE_DATA_CURRENLY_AVAILABLE 0x00 +/* trace data is available */ + +#define TRACE_DATA_CURRENLY_AVAILABLE 0x01 +/* no trace data is available */ + + +/* the change in station status - used when + * checking to see if we must report this status + * change to the application */ + +#define STATION_ENTERING_NRM 0x01 +/* the station is entering NRM */ + +#define STATION_ENTERING_NDM 0x02 +/* the station is entering NDM */ + + + +/* general constants */ +#define MAX_SDLC_STATIONS_SUPPORTED 255 +/* the maximum number of SDLC addresses + * supported (254 "real" addesses plus an + * all-poll address) */ + +#define HIGHEST_SDLC_ADDRESS 0xFE +/* the highest valid SDLC station address */ + +#define SDLC_WINDOW 0x07 +/* the SDLC window */ + +#define HIGHEST_TIME_CONSTANT_VALUE 256 +/* the highest time constant value permitted + * when setting the baud rate */ + +#define NUMBER_BITS_IN_FLAG_CHAR 8 +/* the number of bits in the HDLC flag character */ + +#define NUMBER_BITS_IN_FIVE_CHARS 40 +/* the number of bits in five characters */ + +#define PROCESS_NEXT_STATION 0x80 +/* an indication that the primary station must + * process the next station in the queue */ + +#define INTERNAL_I_FRM_BFR_FLUSH 0x80 +/* a dummy command used for an internal I-frame buffer flush */ + +#define DEFAULT_APP_IRQ_RESPONSE_TIMEOUT 250 +/* the default application IRQ timeout value */ + +#define RTS_LOW 0x00 /* the initial state of RTS */ +#define NO 0x00 /* logical 'no' */ +#define YES 0x01 /* logical 'yes' */ +#define RESET 0x00 /* flag in a reset state */ +#define SET 0x01 /* flag in a set state */ +#define BIT_1_SET 0x02 /* bit one set mask */ +#define ZERO 0x00 /* zero count */ + +#define HIGH_BIT_SET_IN_UNSIGNED_CHAR 0x80 +/* test for the high bit being set in an + * unsigned character */ + +/* general byte counts */ + +#define ONE_BYTE 0x01 +#define TWO_BYTES 0x02 +#define THREE_BYTES 0x03 +#define FOUR_BYTES 0x04 +#define TWENTY_BYTES 20 +#define FOUR_BITS 4 +#define EIGHT_BITS 8 + + + +/* a general head/tail buffer list used for linked list pragmatics */ +typedef struct { + char head; + char tail; +} BFR_LIST; + + + +/* the I-frame receive structure */ +typedef struct { + char *ptr_Rx_I_frm; /* a pointer to the I-frame */ + unsigned lgth_Rx_I_frm; /* the length of the I-frame */ + char PF_bit; /* the P/F bit as received */ +} RX_I_FRAME_STRUCTURE; + + + +/* the I-frame transmit structure */ +typedef struct { + char *ptr_Tx_I_frm; /* a pointer to the I-frame */ + unsigned lgth_Tx_I_frm; /* the length of the I-frame */ + char PF_bit; /* the P/F bit to be transmitted */ +} TX_I_FRAME_STRUCTURE; + + + +/* SDLC station statistics */ +/* Note - a number of the statistics only use + * four bits so as to save on data space. + * These statistics start at 0 and increment to a + * maximum value of 15, before rotating over + * the top to 1. */ + +typedef struct { + unsigned no_I_frms_Rx_and_stored; /* the number of I-frames received and stored */ + char I_frms_Rx_seq_err_no_I_fld; /* low: no I-frames Rx out of sequence, high: no I-frames Rx */ + /* with no I-field */ + char frms_Rx_bad_state_reserved; /* low: no frames Rx in incorrect state, high: reserved */ + unsigned no_I_frms_Tx_and_acknowledged; /* the number of I-frames transmitted and acknowledged */ + char no_I_frms_retransmitted; /* the number of I-frames re-transmitted */ + char RR_statistics; /* low: no RR frames Tx, high: no RR frames Rx */ + char RNR_statistics; /* low: no RNR frames Tx, high: no RNR frames Rx */ + char REJ_statistics; /* low: no REJ frames Tx, high: no REJ frames Rx */ + char TEST_statistics; /* low: no TEST frames Tx, high: no TEST frames Rx */ + char XID_statistics; /* low: no XID frames Tx, high: no XID frames Rx */ + char DISC_RD_statistics; /* primary - low: no DISC frames Tx, high: no RD frames Rx */ + /* secondary - low: no RD frames Tx, high: no DISC frames Rx */ + char SNRM_UA_statistics; /* primary - low: no SNRM frames Tx, high: no UA frames Rx */ + /* secondary - low: no UA frames Tx, high: no SNRM frames Rx */ + char DM_FRMR_statistics; /* primary - low: no DM frames Rx, high: no FRMR frames Rx */ + /* secondary - low: no DM frames Tx, high: no FRMR frames Tx */ + char SIM_RIM_statistics; /* primary - low: no SIM frames Tx, high: no RIM frames Rx */ + /* secondary - low: no RIM frames Tx, high: no SIM frames Rx */ + char timeout_SNRM_DISC_statistic; /* primary - low: no timeouts on SNRM frames Tx, high: no */ + /* timeouts on DISC frames Tx */ + char timeout_SUP_I_SIM_statistic; /* primary - low: no timeouts on SUP or I frames Tx, high: no */ + /* timeouts on SIM frames Tx */ + /* secondary - low: no timeouts while in NRM */ + char timeout_TEST_XID_statistic; /* primary - low: no timeouts on TEST frames Tx, high: no */ + /* timeouts on XID frames Tx */ +} STATION_STATISTICS; + + + +/* Secondary SDLC device parameters for keeping track + * of the status, sequence numbers etc. of the + * SDLC devices */ +typedef struct { + + /* general variables */ + unsigned status; /* the current station status */ + char internal_SDLC_state; /* the state of the SDLC device (used for the state machine) */ + unsigned state_timer; /* the station state timer */ + unsigned poll_timer_interval; /* primary - the number of milliseconds between polls */ + /* secondary - the maximum permitted time between polls while */ + /* in the NRM before a secondary station enters the NDM */ + char no_consec_secondary_timeouts; /* the number of consecutive secondary station timeouts */ + /* transmit variables */ + char no_I_frms_queued_for_Tx; /* the number of I-frames queued for transmission */ + char no_Tx_I_frms_awaiting_acknowledgement; /* the number of transmitted I-frames awaiting acknowledgement */ + char Ns_variables; /* low nibble - the number of the last I-frame transmitted */ + /* high nibble - the number of the last I-frame acknowledged */ + char I_frm_Tx_ack_status; /* the I-frame transmit/acknowledgment status */ + /* receive variables */ + char Nr_variables; /* low nibble - the number of the next I-frame we expect to */ + /* receive */ + /* high nibble - the number of I-frames currently available for */ + /* reception by the application statistics */ + STATION_STATISTICS statistics; /* the station statistics */ + +} STATION_INFORMATION; + + + +/* the structure for handling primary station XID data fields */ +typedef struct { + char SDLC_address; /* the SDLC address associated with this XID field */ + char length_XID_I_field; /* the length of the XID data field */ +} XID_INFORMATION_STRUCT; + + + + +/* definitions for primary receive buffering */ +/* the primary receive status element structure */ +typedef struct { + char opp_flag; /* the 'opp_flag' */ + char *ptr_base_nxt_Rx_frame; /* a pointer to the physical base address of the next frame */ + char reserved; /* reserved */ +} PRI_RX_STAT_EL_STRUCT; + +#define MAX_NO_PRI_RX_BFR_STATUS_ELS 32 /* the maximum number of primary receive status elements */ +#define MIN_NO_RECEIVE_BFRS 4 /* the minimum number of receive buffers */ +#define MAX_NO_RECEIVE_BFRS 32 /* the maximum number of receive buffers */ +#define SIZEOF_PRI_RX_STATUS_ELEMENT 0x04 /* the size of a primary receive status element */ +#define P0_MAX_SIZE_PRI_RX_BFR 0xF000 /* Port 0 - for 128K board, the maximum size DMA Rx buffer goes */ + /* from 0x10000 to 0x1EFFF (if no transmit buffering is used) */ +#define P0_SIZE_PRI_RX_BFR_256K_RAM 0xF000 /* Port 0 - for 256K board, the DMA Rx buffer always goes from */ + /* 0x10000 to 0x1EFFF, irrespective of the size of the Tx buffer */ +#define P0_RX_DMA_AREA_BASE_ADDR_BYTE 0x00 /* Port 0 - the high byte of the base address of the DMA Rx */ + /* buffer area */ +#define P0_RX_DMA_AREA_BASE_ADDR 0x10000 /* Port 0 - the base address of the DMA Rx buffer area */ +#define MAX_CONSEC_RX_BFRS_HANDLED 0x04 /* the maximum consecutive number of Rx buffers handled before */ + /* continuing with the main 'C' loop */ + +/* the setting of the 'opp_flag' in the receive status element */ +#define PRI_BFR_QUEUED_BUT_NOT_FREED 0x08 /* a flag indicating that the primary receive buffer has been */ + /* queued for application processing, but not yet freed by the */ + /* application */ +#define PRI_RX_BFR_AVAIL 0x80 /* bit to be set in the 'opp_flag' of the primary Rx status */ + /* element to indicate that this element is available for */ + /* processing by the application */ + +/* Z80 op codes for resetting a specified bit in the L register */ +#define OP_CODE_RES_4_L 0xA5 /* reset bit 4 */ +#define OP_CODE_RES_5_L 0xAD /* reset bit 5 */ +#define OP_CODE_RES_6_L 0xB5 /* reset bit 6 */ +#define OP_CODE_RES_7_L 0xBD /* reset bit 7 */ + +/* definitions for the 'P0_Tx_Rx_cfg' */ +#define TX_RX_CFG_IDLE_MARK 0x01 /* we are configured to idle mark */ +#define TX_RX_CFG_SW_CTS_RTS 0x02 /* we are configured for switched CTS/RTS */ + + +/* definitions for the 'P0_Tx_status_byte' */ +#define TX_STAT_DROP_RTS_AFTR_TX 0x01 /* we must drop RTS after frame transmission */ +#define TX_STAT_IDLE_FLGS_AFTR_TX 0x02 /* we must idle flags after frame transmission */ +#define TX_STAT_RTS_HI 0x08 /* RTS is currently set high */ +#define TX_STAT_WT_CTS_HI 0x10 /* we are waiting for CTS to be set high */ +#define TX_STAT_CURR_IDLE_FLAGS 0x20 /* we are currently idling flags */ +#define TX_STAT_OPEN_FLG_TMR_ACTIVE 0x40 /* we have started a timer for transmitting an opening flag */ + /* sequence */ +#define TX_STAT_CLOSE_FLG_TMR_ACTIVE 0x80 /* we have started a timer for transmitting a closing flag */ + /* sequence */ + + +/* definitions for the 'P0_ESCC_WR10_cfg' */ +#define ESCC_WR10_NRZ_IDLE_FLAGS 0x80 /* NRZ, idle flags */ +#define ESCC_WR10_ENABLE_NRZI 0x20 /* enable NRZI */ +#define ESCC_WR10_ENABLE_IDLE_MARK 0x08 /* enable 'idle mark' */ + + +/* settings for the 'error_flag' */ +#define RX_FRM_ABORT 0x01 /* the incoming frame was aborted */ +#define RX_FRM_CRC_ERROR 0x02 /* the incoming frame has a CRC error */ +#define RX_FRM_OVERRUN_ERROR 0x04 /* the incoming frame has an overrun error */ + + +#define ONLY_INCL_ABORT_BIT_IN_RR0 0x80 /* only include the break/abort bit in the read RR0 byte */ + + +/* definitions for the 'P0_baud_cal_status' variable */ +#define BAUD_CAL_BUSY 0x01 /* busy with baud calibration */ +#define BAUD_CAL_COMPLETED 0x02 /* baud calibration has been completed */ +#define BAUD_CAL_COMPUTE_BAUD 0x04 /* the baud rate must be computed */ +#define BAUD_CAL_FAIL_NO_CLK 0x10 /* baud calibration has failed - no Tx clock */ +#define BAUD_CAL_FAIL_BAUD_HI 0x20 /* baud calibration has failed - Tx clock speed too high */ +#define BAUD_CAL_SUCCESSFUL 0x80 /* baud calibration was successful */ + + + +/* constants for indicating the modem status */ +#define SHOW_CHANGE_IN_DCD_OCCURRED 0x04 /* a change in DCD occured */ +#define SHOW_CHANGE_IN_CTS_OCCURRED 0x10 /* a change in CTS occured */ +#define SHOW_CTS_TIMEOUT_FAILURE_OCCURRED 0x80 /* a CTS timeout occurred */ + + +/* Special UDP drivers management commands */ +#define CPIPE_ENABLE_TRACING 0x50 +#define CPIPE_DISABLE_TRACING 0x51 +#define CPIPE_GET_TRACE_INFO 0x52 +#define CPIPE_GET_IBA_DATA 0x53 +#define CPIPE_FT1_READ_STATUS 0x54 +#define CPIPE_DRIVER_STAT_IFSEND 0x55 +#define CPIPE_DRIVER_STAT_INTR 0x56 +#define CPIPE_DRIVER_STAT_GEN 0x57 +#define CPIPE_FLUSH_DRIVER_STATS 0x58 +#define CPIPE_ROUTER_UP_TIME 0x59 +#define CPIPE_MPPP_TRACE_ENABLE 0x60 +#define CPIPE_MPPP_TRACE_DISABLE 0x61 +#define CPIPE_TE1_56K_STAT 0x62 /* TE1_56K */ +#define CPIPE_GET_MEDIA_TYPE 0x63 /* TE1_56K */ +#define CPIPE_FLUSH_TE1_PMON 0x64 /* TE1 */ +#define CPIPE_READ_REGISTER 0x65 /* TE1_56K */ +#define CPIPE_TE1_CFG 0x66 /* TE1 */ + +/* Driver specific commands for API */ +#define CHDLC_READ_TRACE_DATA 0xE4 /* read trace data */ +#define TRACE_ALL 0x00 +#define TRACE_PROT 0x01 +#define TRACE_DATA 0x02 + +#define UDPMGMT_SIGNATURE "STPIPEAB" +#define UDPMGMT_UDP_PROTOCOL 0x11 + + + +typedef struct SDLC_CONFIGURATION { + + /* configuration variables */ + /* NOTE - these variables must be kept in this + * order and so must be initialized */ + + /* the station configuration (primary or secondary) */ + unsigned char station_configuration; + /* the baud rate to be generated */ + unsigned long baud_rate; + /* the maximum permitted Information field length supported */ + unsigned short max_I_field_length; + /* miscellaneous operational configuration bits */ + unsigned short general_operational_config_bits; + /* miscellaneous protocol configuration bits */ + unsigned short protocol_config_bits; + /* bits to specify which exception conditions are reported to the application */ + unsigned short exception_condition_reporting_config; + /* modem operation configuration bits */ + unsigned short modem_config_bits; + /* the statistics format byte */ + unsigned short statistics_format; + /* the slow poll interval for a primary station (milliseconds) */ + unsigned short pri_station_slow_poll_interval; + /* the permitted secondary station_response timeout (milliseconds) */ + unsigned short permitted_sec_station_response_TO; + /* the number of consecutive secondary timeouts while */ + /* in the NRM before a SNRM is issued */ + unsigned short no_consec_sec_TOs_in_NRM_before_SNRM_issued; + /* the maximum Information field length permitted in an XID */ + /* frame sent by a primary station */ + unsigned short max_lgth_I_fld_pri_XID_frame; + /* the additional bit delay before transmitting the opening */ + /* character in a frame */ + unsigned short opening_flag_bit_delay_count; + /* the additional bit delay before dropping RTS */ + unsigned short RTS_bit_delay_count; + /* the permitted CTS timeout for switched CTS/RTS configurations */ + /* (in 1000ths/second) */ + unsigned short CTS_timeout_1000ths_sec; + /* the adapter type and the CPU speed */ + unsigned char SDLA_configuration; + +}SDLC_CONFIGURATION_STRUCT; + +typedef struct { + unsigned char CHDLC_interrupt_triggers; /* CHDLC interrupt trigger configuration */ + unsigned char IRQ; /* IRQ to be used */ + unsigned short interrupt_timer; /* interrupt timer */ + unsigned short misc_interrupt_bits; /* miscellaneous bits */ +}SDLC_INT_TRIGGERS_STRUCT; + +/* the interrupt information structure */ +typedef struct { + unsigned char interrupt_type; /* type of interrupt triggered */ + unsigned char interrupt_permission; /* interrupt permission mask */ + unsigned char int_info_reserved[14]; /* reserved */ +} INTERRUPT_INFORMATION_STRUCT; + +/* the communications error statistics structure */ +typedef struct { + char Rx_overrun_err_cnt; + char CRC_err_cnt; + char Rx_abort_cnt; + char Rx_frm_lgth_err_cnt; + char Tx_abort_cnt; + char Tx_underrun_cnt; + char msd_Tx_und_int_cnt; + char no_CTS_resp_to_RTS_cnt; + char DCD_state_change_cnt; + char CTS_state_change_cnt; +} COMMS_ERROR_STATS_STRUCT; + + +typedef struct { + + unsigned long total_no_frms_Rx; + unsigned long total_no_I_frms_Rx_and_stored; + unsigned long total_no_frms_Tx; + unsigned long total_no_I_frms_Tx_and_acknowledged; + unsigned no_frames_Rx_address_invalid; + unsigned no_frames_Rx_on_unconfigured_stations; + unsigned no_short_frames_Rx; + unsigned no_unsupported_frames_Rx; + unsigned no_frms_Rx_incompat_station_config; + unsigned frm_Rx_in_incorrect_state; + unsigned no_Rx_XID_frms_disc_bfr_full; + unsigned no_Rx_TEST_frms_disc_bfr_full; + unsigned no_Rx_FRMR_frms_disc_bfr_full; + unsigned Rx_resp_broadcast_XID_added_station; + unsigned Rx_frm_discards_int_lvl; + unsigned no_Tx_bridge_discard_count; + unsigned no_IRQ_timeouts; + +}SDLC_OPERATIONAL_STATS_STRUCT; + + +typedef struct { + unsigned char station; + unsigned char state; + +}SDLC_STATE_STRUCT; + +/* the line trace status element configuration structure */ +typedef struct { + unsigned short number_trace_status_elements ; /* number of line trace elements */ + unsigned long base_addr_trace_status_elements ; /* base address of the trace element list */ + unsigned long next_trace_element_to_use ; /* pointer to the next trace element to be used */ + unsigned long base_addr_trace_buffer ; /* base address of the trace data buffer */ + unsigned long end_addr_trace_buffer ; /* end address of the trace data buffer */ +} TRACE_STATUS_EL_CFG_STRUCT; + +/* the line trace status element structure */ +typedef struct { + unsigned char opp_flag ; /* opp flag */ + unsigned short trace_length ; /* trace length */ + unsigned char trace_type ; /* trace type */ + unsigned short trace_time_stamp ; /* time stamp */ + unsigned short trace_reserved_1 ; /* reserved for later use */ + unsigned long trace_reserved_2 ; /* reserved for later use */ + unsigned long ptr_data_bfr ; /* ptr to the trace data buffer */ +} TRACE_STATUS_ELEMENT_STRUCT; + + +#pragma pack() + +#define SIOC_WANPIPE_EXEC_CMD SIOC_WANPIPE_DEVPRIVATE + +#ifdef __KERNEL__ + +typedef struct wp_sdlc_reg { + int (*sdlc_stack_rx) (struct sk_buff *skb); +}wp_sdlc_reg_t; + +extern int wanpipe_sdlc_unregister(netdevice_t *dev); +extern int wanpipe_sdlc_register(struct net_device *dev, void *wp_sdlc_reg); + +/*__KERNEL__*/ +#endif + +#endif diff -Nur linux.org/include/linux/sdlasfm.h linux-2.6.17/include/linux/sdlasfm.h --- linux.org/include/linux/sdlasfm.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/sdlasfm.h 2006-08-30 10:07:15.000000000 +0000 @@ -0,0 +1,295 @@ +/***************************************************************************** +* sdlasfm.h WANPIPE(tm) Multiprotocol WAN Link Driver. +* Definitions for the SDLA Firmware Module (SFM). +* +* Author: Gideon Hack +* +* Copyright: (c) 1995-1999 Sangoma Technologies Inc. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version +* 2 of the License, or (at your option) any later version. +* ============================================================================ +* Jun 02, 1999 Gideon Hack Added support for the S514 adapter. +* Dec 11, 1996 Gene Kozin Cosmetic changes +* Apr 16, 1996 Gene Kozin Changed adapter & firmware IDs. Version 2 +* Dec 15, 1995 Gene Kozin Structures chaned +* Nov 09, 1995 Gene Kozin Initial version. +*****************************************************************************/ +#ifndef _SDLASFM_H +#define _SDLASFM_H + +/****** Defines *************************************************************/ + +#define SFM_VERSION 2 +#define SFM_SIGNATURE "SFM - Sangoma SDLA Firmware Module" + +/* min/max */ +#define SFM_IMAGE_SIZE 0x8000 /* max size of SDLA code image file */ +#define SFM_DESCR_LEN 256 /* max length of description string */ +#define SFM_MAX_SDLA 16 /* max number of compatible adapters */ + +/* Adapter types */ +#define SDLA_S502A 5020 +#define SDLA_S502E 5021 +#define SDLA_S503 5030 +#define SDLA_S508 5080 +#define SDLA_S507 5070 +#define SDLA_S509 5090 +#define SDLA_S514 5140 +#define SDLA_ADSL 6000 +#define SDLA_AFT 7000 + +/* S514 PCI adapter CPU numbers */ +#define S514_CPU_A 'A' +#define S514_CPU_B 'B' +#define SDLA_CPU_A 1 +#define SDLA_CPU_B 2 +#define SDLA_GET_CPU(cpu_no) (cpu_no==SDLA_CPU_A)?S514_CPU_A:S514_CPU_B + + +/* Firmware identification numbers: + * 0 .. 999 Test & Diagnostics + * 1000 .. 1999 Streaming HDLC + * 2000 .. 2999 Bisync + * 3000 .. 3999 SDLC + * 4000 .. 4999 HDLC + * 5000 .. 5999 X.25 + * 6000 .. 6999 Frame Relay + * 7000 .. 7999 PPP + * 8000 .. 8999 Cisco HDLC + */ +#define SFID_CALIB502 200 +#define SFID_STRM502 1200 +#define SFID_STRM508 1800 +#define SFID_BSC502 2200 +#define SFID_BSCMP514 2201 +#define SFID_SDLC502 3200 +#define SFID_HDLC502 4200 +#define SFID_HDLC508 4800 +#define SFID_X25_502 5200 +#define SFID_X25_508 5800 +#define SFID_FR502 6200 +#define SFID_FR508 6800 +#define SFID_PPP502 7200 +#define SFID_PPP508 7800 +#define SFID_PPP514 7140 +#define SFID_CHDLC508 8800 +#define SFID_CHDLC514 8140 +#define SFID_BITSTRM 10000 +#define SFID_EDU_KIT 8141 +#define SFID_SS7514 9000 +#define SFID_BSCSTRM 2205 +#define SFID_ADSL 20000 +#define SFID_SDLC514 3300 +#define SFID_ATM 11000 +#define SFID_POS 12000 +#define SFID_ADCCP 13000 +#define SFID_AFT 30000 + +/****** Data Types **********************************************************/ + +typedef struct sfm_info /* firmware module information */ +{ + unsigned short codeid; /* firmware ID */ + unsigned short version; /* firmaware version number */ + unsigned short adapter[SFM_MAX_SDLA]; /* compatible adapter types */ + unsigned int memsize; /* minimum memory size */ + unsigned short reserved[2]; /* reserved */ + unsigned short startoffs; /* entry point offset */ + unsigned short winoffs; /* dual-port memory window offset */ + unsigned short codeoffs; /* code load offset */ + unsigned short codesize; /* code size */ + unsigned short dataoffs; /* configuration data load offset */ + unsigned short datasize; /* configuration data size */ +} sfm_info_t; + +typedef struct sfm /* SDLA firmware file structire */ +{ + char signature[80]; /* SFM file signature */ + unsigned short version; /* file format version */ + unsigned short checksum; /* info + image */ + unsigned short reserved[6]; /* reserved */ + char descr[SFM_DESCR_LEN]; /* description string */ + sfm_info_t info; /* firmware module info */ + unsigned char image[1]; /* code image (variable size) */ +} sfm_t; + +/* settings for the 'adapter_type' */ +#define S5141_ADPTR_1_CPU_SERIAL 0x0011 /* S5141, single CPU, serial */ +#define S5142_ADPTR_2_CPU_SERIAL 0x0012 /* S5142, dual CPU, serial */ +#define S5143_ADPTR_1_CPU_FT1 0x0013 /* S5143, single CPU, FT1 */ +#define S5144_ADPTR_1_CPU_T1E1 0x0014 /* S5144, single CPU, T1/E1 */ +#define S5145_ADPTR_1_CPU_56K 0x0015 /* S5145, single CPU, 56K */ +#define S5147_ADPTR_2_CPU_T1E1 0x0017 /* S5147, dual CPU, T1/E1 */ +#define S5148_ADPTR_1_CPU_T1E1 0x0018 /* S5148, single CPU, T1/E1 */ + +#define S518_ADPTR_1_CPU_ADSL 0x0018 /* S518, adsl card */ + +#define A101_ADPTR_TE1_MASK 0x0040 /* Single T1/E1 type mask */ +#define A101_ADPTR_1TE1 0x0041 /* 1 Channel T1/E1 */ +#define A101_ADPTR_2TE1 0x0042 /* 2 Channels T1/E1 */ + +#define A104_ADPTR_TE1_MASK 0x0080 /* Quad T1/E1 type mask */ +#define A104_ADPTR_4TE1 0x0081 /* Quad line T1/E1 */ + +#define A108_ADPTR_TE1_MASK 0x0200 /* 8 Channels T1/E1 type mask */ +#define A108_ADPTR_8TE1 0x0201 /* 8 Channels T1/E1 */ + +#define A100_ADPTR_T3E3_MASK 0x0100 /* T3/E3 type mask */ +#define A100_ADPTR_U_1TE3 0x0101 /* 1 Channel T3/E3 (Proto) */ +#define A300_ADPTR_U_1TE3 0x0102 /* 1 Channel T3/E3 (unchannelized) */ +#define A305_ADPTR_C_1TE3 0x0104 /* 1 Channel T3/E3 (channelized) */ + +#define A200_ADPTR_ANALOG_MASK 0x0400 /* AFT-REMORA analog board mask */ +#define A200_ADPTR_ANALOG 0x0401 /* AFT-REMORA analog board */ + +#define A104_ADPTR_X_TE1_MASK 0x0800 /* Quad T1/E1 type mask */ +#define A104_ADPTR_X_4TE1 0x0801 /* Quad line T1/E1 */ + +#define OPERATE_T1E1_AS_SERIAL 0x8000 /* For bitstreaming only + * Allow the applicatoin to + * E1 front end */ + +/* settings for the 'adapter_subtype' */ +#define AFT_SUBTYPE_NORMAL 0x00 +#define AFT_SUBTYPE_SHARK 0x01 +#define IS_ADPTR_SHARK(type) ((type) == AFT_SUBTYPE_SHARK) + +/* settings for the 'adapter_security' */ +#define AFT_SECURITY_NONE 0x00 +#define AFT_SECURITY_CHAN 0x01 +#define AFT_SECURITY_UNCHAN 0x02 + +/* settings for the 'adptr_subtype' */ +#define AFT_SUBTYPE_SHIFT 8 +#define AFT_SUBTYPE_MASK 0x0F + +/* CPLD interface */ +#define AFT_MCPU_INTERFACE_ADDR 0x46 +#define AFT_MCPU_INTERFACE 0x44 + +/* CPLD definitions */ +#define AFT_SECURITY_1LINE_UNCH 0x00 +#define AFT_SECURITY_1LINE_CH 0x01 +#define AFT_SECURITY_2LINE_UNCH 0x02 +#define AFT_SECURITY_2LINE_CH 0x03 + +#define AFT_BIT_DEV_ADDR_CLEAR 0x600 +#define AFT_BIT_DEV_ADDR_CPLD 0x200 +#define AFT4_BIT_DEV_ADDR_CLEAR 0x800 +#define AFT4_BIT_DEV_ADDR_CPLD 0x800 + +/* Maxim CPLD definitions */ +#define AFT8_BIT_DEV_ADDR_CLEAR 0x1800 /* QUAD */ +#define AFT8_BIT_DEV_ADDR_CPLD 0x800 +#define AFT8_BIT_DEV_MAXIM_ADDR_CPLD 0x1000 + +#define AFT_SECURITY_CPLD_REG 0x09 +#define AFT_SECURITY_CPLD_SHIFT 0x02 +#define AFT_SECURITY_CPLD_MASK 0x03 + +/* AFT SHARK CPLD */ +#define AFT_SH_CPLD_BOARD_CTRL_REG 0x00 +#define AFT_SH_CPLD_BOARD_STATUS_REG 0x01 +#define A200_SH_CPLD_BOARD_STATUS_REG 0x09 + +#define AFT_SH_SECURITY_MASK 0x07 +#define AFT_SH_SECURITY_SHIFT 1 +#define AFT_SH_SECURITY(reg) \ + (((reg) >> AFT_SH_SECURITY_SHIFT) & AFT_SH_SECURITY_MASK) + +#define A104_SECURITY_32_ECCHAN 0x00 +#define A104_SECURITY_64_ECCHAN 0x01 +#define A104_SECURITY_96_ECCHAN 0x02 +#define A104_SECURITY_128_ECCHAN 0x03 +#define A104_SECURITY_256_ECCHAN 0x04 +#define A104_SECURITY_PROTO_128_ECCHAN 0x05 +#define A104_SECURITY_0_ECCHAN 0x07 + +#define A108_SECURITY_32_ECCHAN 0x00 +#define A108_SECURITY_64_ECCHAN 0x01 +#define A108_SECURITY_96_ECCHAN 0x02 +#define A108_SECURITY_128_ECCHAN 0x03 +#define A108_SECURITY_256_ECCHAN 0x04 +#define A108_SECURITY_0_ECCHAN 0x05 + +#define A104_ECCHAN(val) \ + ((val) == A104_SECURITY_32_ECCHAN) ? 32 : \ + ((val) == A104_SECURITY_64_ECCHAN) ? 64 : \ + ((val) == A104_SECURITY_96_ECCHAN) ? 96 : \ + ((val) == A104_SECURITY_128_ECCHAN) ? 128 : \ + ((val) == A104_SECURITY_PROTO_128_ECCHAN) ? 128 : \ + ((val) == A104_SECURITY_256_ECCHAN) ? 256 : 0 + +#define A108_ECCHAN(val) \ + ((val) == A108_SECURITY_32_ECCHAN) ? 32 : \ + ((val) == A108_SECURITY_64_ECCHAN) ? 64 : \ + ((val) == A108_SECURITY_96_ECCHAN) ? 96 : \ + ((val) == A108_SECURITY_128_ECCHAN) ? 128 : \ + ((val) == A108_SECURITY_256_ECCHAN) ? 256 : 0 + +#define A200_SECURITY_16_ECCHAN 0x00 +#define A200_SECURITY_32_ECCHAN 0x01 +#define A200_SECURITY_0_ECCHAN 0x05 +#define A200_ECCHAN(val) \ + ((val) == A200_SECURITY_16_ECCHAN) ? 16 : \ + ((val) == A200_SECURITY_32_ECCHAN) ? 32 : 0 + + + +#define SDLA_ADPTR_NAME(adapter_type) \ + (adapter_type == S5141_ADPTR_1_CPU_SERIAL) ? "S514-1-PCI" : \ + (adapter_type == S5142_ADPTR_2_CPU_SERIAL) ? "S514-2-PCI" : \ + (adapter_type == S5143_ADPTR_1_CPU_FT1) ? "S514-3-PCI" : \ + (adapter_type == S5144_ADPTR_1_CPU_T1E1) ? "S514-4-PCI" : \ + (adapter_type == S5145_ADPTR_1_CPU_56K) ? "S514-5-PCI" : \ + (adapter_type == S5147_ADPTR_2_CPU_T1E1) ? "S514-7-PCI" : \ + (adapter_type == S518_ADPTR_1_CPU_ADSL) ? "S518-PCI" : \ + (adapter_type == A101_ADPTR_1TE1) ? "AFT-A101" : \ + (adapter_type == A101_ADPTR_2TE1) ? "AFT-A102" : \ + (adapter_type == A104_ADPTR_4TE1) ? "AFT-A104" : \ + (adapter_type == A108_ADPTR_8TE1) ? "AFT-A108" : \ + (adapter_type == A300_ADPTR_U_1TE3) ? "AFT-A301" : \ + (adapter_type == A200_ADPTR_ANALOG) ? "AFT-A200" : \ + (adapter_type == A104_ADPTR_X_4TE1) ? "AFT-X " : \ + "UNKNOWN" + +#if 0 +#define SDLA_ADPTR_DECODE(adapter_type) \ + (adapter_type == S5141_ADPTR_1_CPU_SERIAL) ? "S514-1-PCI" : \ + (adapter_type == S5142_ADPTR_2_CPU_SERIAL) ? "S514-2-PCI" : \ + (adapter_type == S5143_ADPTR_1_CPU_FT1) ? "S514-3-PCI" : \ + (adapter_type == S5144_ADPTR_1_CPU_T1E1) ? "S514-4-PCI" : \ + (adapter_type == S5145_ADPTR_1_CPU_56K) ? "S514-5-PCI" : \ + (adapter_type == S5147_ADPTR_2_CPU_T1E1) ? "S514-7-PCI" : \ + (adapter_type == S518_ADPTR_1_CPU_ADSL) ? "S518-PCI " : \ + (adapter_type == A101_ADPTR_1TE1) ? "AFT-A101 " : \ + (adapter_type == A101_ADPTR_2TE1) ? "AFT-A102 " : \ + (adapter_type == A104_ADPTR_4TE1) ? "AFT-A104 " : \ + (adapter_type == A300_ADPTR_U_1TE3) ? "AFT-A301 " : \ + "UNKNOWN " +#endif + +#define AFT_GET_SECURITY(security) \ + ((security >> AFT_SECURITY_CPLD_SHIFT) & AFT_SECURITY_CPLD_MASK) + +#define AFT_SECURITY(adapter_security) \ + (adapter_security == AFT_SECURITY_CHAN) ? "c" : \ + (adapter_security == AFT_SECURITY_UNCHAN) ? "u" : "" + +#define AFT_SECURITY_DECODE(adapter_security) \ + (adapter_security == AFT_SECURITY_CHAN) ? "Channelized" : \ + (adapter_security == AFT_SECURITY_UNCHAN) ? "Unchannelized" : "" + +#define AFT_SUBTYPE(adptr_subtype) \ + (adptr_subtype == AFT_SUBTYPE_NORMAL) ? "" : \ + (adptr_subtype == AFT_SUBTYPE_SHARK) ? "-SH" : "" + +#define AFT_SUBTYPE_DECODE(adptr_subtype) \ + (adptr_subtype == AFT_SUBTYPE_NORMAL) ? "" : \ + (adptr_subtype == AFT_SUBTYPE_SHARK) ? "SHARK" : "" + +#endif /* _SDLASFM_H */ + diff -Nur linux.org/include/linux/sdla_ss7.h linux-2.6.17/include/linux/sdla_ss7.h --- linux.org/include/linux/sdla_ss7.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/sdla_ss7.h 2006-08-30 10:07:15.000000000 +0000 @@ -0,0 +1,1053 @@ +/* + **************************************************************************** + * * + * SS7L2API.H - the 'C' header file for the Sangoma S508/S514 SS7 code API. * + * * + **************************************************************************** +*/ + +#ifndef _SDLA_SS7_H +#define _SDLA_SS7_H + + +#pragma pack(1) + +/* ---------------------------------------------------------------------------- + * Constants defining the shared memory control block (mailbox) + * --------------------------------------------------------------------------*/ + +#define PRI_BASE_ADDR_MB_STRUCT 0xE000 /* the base address of the mailbox structure (primary port) */ +#define NUMBER_MB_RESERVED_BYTES 0x0B /* the number of reserved bytes in the mailbox header area */ +#define SIZEOF_MB_DATA_BFR 2032 /* the size of the actual mailbox data area */ + +/* the control block mailbox structure */ +#if 0 +typedef struct { + unsigned char opp_flag; /* the opp flag */ + unsigned char command; /* the user command */ + unsigned short buffer_length; /* the data length */ + unsigned char return_code; /* the return code */ + char MB_reserved[NUMBER_MB_RESERVED_BYTES]; /* reserved for later use */ + char data[SIZEOF_MB_DATA_BFR]; /* the data area */ +} SS7_MAILBOX_STRUCT; +#endif + + +/* ---------------------------------------------------------------------------- + * Interface commands + * --------------------------------------------------------------------------*/ + +/* global interface commands */ +#define READ_GLOBAL_EXCEPTION_CONDITION 0x01 /* read a global exception condition from the adapter */ +#define SET_GLOBAL_CONFIGURATION 0x02 /* set the global operational configuration */ +#define READ_GLOBAL_CONFIGURATION 0x03 /* read the global configuration */ +#define READ_GLOBAL_STATISTICS 0x04 /* retrieve the global statistics */ +#define FLUSH_GLOBAL_STATISTICS 0x05 /* flush the global statistics */ +#define SET_MODEM_STATUS 0x06 /* set the status of DTR and/or RTS */ +#define READ_MODEM_STATUS 0x07 /* read the current status of CTS and DCD */ +#define READ_COMMS_ERROR_STATS 0x08 /* read the communication error statistics */ +#define FLUSH_COMMS_ERROR_STATS 0x09 /* flush the communication error statistics */ +#define SET_TRACE_CONFIGURATION 0x0A /* set the line trace configuration */ +#define READ_TRACE_CONFIGURATION 0x0B /* read the line trace configuration */ +#define READ_TRACE_STATISTICS 0x0C /* read the trace statistics */ +#define FLUSH_TRACE_STATISTICS 0x0D /* flush the trace statistics */ + +/* SS7-level interface commands */ +#define READ_SS7_CODE_VERSION 0x20 /* read the SS7 code version */ +#define L2_READ_EXCEPTION_CONDITION 0x21 /* L2 - read an exception condition from the adapter */ +#define L2_SET_CONFIGURATION 0x22 /* L2 - set the operational configuration */ +#define L2_READ_CONFIGURATION 0x23 /* L2 - read the current configuration */ +#define L2_READ_LINK_STATUS 0x24 /* L2 - read the link status */ +#define L2_READ_OPERATIONAL_STATS 0x25 /* L2 - retrieve the operational statistics */ +#define L2_FLUSH_OPERATIONAL_STATS 0x26 /* L2 - flush the operational statistics */ +#define L2_READ_HISTORY_TABLE 0x27 /* L2 - read the history table */ +#define L2_FLUSH_HISTORY_TABLE 0x28 /* L2 - flush the history table */ +#define L2_SET_INTERRUPT_TRIGGERS 0x30 /* L2 - set the application interrupt triggers */ +#define L2_READ_INTERRUPT_TRIGGERS 0x31 /* L2 - read the application interrupt trigger configuration */ +#define L2_POWER_ON 0x40 /* L2 - power on */ +#define L2_EMERGENCY 0x41 /* L2 - emergency */ +#define L2_EMERGENCY_CEASES 0x42 /* L2 - emergency ceases */ +#define L2_START 0x43 /* L2 - start */ +#define L2_STOP 0x44 /* L2 - stop */ +#define L2_RESUME 0x45 /* L2 - resume (ANSI) / local processor recovered (ITU) */ +#define L2_RETRIEVE_BSNT 0x46 /* L2 - retrieve BSNT */ +#define L2_RETRIEVAL_REQ_AND_FSNC 0x47 /* L2 - retrieval request and FSNC */ +#define L2_CLEAR_BUFFERS 0x48 /* L2 - clear buffers (ANSI) / flush buffers (ITU) */ +#define L2_CLEAR_RTB 0x49 /* L2 - clear RTB */ +#define L2_LOCAL_PROCESSOR_OUTAGE 0x4A /* L2 - local processor outage */ +#define L2_CONTINUE 0x4B /* L2 - continue (ITU) */ +#define L2_SET_TX_CONG_CFG 0x50 /* L2 - set the transmission congestion configuration */ +#define L2_READ_TX_CONG_STATUS 0x51 /* L2 - read the transmission congestion status */ +#define L2_SET_RX_CONG_CFG 0x52 /* L2 - set the receive congestion configuration */ +#define L2_READ_RX_CONG_STATUS 0x53 /* L2 - read the receive congestion status */ +#define L2_DEBUG 0x5F /* L2 - debug */ + + + +/* ---------------------------------------------------------------------------- + * Return codes from interface commands + * --------------------------------------------------------------------------*/ + +#define OK 0x00 /* the interface command was successful */ + +/* return codes from global interface commands */ +#define NO_GLOBAL_EXCEP_COND_TO_REPORT 0x01 /* there is no global exception condition to report */ +#define LGTH_GLOBAL_CFG_DATA_INVALID 0x01 /* the length of the passed global configuration data is invalid */ +#define LGTH_TRACE_CFG_DATA_INVALID 0x01 /* the length of the passed trace configuration data is invalid */ +#define IRQ_TIMEOUT_VALUE_INVALID 0x02 /* an invalid application IRQ timeout value was selected */ +#define TRACE_CONFIG_INVALID 0x02 /* the passed line trace configuration is invalid */ +#define ADAPTER_OPERATING_FREQ_INVALID 0x03 /* an invalid adapter operating frequency was selected */ +#define TRC_DEAC_TMR_INVALID 0x03 /* the trace deactivation timer is invalid */ + +/* return codes from command READ_GLOBAL_EXCEPTION_CONDITION */ +#define EXCEP_MODEM_STATUS_CHANGE 0x10 /* a modem status change occurred */ +#define EXCEP_TRC_DISABLED 0x11 /* the trace has been disabled */ +#define EXCEP_APP_IRQ_TIMEOUT 0x12 /* an application IRQ timeout has occurred */ +#define EXCEP_FT1_INS_ALARM_COND 0x16 /* an FT1 in-service/alarm condition has occurred */ + +/* return codes from SS7 L2 interface commands */ +#define NO_L2_EXCEP_COND_TO_REPORT 0x21 /* there is no L2 exception condition to report */ +#define L2_STOP_BEFORE_CFG 0x21 /* stop L2 communications before setting the configuration */ +#define L2_INVALID_CONGESTION_STATUS 0x21 /* invalid congestion status selected */ +#define L2_CFG_BEFORE_POWER_ON 0x22 /* perform a L2_SET_CONFIGURATION before L2_POWER_ON */ +#define LGTH_L2_CFG_DATA_INVALID 0x22 /* the length of the passed configuration data is invalid */ +#define LGTH_INT_TRIGGERS_DATA_INVALID 0x22 /* the length of the passed interrupt trigger data is invalid */ +#define LGTH_L2_TX_CONG_DATA_INVALID 0x22 /* the length of the passed Tx congestion data is invalid */ +#define LGTH_L2_RX_CONG_DATA_INVALID 0x22 /* the length of the passed Rx congestion data is invalid */ +#define INVALID_L2_CFG_DATA 0x23 /* the passed SS7 configuration data is invalid */ +#define INVALID_L2_TX_CONG_CFG 0x23 /* the passed Tx congestion configuration data is invalid */ +#define INVALID_L2_RX_CONG_CFG 0x23 /* the passed Rx congestion configuration data is invalid */ +#define L2_INVALID_FSNC 0x23 /* an invalid FSNC value was selected */ +#define INVALID_IRQ_SELECTED 0x23 /* an invalid IRQ was selected in the SET_SS7_INTERRUPT_TRIGGERS */ +#define IRQ_TMR_VALUE_INVALID 0x24 /* an invalid application IRQ timer value was selected */ +#define L2_INVALID_STATE_FOR_CMND 0x25 /* the command is invalid for the current SS7 L2 state */ +#define L2_INVALID_PROTOCOL_FOR_CMND 0x26 /* the command is invalid for the protocol specification */ +#define INVALID_SS7_COMMAND 0x8F /* the defined SS7 interface command is invalid */ + +/* return codes from command L2_READ_EXCEPTION_CONDITION */ +#define L2_EXCEP_IN_SERVICE 0x30 /* the link is 'In service' */ +#define L2_EXCEP_OUT_OF_SERVICE 0x31 /* the link is 'Out of service' */ +#define L2_EXCEP_REMOTE_PROC_OUTAGE 0x32 /* the remote processor has reported an outage */ +#define L2_EXCEP_REMOTE_PROC_RECOVERED 0x33 /* the remote processor has recovered after an outage */ +#define L2_EXCEP_RTB_CLEARED 0x34 /* a L2_CLEAR_RTB command has been completed */ +#define L2_EXCEP_RB_CLEARED 0x35 /* a L2_CLEAR_BUFFERS command has been completed */ +#define L2_EXCEP_BSNT 0x36 /* a L2_RETRIEVE_BSNT command has been completed */ +#define L2_EXCEP_RETRIEVAL_COMPLETE 0x37 /* a L2_RETRIEVAL_REQ_AND_FSNC command has been completed */ +#define L2_EXCEP_CONG_OUTBOUND 0x38 /* outbound congestion status change */ +#define L2_EXCEP_CONG_INBOUND 0x39 /* inbound congestion status change */ +#define L2_EXCEP_CORRECT_SU 0x3A /* a correct SU was received after a link inactivity timeout */ +#define L2_EXCEP_TX_MSU_DISC_LGTH_ERR 0x3E /* an outbound MSU was discarded due to a length error */ +#define L2_EXCEP_RX_MSU_DISC 0x3F /* a received MSU was discarded due to a format error */ + +/* qualifiers for the L2_EXCEP_OUT_OF_SERVICE return code */ +typedef struct { /* the structure used for retrieving the 'out of service' qualifier */ + unsigned char OOS_qualifier; /* the 'out of service' qualifier */ +} L2_EXCEP_OOS_STRUCT; + +/* L2_EXCEP_OUT_OF_SERVICE qualifiers */ +#define L2_OOS_L3_CMND_STOP 0x10 /* an application level L2_STOP command was issued */ +#define L2_OOS_L3_CMND_PROC_OUT 0x11 /* an application level L2_LOCAL_PROCESSOR_OUTAGE command was issued */ +#define L2_OOS_IAC_ALIGN_NOT_POSS 0x21 /* link failure - alignment not possible (alignment control) */ +#define L2_OOS_TXC_T6_EXP 0x30 /* link failure - T6 expired (transmission control) */ +#define L2_OOS_TXC_T7_EXP 0x31 /* link failure - T7 expired (transmission control) */ +#define L2_OOS_RXC_SIO 0x40 /* link failure - SIO received (reception control) */ +#define L2_OOS_RXC_SIN 0x41 /* link failure - SIN received (reception control) */ +#define L2_OOS_RXC_SIE 0x42 /* link failure - SIE received (reception control) */ +#define L2_OOS_RXC_SIOS 0x43 /* link failure - SIOS received (reception control) */ +#define L2_OOS_RXC_ABNORMAL_BSNR 0x45 /* link failure - abnormal BSNR (reception control) */ +#define L2_OOS_RXC_ABNORMAL_FIBR 0x46 /* link failure - abnormal FIBR (reception control) */ +#define L2_OOS_SUERM_ERR 0x50 /* link failure - SU in error (SUERM) */ +#define L2_OOS_SUERM_INACTIVITY 0x51 /* link failure - inactivity timeout (SUERM) */ + + + + +/* ---------------------------------------------------------------------------- + * Constants for the SET_GLOBAL_CONFIGURATION/READ_GLOBAL_CONFIGURATION commands + * --------------------------------------------------------------------------*/ + +/* the global configuration structure */ +typedef struct { + unsigned short adapter_config_options; /* adapter configuration options */ + unsigned short app_IRQ_timeout; /* application IRQ timeout */ + unsigned long adapter_operating_frequency; /* adapter operating frequency */ +} GLOBAL_CONFIGURATION_STRUCT; + +/* settings for the 'adapter_config_options' */ +#define ADPTR_CFG_S514 0x0001 /* S514 adapter */ + +/* settings for the 'app_IRQ_timeout' */ +#define MAX_APP_IRQ_TIMEOUT_VALUE 5000 /* the maximum permitted IRQ timeout */ + + + +/* ---------------------------------------------------------------------------- + * Constants for the READ_GLOBAL_STATISTICS command + * --------------------------------------------------------------------------*/ + +/* the global statistics structure */ +typedef struct { + unsigned short app_IRQ_timeout_count; /* application IRQ timeout count */ +} GLOBAL_STATS_STRUCT; + + + +/* ---------------------------------------------------------------------------- + * Constants for the READ_COMMS_ERROR_STATS command + * --------------------------------------------------------------------------*/ + +/* the communications error statistics structure */ +typedef struct { + unsigned short Rx_overrun_err_count; /* receiver overrun error count */ + unsigned short CRC_err_count; /* receiver CRC error count */ + unsigned short Rx_abort_count; /* abort frames received count */ + unsigned short Rx_dis_pri_bfrs_full_count; /* receiver disabled count */ + unsigned short reserved_1; /* reserved */ + unsigned short reserved_2; + unsigned short reserved_3; + unsigned short DCD_state_change_count; /* DCD state change count */ + unsigned short CTS_state_change_count; /* CTS state change count */ +} COMMS_ERROR_STATS_STRUCT; + + + +/* ---------------------------------------------------------------------------- + * Constants used for line tracing + * --------------------------------------------------------------------------*/ + +/* the trace configuration structure (SET_TRACE_CONFIGURATION/READ_TRACE_CONFIGURATION commands) */ +typedef struct { + unsigned char trace_config; /* trace configuration */ + unsigned short trace_deactivation_timer; /* trace deactivation timer */ + unsigned long ptr_trace_stat_el_cfg_struct; /* a pointer to the line trace element configuration structure */ +} LINE_TRACE_CONFIG_STRUCT; + +/* 'trace_config' bit settings */ +#define TRACE_INACTIVE 0x00 /* trace is inactive */ +#define TRACE_ACTIVE 0x01 /* trace is active */ +#define TRACE_DELAY_MODE 0x04 /* operate the trace in the delay mode */ +#define TRACE_FISU 0x08 /* trace FISUs */ +#define TRACE_LSSU 0x10 /* trace LSSUs */ +#define TRACE_MSU 0x20 /* trace MSUs */ + +/* permitted range for the 'trace_deactivation_timer' */ +#define MIN_TRC_DEAC_TMR_VAL 0 /* the minimum trace deactivation timer value */ +#define MAX_TRC_DEAC_TMR_VAL 8000 /* the maximum trace deactivation timer value */ + +/* the line trace status element configuration structure */ +typedef struct { + unsigned short number_trace_status_elements; /* number of line trace elements */ + unsigned long base_addr_trace_status_elements;/* base address of the trace element list */ + unsigned long next_trace_element_to_use; /* pointer to the next trace element to be used */ + unsigned long base_addr_trace_buffer; /* base address of the trace data buffer */ + unsigned long end_addr_trace_buffer; /* end address of the trace data buffer */ +} TRACE_STATUS_EL_CFG_STRUCT; + +/* the line trace status element structure */ +typedef struct { + unsigned char opp_flag; /* opp flag */ + unsigned short trace_length; /* trace length */ + unsigned char trace_type; /* trace type */ + unsigned short trace_time_stamp; /* time stamp */ + unsigned short trace_reserved_1; /* reserved for later use */ + unsigned long trace_reserved_2; /* reserved for later use */ + unsigned long ptr_data_bfr; /* pointer to the trace data buffer */ +} TRACE_STATUS_ELEMENT_STRUCT; + +/* the line trace statistics structure */ +typedef struct { + unsigned long frames_traced_count; /* number of frames traced */ + unsigned long trc_frms_not_recorded_count; /* number of trace frames discarded */ + unsigned short trc_disabled_internally_count;/* number of times the trace was disabled internally */ +} LINE_TRACE_STATS_STRUCT; + + + +/* ---------------------------------------------------------------------------- + * Constants for the L2_SET_CONFIGURATION/L2_READ_CONFIGURATION command + * --------------------------------------------------------------------------*/ + +/* the SS7 L2 configuration structure */ +typedef struct { + unsigned long baud_rate; /* the baud rate */ + unsigned short line_config_options; /* line configuration options */ + unsigned short modem_config_options; /* modem configuration options */ + unsigned short modem_status_timer; /* timer for monitoring modem status changes */ + unsigned short L2_API_options; /* L2 API options */ + unsigned short L2_protocol_options; /* L2 protocol options */ + unsigned short L2_protocol_specification; /* L2 protocol specification */ + unsigned short L2_stats_history_options; /* L2 operational statistics options */ + unsigned short max_length_MSU_SIF; /* maximum length of the MSU Signal Information Field */ + unsigned short max_unacked_Tx_MSUs; /* maximum number of unacknowledged outgoing MSUs */ + unsigned short link_inactivity_timer; /* link inactivity timer */ + unsigned short T1_timer; /* T1 'aligned/ready' timer */ + unsigned short T2_timer; /* T2 'not aligned' timer */ + unsigned short T3_timer; /* T3 'aligned' timer */ + unsigned short T4_timer_emergency; /* T4 'emergency proving period' timer */ + unsigned short T4_timer_normal; /* T4 'normal proving period' timer */ + unsigned short T5_timer; /* T5 'sending SIB' timer */ + unsigned short T6_timer; /* T6 'remote congestion' timer */ + unsigned short T7_timer; /* T7 'excessive delay of acknowledgement' timer */ + unsigned short T8_timer; /* T8 'errored interval' timer */ + unsigned short N1; /* maximum sequence number values for retransmission (PCR) */ + unsigned short N2; /* maximum MSU octets for retransmission (PCR) */ + unsigned short Tin; /* normal alignment error rate monitor threshold */ + unsigned short Tie; /* emergency alignment error rate monitor threshold */ + unsigned short SUERM_error_threshold; /* SUERM error rate threshold */ + unsigned short SUERM_number_octets; /* SUERM octet counter */ + unsigned short SUERM_number_SUs; /* SUERM number SUs/SU error */ + unsigned short SIE_interval_timer; /* timer interval between LSSUs (SIE) */ + unsigned short SIO_interval_timer; /* timer interval between LSSUs (SIO) */ + unsigned short SIOS_interval_timer; /* timer interval between LSSUs (SIOS) */ + unsigned short FISU_interval_timer; /* timer interval between FISUs */ + unsigned long ptr_shared_mem_info_struct; /* a pointer to the shared memory area information structure */ + unsigned long ptr_L2_Tx_stat_el_cfg_struct; /* a pointer to the transmit status element configuration structure */ + unsigned long ptr_L2_Rx_stat_el_cfg_struct; /* a pointer to the receive status element configuration structure */ +} L2_CONFIGURATION_STRUCT; + +/* settings for the 'line_config_options' */ +#define INTERFACE_LEVEL_V35 0x0000 /* V.35 interface level */ +#define INTERFACE_LEVEL_RS232 0x0001 /* RS-232 interface level */ + +/* settings for the 'modem_config_options' */ +#define DONT_RAISE_DTR_RTS_ON_EN_COMMS 0x0001 /* don't automatically raise DTR and RTS when performing an */ + /* ENABLE_SS7_COMMUNICATIONS command */ +#define DONT_REPORT_CHG_IN_MODEM_STAT 0x0002 /* don't report changes in modem status to the application */ + +/* bit settings for the 'L2_protocol_options' */ +#define LSSU_TWO_BYTE_SF 0x0001 /* LSSUs have a 2-byte Status Field */ +#define MODULO_4096 0x0001 /* modulo 4096 */ +#define AUTO_START_WHEN_OUT_OF_SERVICE 0x0010 /* automatically start link when out of service */ +#define AUTO_RECOVERY_AFTR_REM_PROC_REC 0x0020 /* automatic local recovery after remote processor recovery */ +#define LINK_INACTIVITY_TMR_SUERM 0x0040 /* include a link inactivity timer in the SUERM */ +#define PREVENTIVE_CYCLIC_RETRANS 0x1000 /* use preventive cyclic retransmission */ + +/* bit settings for the 'L2_protocol_specification' */ +#define L2_PROTOCOL_ANSI 0x0001 /* L2 protocol is ANSI T1.111.3 */ +#define L2_PROTOCOL_ITU 0x0002 /* L2 protocol is ITU-T Q.703 */ +#define L2_PROTOCOL_NTT 0x0004 /* L2 protocol is NTT (Japan) */ + +/* settings for the 'L2_stats_history_options' */ +#define L2_TX_SIF_BYTE_COUNT_STAT 0x0001 /* record the number of MSU SIF bytes transmitted */ +#define L2_RX_SIF_BYTE_COUNT_STAT 0x0002 /* record the number of MSU SIF bytes received */ +#define L2_TX_THROUGHPUT_STAT 0x0004 /* compute the MSU transmit throughput */ +#define L2_RX_THROUGHPUT_STAT 0x0008 /* compute the MSU frame receive throughput */ +#define L2_HIST_ALL 0x0100 /* include all state transactions in the history table */ +#define L2_HIST_MANUAL_FLUSH 0x0200 /* manually flush the L2 history table */ + +/* permitted minimum and maximum values for setting the SS7 configuration - note that all timer values are in units */ +/* of 1/100th of a second */ +#define MAX_BAUD_RATE 64000 /* maximum baud rate */ +#define MIN_PERMITTED_MODEM_TIMER 0 /* minimum modem status timer */ +#define MAX_PERMITTED_MODEM_TIMER 5000 /* maximum modem status timer */ +#define MAX_LENGTH_MSU_SIF 272 /* maximum length of the MSU Signal Information Field */ +#define MAX_UNACKED_TX_MSUs 126 /* maximum number of unacknowledged outgoing MSUs */ +#define MIN_INACTIVITY_TIMER 1 /* minimum link inactivity timer value */ +#define MAX_INACTIVITY_TIMER 60000 /* maximum link inactivity timer value */ +#define MIN_T1_TIMER 1 /* minimum T1 timer value */ +#define MAX_T1_TIMER 60000 /* maximum T1 timer value */ +#define MIN_T2_TIMER 1 /* minimum T2 timer value */ +#define MAX_T2_TIMER 60000 /* maximum T2 timer value */ +#define MIN_T3_TIMER 1 /* minimum T3 timer value */ +#define MAX_T3_TIMER 60000 /* maximum T3 timer value */ +#define MIN_T4_TIMER 1 /* minimum T4 timer value */ +#define MAX_T4_TIMER 60000 /* maximum T4 timer value */ +#define MIN_T5_TIMER 1 /* minimum T5 timer value */ +#define MAX_T5_TIMER 60000 /* maximum T5 timer value */ +#define MIN_T6_TIMER 1 /* minimum T6 timer value */ +#define MAX_T6_TIMER 60000 /* maximum T6 timer value */ +#define MIN_T7_TIMER 1 /* minimum T7 timer value */ +#define MAX_T7_TIMER 60000 /* maximum T7 timer value */ +#define MIN_T8_TIMER 1 /* minimum T8 timer value */ +#define MAX_T8_TIMER 60000 /* maximum T8 timer value */ +#define MIN_N1 1 /* minimum N1 */ +#define MAX_N1 4095 /* maximum N1 */ +#define MIN_N2 1 /* minimum N2 */ +#define MAX_N2 64000 /* maximum N2 */ +#define MIN_Tin 1 /* minimum normal alignment error rate monitor threshold */ +#define MAX_Tin 1000 /* maximum normal alignment error rate monitor threshold */ +#define MIN_Tie 1 /* minimum emergency alignment error rate monitor threshold */ +#define MAX_Tie 1000 /* maximum emergency alignment error rate monitor threshold */ +#define MIN_SUERM_ERROR_THRESHOLD 1 /* minimum SUERM error rate threshold */ +#define MAX_SUERM_ERROR_THRESHOLD 1024 /* maximum SUERM error rate threshold */ +#define MIN_SUERM_NUMBER_OCTETS 1 /* minimum SUERM octet counter */ +#define MAX_SUERM_NUMBER_OCTETS 1024 /* maximum SUERM octet counter */ +#define MIN_SUERM_NUMBER_SUs 1 /* minimum SUERM number SUs/SU error */ +#define MAX_SUERM_NUMBER_SUs 1024 /* maximum SUERM number SUs/SU error */ +#define MIN_SIE_INTERVAL_TIMER 1 /* minimum timer interval between LSSUs (SIE) */ +#define MAX_SIE_INTERVAL_TIMER 60000 /* maximum timer interval between LSSUs (SIE) */ +#define MIN_SIO_INTERVAL_TIMER 1 /* minimum timer interval between LSSUs (SIO) */ +#define MAX_SIO_INTERVAL_TIMER 60000 /* maximum timer interval between LSSUs (SIO) */ +#define MIN_SIOS_INTERVAL_TIMER 1 /* minimum timer interval between LSSUs (SIOS) */ +#define MAX_SIOS_INTERVAL_TIMER 60000 /* maximum timer interval between LSSUs (SIOS) */ +#define MIN_FISU_INTERVAL_TIMER 1 /* minimum timer interval between FISUs */ +#define MAX_FISU_INTERVAL_TIMER 60000 /* maximum timer interval between FISUs */ + + + +/* ---------------------------------------------------------------------------- + * Constants for the L2_READ_LINK_STATUS command + * --------------------------------------------------------------------------*/ + +/* the SS7 status structure */ +typedef struct { + unsigned short L2_link_status; /* L2 link status */ + unsigned short no_Tx_MSU_bfrs_occupied; /* number of Tx MSU buffers occupied */ + unsigned short no_Rx_MSUs_avail_for_L3; /* number of MSUs available for the application */ + unsigned char receiver_status; /* receiver status (enabled/disabled) */ +} L2_LINK_STATUS_STRUCT; + +/* settings for 'L2_link_status' variable */ +#define L2_LINK_STAT_POWER_OFF 0x0001 /* power off */ +#define L2_LINK_STAT_OUT_OF_SERVICE 0x0002 /* out of service */ +#define L2_LINK_STAT_INIT_ALIGN 0x0004 /* initial alignment */ +#define L2_LINK_STAT_ALIGNED_READY 0x0008 /* aligned ready */ +#define L2_LINK_STAT_ALIGNED_NOT_READY 0x0010 /* aligned/not ready */ +#define L2_LINK_STAT_IN_SERVICE 0x0020 /* in service */ +#define L2_LINK_STAT_PROCESSOR_OUTAGE 0x0040 /* processor outage */ + + + +/* ---------------------------------------------------------------------------- + * Constants for the L2_READ_OPERATIONAL_STATS command + * --------------------------------------------------------------------------*/ + +/* the L2 operational statistics structure */ +typedef struct { + +/* MSU transmission statistics */ + unsigned long MSU_Tx_ack_count; /* number of MSUs transmitted and acknowledged */ + unsigned long SIF_bytes_Tx_ack_count; /* number of SIF bytes transmitted and acknowledged */ + unsigned long MSU_re_Tx_count; /* number of MSUs re-transmitted */ + unsigned long SIF_bytes_re_Tx_count; /* number of SIF bytes re-transmitted */ + unsigned long MSU_Tx_throughput; /* transmit throughput */ + unsigned long no_hs_for_MSU_Tx_thruput_comp; /* 1/100th second time used for the Tx throughput computation */ + unsigned short Tx_MSU_disc_lgth_err_count; /* number of outgoing MSUs discarded (length error) */ + unsigned long reserved_MSU_Tx_stat1; /* reserved for later use */ + unsigned long reserved_MSU_Tx_stat2; /* reserved for later use */ + unsigned long reserved_MSU_Tx_stat3; /* reserved for later use */ + +/* MSU reception statistics */ + unsigned long MSU_Rx_count; /* number of MSUs received */ + unsigned long SIF_bytes_Rx_count; /* number of SIF bytes received */ + unsigned long MSU_Rx_throughput; /* receive throughput */ + unsigned long no_hs_for_MSU_Rx_thruput_comp; /* 1/100th second time used for the Rx throughput computation */ + unsigned short Rx_MSU_disc_short_count; /* received MSUs discarded (too short) */ + unsigned short Rx_MSU_disc_long_count; /* received MSUs discarded (too long) */ + unsigned short Rx_MSU_disc_bad_LI_count; /* received MSUs discarded (bad LI) */ + unsigned long Rx_MSU_disc_cong_count; /* received MSUs discarded (congestion) */ + unsigned long reserved_MSU_Rx_stat1; /* reserved for later use */ + unsigned long reserved_MSU_Rx_stat2; /* reserved for later use */ + unsigned long reserved_MSU_Rx_stat3; /* reserved for later use */ + +/* General SU transmission/reception statistics */ + unsigned long SU_Tx_count; /* number of SUs transmitted */ + unsigned long SU_Rx_count; /* number of SUs received */ + unsigned long LSSU_Tx_count; /* number of LSSUs transmitted */ + unsigned long LSSU_Rx_count; /* number of LSSUs received */ + unsigned long FISU_Tx_count; /* number of FISUs transmitted */ + unsigned long FISU_Rx_count; /* number of FISUs received */ + unsigned long reserved_SU_stat1; /* reserved for later use */ + unsigned long reserved_SU_stat2; /* reserved for later use */ + +/* Incoming SUs with a format error statistics */ + unsigned short Rx_SU_disc_short_count; /* SUs discarded - too short */ + unsigned short Rx_SU_disc_long_count; /* SUs discarded - too long */ + unsigned short Rx_LSSU_disc_short_count; /* LSSUs discarded - too short */ + unsigned short Rx_LSSU_disc_long_count; /* LSSUs discarded - too long */ + unsigned short Rx_LSSU_disc_invalid_SF_count; /* LSSUs discarded - invalid Status Field */ + unsigned short Rx_FISU_disc_short_count; /* FISUs discarded - too short */ + unsigned short Rx_FISU_disc_long_count; /* FISUs discarded - too long */ + unsigned long reserved_SU_format_err1; /* reserved for later use */ + unsigned long reserved_SU_format_err2; /* reserved for later use */ + unsigned long reserved_SU_format_err3; /* reserved for later use */ + unsigned long reserved_SU_format_err4; /* reserved for later use */ + +/* Incoming frames discarded statistics */ + unsigned long Rx_SU_disc_RC_idle_count; /* SUs discarded - Reception Control in 'idle' state */ + unsigned long Rx_SU_disc_MSU_FISU_NA_count; /* SUs discarded - MSU/FISU not accepted */ + +/* SS7 timeout/retry statistics */ + unsigned long To_retry_reserved_stat1; /* reserved for later use */ + unsigned long To_retry_reserved_stat2; /* reserved for later use */ + unsigned long To_retry_reserved_stat3; /* reserved for later use */ + +/* link state statistics */ + unsigned short link_in_service_count; /* number of times that the link went 'in service' */ + unsigned short link_start_fail_T1_exp_count; /* link 'start' failure (T1 expired) count */ + unsigned short align_fail_T2_exp_count; /* link alignment failure (T2 expired) count */ + unsigned short align_fail_T3_exp_count; /* link alignment failure (T3 expired) count */ + unsigned short link_fail_abnrm_BSNR_Rx_count; /* link failure (abnormal BSNR received) count */ + unsigned short link_fail_abnrm_FIBR_Rx_count; /* link failure (abnormal FIBR received) count */ + unsigned short link_fail_T6_exp_count; /* link failure (T6 expired) count */ + unsigned short link_fail_T7_exp_count; /* link failure (T6 expired) count */ + unsigned short link_fail_SUERM_count; /* link failure (SUERM) count */ + unsigned short link_fail_EIM_count; /* link failure (EIM) count */ + unsigned short link_fail_inactivity_count; /* link failure (inactivity timeout) count */ + unsigned short link_out_of_serv_SIO_Rx_count; /* link 'out of service' due to reception of SIO */ + unsigned short link_out_of_serv_SIN_Rx_count; /* link 'out of service' due to reception of SIN */ + unsigned short link_out_of_serv_SIE_Rx_count; /* link 'out of service' due to reception of SIE */ + unsigned short link_out_of_serv_SIOS_Rx_count; /* link 'out of service' due to reception of SIOS */ + unsigned long link_status_reserved_stat1; /* reserved for later use */ + unsigned long link_status_reserved_stat2; /* reserved for later use */ + +/* processor outage statistics */ + unsigned short loc_proc_out_count; /* local processor outage count */ + unsigned short rem_proc_out_count; /* rem processor outage count */ + +/* miscellaneous statistics */ + unsigned long NACK_Tx_count; /* number of negative acknowledgements transmitted */ + unsigned long NACK_Rx_count; /* number of negative acknowledgements received */ + unsigned long abnrm_BSNR_Rx_count; /* 'abnormal BSNR received' count */ + unsigned long abnrm_FIBR_Rx_count; /* 'abnormal FIBR received' count */ + unsigned long abnrm_FSNR_Rx_count; /* 'abnormal FSNR received' count */ + unsigned long reserved_misc_stat1; /* reserved for later use */ + unsigned long reserved_misc_stat2; /* reserved for later use */ + unsigned long reserved_misc_stat3; /* reserved for later use */ + unsigned long reserved_misc_stat4; /* reserved for later use */ + +/* DAEDR statistics */ + unsigned long DAEDR_OCM_7_consec_1s; /* DAEDR - number of octet counting mode conditions (7 consecutive 1s) */ + unsigned long DAEDR_OCM_Nmax; /* DAEDR - number of octet counting mode conditions (Nmax + 1) */ + +/* congestion statistics */ + unsigned long start_outbound_cong_count; /* start of outbound congestion */ + unsigned long start_inbound_cong_disc_count; /* start of inbound 'congestion discard' */ + unsigned long start_inbound_cong_acc_count; /* start of inbound 'congestion accept' */ + unsigned long start_auto_inbound_cong_count; /* start of inbound congestion (instigated internally) */ + +} L2_OPERATIONAL_STATS_STRUCT; + + + +/* ---------------------------------------------------------------------------- + * Constants for the L2_READ_HISTORY_TABLE command + * --------------------------------------------------------------------------*/ + +/* the L2 operational statistics structure */ + +typedef struct { + unsigned char function; + unsigned short action; + unsigned short status_before_action; + unsigned char LSSU_SF; + unsigned short time; +} L2_HISTORY_STRUCT; + +/* L2 history 'function' definitions */ +#define L2_HISTORY_LSC 0x00 /* Link State Control */ +#define L2_HISTORY_IAC 0x01 /* Initial Alignment Control */ +#define L2_HISTORY_POC 0x02 /* Processor Outage Control */ +#define L2_HISTORY_DAEDR 0x03 /* Delimination, Alignment and Error Detection (Receiving) */ +#define L2_HISTORY_DAEDT 0x04 /* Delimination, Alignment and Error Detection (Transmitting) */ +#define L2_HISTORY_TXC 0x05 /* Transmission Control */ +#define L2_HISTORY_RXC 0x06 /* Reception Control */ +#define L2_HISTORY_AERM 0x07 /* Alignment Error Rate Monitor */ +#define L2_HISTORY_SUERM 0x08 /* Signal Unit Error Rate Monitor */ +#define L2_HISTORY_CC 0x09 /* Congestion Control */ +#define L2_HISTORY_EIM 0x0A /* Errored Interval Monitor */ + +/* L2 history 'action' definitions (Link State Control) */ +#define LSC_ACT_POWER_ON_RETRIEVE_BSNT 0x0001 /* power on / retrieve BSNT */ +#define LSC_ACT_START_RTB_CLEARED 0x0002 /* start / RTB cleared */ +#define LSC_ACT_EMERGENCY_CONTINUE 0x0004 /* emergency / continue (ITU) */ +#define LSC_ACT_EMERG_CEASES 0x0008 /* emergency ceases */ +#define LSC_ACT_LOC_PROC_OUT 0x0010 /* local processor outage */ +#define LSC_ACT_RESUME 0x0020 /* resume */ +#define LSC_ACT_CLEAR_BFRS 0x0040 /* clear buffers */ +#define LSC_ACT_ALIGN_CPLT_RET_REQ_FSNC 0x0080 /* alignment complete / retrieval request and FSNC */ +#define LSC_ACT_STOP 0x0100 /* stop */ +#define LSC_ACT_LINK_FAIL 0x0200 /* link failure */ +#define LSC_ACT_ALIGN_NOT_POSS_CLR_RTB 0x0400 /* aligment not possible / clear RTB */ +#define LSC_ACT_FISU_MSU_RX 0x0800 /* FISU/MSU received */ +#define LSC_ACT_SIPO 0x1000 /* SIPO */ +#define LSC_ACT_SIO_SIOS 0x2000 /* SIO, SIOS */ +#define LSC_ACT_T1_EXPIRED_NO_PROC_OUT 0x4000 /* timer T1 expired / no processor outage (ITU) */ +#define LSC_ACT_SIO_SIN_SIE_SIOS 0x8000 /* SIO, SIN, SIE, SIOS */ + +/* L2 history 'status_before_action' definitions (Link State Control) */ +#define LSC_STAT_POWER_OFF 0x0001 /* power off */ +#define LSC_STAT_OUT_OF_SERVICE 0x0002 /* out of service */ +#define LSC_STAT_INIT_ALIGN 0x0004 /* initial alignment */ +#define LSC_STAT_ALIGNED_READY 0x0008 /* aligned ready */ +#define LSC_STAT_ALIGNED_NOT_READY 0x0010 /* aligned/not ready */ +#define LSC_STAT_IN_SERVICE 0x0020 /* in service */ +#define LSC_STAT_PROCESSOR_OUTAGE 0x0040 /* processor outage */ +#define LSC_STAT_EMERGENCY 0x0080 /* emergency */ +#define LSC_STAT_LOC_PROC_OUT 0x0100 /* local processor outage */ +#define LSC_STAT_REM_PROC_OUT 0x0200 /* remote processor outage (ANSI) */ +#define LSC_STAT_PROC_OUT 0x0400 /* processor outage (ITU) */ +#define LSC_STAT_T1_RUNNING 0x0800 /* timer T1 running */ +#define LSC_STAT_LVL_3_IND_RX 0x1000 /* Level 3 indication received */ + +/* L2 history 'action' definitions (Initial Alignment Control) */ +#define IAC_ACT_EMERGENCY 0x0001 /* emergency */ +#define IAC_ACT_START 0x0002 /* start */ +#define IAC_ACT_SIO_SIN 0x0004 /* SIO, SIN */ +#define IAC_ACT_SIE 0x0008 /* SIE */ +#define IAC_ACT_STOP 0x0010 /* stop */ +#define IAC_ACT_T2_EXPIRED 0x0020 /* timer T2 expired */ +#define IAC_ACT_SIN 0x0040 /* SIN */ +#define IAC_ACT_T3_EXPIRED 0x0080 /* timer T3 expired */ +#define IAC_ACT_SIOS 0x0100 /* SIOS */ +#define IAC_ACT_CORRECT_SU 0x0200 /* correct SU */ +#define IAC_ACT_T4_EXPIRED 0x0400 /* timer T4 expired */ +#define IAC_ACT_ABRT_PRV 0x0800 /* abort proving */ +#define IAC_ACT_SIO 0x1000 /* SIO */ + +/* L2 history 'status_before_action' definitions (Initial Alignment Control) */ +#define IAC_STAT_IDLE 0x0001 /* idle */ +#define IAC_STAT_NOT_ALIGNED 0x0002 /* not aligned */ +#define IAC_STAT_ALIGNED 0x0004 /* aligned */ +#define IAC_STAT_PROVING 0x0008 /* proving */ +#define IAC_STAT_FURTHER_PRV 0x0010 /* further proving */ +#define IAC_STAT_EMERGENCY 0x0020 /* emergency */ +#define IAC_STAT_T2_RUNNING 0x0040 /* timer T2 running */ +#define IAC_STAT_T3_RUNNING 0x0080 /* timer T3 running */ +#define IAC_STAT_T4_RUNNING 0x0100 /* timer T4 running */ + +/* L2 history 'action' definitions (Processor Outage Control) */ +#define POC_ACT_LOC_PROC_OUT 0x0001 /* local processor outage */ +#define POC_ACT_REM_PROC_OUT 0x0002 /* remote processor outage */ +#define POC_ACT_STOP 0x0004 /* stop */ +#define POC_ACT_LOC_PROC_RECOVERED 0x0008 /* local processor recovered */ +#define POC_ACT_REM_PROC_RECOVERED 0x0010 /* remote processor recovered */ + +/* L2 history 'status_before_action' definitions (Processor Outage Control) */ +#define POC_STAT_IDLE 0x0001 /* idle */ +#define POC_STAT_LOC_PROC_OUT 0x0002 /* local processor outage */ +#define POC_STAT_REM_PROC_OUT 0x0004 /* remote processor outage */ +#define POC_STAT_BOTH_PROC_OUT 0x0008 /* both processors out */ + +/* L2 history 'action' definitions (Delimination, Alignment and Error Detection - Receiving) */ +#define DAEDR_ACT_START 0x0001 /* start */ +#define DAEDR_ACT_7_CONSEC_ONES 0x0002 /* 7 consecutive one's */ +#define DAEDR_ACT_Nmax_PLS_1_OCT_NO_FLG 0x0004 /* Nmax + 1 octets without flags */ +#define DAEDR_ACT_16_OCTETS 0x0008 /* 16 octets */ +#define DAEDR_ACT_BITS_RX 0x0010 /* bits received */ + +/* L2 history 'status_before_action' definitions (Delimination, Alignment and Error Detection - Receiving) */ +#define DAEDR_STAT_IDLE 0x0001 /* idle */ +#define DAEDR_STAT_IN_SERVICE 0x0002 /* in service */ +#define DAEDR_STAT_OCTET_COUNT_MODE 0x0004 /* octet counting mode */ + +/* L2 history 'action' definitions (Delimination, Alignment and Error Detection - Transmitting) */ +#define DAEDT_ACT_START 0x0001 /* start */ +#define DAEDT_ACT_SIGNAL_UNIT 0x0002 /* signal unit */ + +/* L2 history 'status_before_action' definitions (Delimination, Alignment and Error Detection - Transmitting) */ +#define DAEDT_STAT_IDLE 0x0001 /* idle */ +#define DAEDT_STAT_IN_SERVICE 0x0002 /* in service */ + +/* L2 history 'action' definitions (Transmission Control) */ +#define TXC_ACT_START 0x0001 /* start */ +#define TXC_ACT_T6_EXPIRED 0x0002 /* timer T6 expired */ +#define TXC_ACT_T7_EXPIRED 0x0004 /* timer T7 expired */ +#define TXC_ACT_TX_REQ 0x0008 /* transmission request */ +#define TXC_ACT_CLEAR_TB 0x0010 /* clear TB */ +#define TXC_ACT_CLEAR_RTB 0x0020 /* clear RTB */ +#define TXC_ACT_SEND_FISU 0x0040 /* send FISU */ +#define TXC_ACT_SEND_MSU 0x0080 /* send MSU */ +#define TXC_ACT_MSG_FOR_TX 0x0100 /* message for transmission */ +#define TXC_ACT_RET_REQ_AND_FSNC 0x0200 /* retrieval request and FSNC */ +#define TXC_ACT_SEND_LSSU 0x0400 /* send LSSU (includes 'send SIB', 'send SIOS,SIPO' and */ + /* 'send SIO, SIN, SIE') */ +#define TXC_ACT_FSNX_VALUE 0x0800 /* FSNX value */ +#define TXC_ACT_NACK_TO_BE_TX 0x1000 /* NACK to be sent */ +#define TXC_ACT_BSNR_AND_BIBR 0x2000 /* BSNR and BIBR */ +#define TXC_ACT_SIB_RX 0x4000 /* SIB received */ +#define TXC_ACT_FLUSH_BFRS 0x8000 /* flush buffers (ITU) */ + +/* L2 history 'status_before_action' definitions (Transmission Control) */ +#define TXC_STAT_IDLE 0x0001 /* idle */ +#define TXC_STAT_IN_SERVICE 0x0002 /* in service */ +#define TXC_STAT_RTB_FULL 0x0004 /* RTB full */ +#define TXC_STAT_LSSU_AVAIL 0x0008 /* LSSU available */ +#define TXC_STAT_MSU_INHIB 0x0010 /* MSU inhibited */ +#define TXC_STAT_CLEAR_RTB 0x0020 /* clear RTB */ +#define TXC_STAT_SIB_RX 0x0040 /* SIB received */ +#define TXC_STAT_PCR_FORCED_RE_TX 0x0080 /* forced retransmission (PCR) */ +#define TXC_STAT_T6_RUNNING 0x0100 /* timer T6 running */ +#define TXC_STAT_T7_RUNNING 0x0200 /* timer T7 running */ + +/* L2 history 'action' definitions (Reception Control) */ +#define RXC_ACT_START 0x0001 /* start */ +#define RXC_ACT_RETRIEVE_BSNT 0x0002 /* retrieve BSNT */ +#define RXC_ACT_FSNT_VALUE 0x0004 /* FSNT value */ +#define RXC_ACT_SIGNAL_UNIT 0x0008 /* signal unit */ +#define RXC_ACT_REJ_MSU_FISU 0x0010 /* reject MSU/FISU */ +#define RXC_ACT_ACCEPT_MSU_FISU 0x0020 /* accept MSU/FISU */ +#define RXC_ACT_ALIGN_FSNX 0x0040 /* align FSNX / retrieve FSNX (ITU) */ +#define RXC_ACT_CLEAR_RB 0x0080 /* clear RB */ +#define RXC_ACT_STOP 0x0100 /* stop */ +#define RXC_ACT_CONGESTION_DISC 0x0200 /* congestion discard */ +#define RXC_ACT_CONGESTION_ACC 0x0400 /* congestion accept */ +#define RXC_ACT_NO_CONGESTION 0x0800 /* no congestion */ +#define RXC_ACT_SIGNAL_UNIT_LSSU 0x1000 /* signal unit (LSSU) */ + +/* L2 history 'status_before_action' definitions (Reception Control) */ +#define RXC_STAT_IDLE 0x0001 /* idle */ +#define RXC_STAT_IN_SERVICE 0x0002 /* in service */ +#define RXC_STAT_MSU_FISU_ACCEPTED 0x0004 /* MSU/FISU accepted */ +#define RXC_STAT_ABNORMAL_BSNR 0x0008 /* abnormal BSNR */ +#define RXC_STAT_ABNORMAL_FIBR 0x0010 /* abnormal FIBR */ +#define RXC_STAT_CONGESTION_DISC 0x0020 /* congestion discard */ +#define RXC_STAT_CONGESTION_ACC 0x0040 /* congestion accept */ + +/* L2 history 'action' definitions (Alignment Error Rate Monitor) */ +#define AERM_ACT_SET_Ti_TO_Tin 0x0001 /* set Ti to Tin */ +#define AERM_ACT_START 0x0002 /* start */ +#define AERM_ACT_SET_Ti_TO_Tie 0x0004 /* set Ti to Tie */ +#define AERM_ACT_STOP 0x0008 /* stop */ +#define AERM_ACT_SU_IN_ERROR 0x0010 /* SU in error */ + +/* L2 history 'status_before_action' definitions (Alignment Error Rate Monitor) */ +#define AERM_STAT_IDLE 0x0001 /* idle */ +#define AERM_STAT_MONITORING 0x0002 /* monitoring */ + +/* L2 history 'action' definitions (Signal Unit Error Rate Monitor) */ +#define SUERM_ACT_START 0x0001 /* start */ +#define SUERM_ACT_STOP 0x0002 /* stop */ +#define SUERM_ACT_SU_IN_ERROR 0x0004 /* SU in error */ +#define SUERM_ACT_CORRECT_SU 0x0008 /* correct SU */ + +/* L2 history 'status_before_action' definitions (Signal Unit Error Rate Monitor) */ +#define SUERM_STAT_IDLE 0x0001 /* idle */ +#define SUERM_STAT_IN_SERVICE 0x0002 /* in service */ + +/* L2 history 'action' definitions (Congestion Control) */ +#define CC_ACT_BUSY 0x0001 /* busy */ +#define CC_ACT_NORMAL 0x0002 /* normal */ +#define CC_ACT_STOP 0x0004 /* stop */ +#define CC_ACT_T5_EXPIRED 0x0008 /* timer T5 expired */ + +/* L2 history 'status_before_action' definitions (Congestion Control) */ +#define CC_STAT_IDLE 0x0001 /* idle */ +#define CC_STAT_LVL_2 0x0002 /* level 2 congestion */ +#define CC_STAT_T5_RUNNING 0x0004 /* timer T5 running */ + +/* L2 history 'action' definitions (Errored Interval Monitor) */ +#define EIM_ACT_START 0x0001 /* start */ +#define EIM_ACT_STOP 0x0002 /* stop */ +#define EIM_ACT_T8_EXPIRED 0x0004 /* timer T8 expired */ +#define EIM_ACT_CORRECT_SU 0x0008 /* correct SU */ +#define EIM_ACT_SU_IN_ERROR 0x0010 /* SU in error */ + +/* L2 history 'status_before_action' definitions (Errored Interval Monitor) */ +#define EIM_STAT_IDLE 0x0001 /* idle */ +#define EIM_STAT_MONITORING 0x0002 /* monitoring */ +#define EIM_STAT_INTERVAL_ERROR 0x0004 /* interval error */ +#define EIM_STAT_SU_RECEIVED 0x0008 /* SU received */ +#define EIM_STAT_T8_RUNNING 0x0010 /* timer T8 running */ + +/* L2 history 'LSSU_SF' definitions (LSSU Status Field) */ +#define LSSU_SIO 0x00 /* status indication "O" (out of alignment) */ +#define LSSU_SIN 0x01 /* status indication "N" (normal alignment) */ +#define LSSU_SIE 0x02 /* status indication "E" (emergency alignment) */ +#define LSSU_SIOS 0x03 /* status indication "OS" (out of service) */ +#define LSSU_SIPO 0x04 /* status indication "PO" (processor outage) */ +#define LSSU_SIB 0x05 /* status indication "B" (busy) */ +#define NO_LSSU 0xFF /* no LSSU transmitted or received */ + + + +/* ---------------------------------------------------------------------------- + * Constants for the L2_RETRIEVE_BSNT command + * --------------------------------------------------------------------------*/ + +/* the structure used for retrieving the BSNT value */ +typedef struct { + unsigned short BSNT; /* the retrieved BSNT value */ +} L2_RETRIEVE_BSNT_STRUCT; + + + +/* ---------------------------------------------------------------------------- + * Constants for the L2_RETRIEVAL_REQ_AND_FSNC command + * --------------------------------------------------------------------------*/ + +/* the structure used for handling the L2_RETRIEVAL_REQ_AND_FSNC command and the L2_EXCEP_RETRIEVAL_COMPLETE */ +/* exception condition */ +typedef struct { + unsigned short FSNC; /* the FSNC value to be used in buffer retrieval */ + unsigned short number_MSUs; /* number of MSU buffers to be retrieved */ + unsigned long ptr_first_MSU_bfr; /* pointer to the first MSU buffer to be retrieved */ +} L2_RETRIEVAL_STRUCT; + + + +/* ---------------------------------------------------------------------------- + * Constants for the L2_SET_TX_CONG_CFG command + * --------------------------------------------------------------------------*/ + +typedef struct { + unsigned short Tx_cong_config; /* transmission congestion configuration */ + unsigned short Tx_cong_onset_1; /* transmit congestion onset threshold #1 */ + unsigned short Tx_cong_abatement_1; /* transmit congestion abatement threshold #1 */ + unsigned short Tx_cong_discard_1; /* transmit congestion discard threshold #1 */ + unsigned short Tx_cong_onset_2; /* transmit congestion onset threshold #2 */ + unsigned short Tx_cong_abatement_2; /* transmit congestion abatement threshold #2 */ + unsigned short Tx_cong_discard_2; /* transmit congestion discard threshold #2 */ + unsigned short Tx_cong_onset_3; /* transmit congestion onset threshold #3 */ + unsigned short Tx_cong_abatement_3; /* transmit congestion abatement threshold #3 */ + unsigned short Tx_cong_discard_3; /* transmit congestion discard threshold #3 */ +} L2_SET_TX_CONG_CFG_STRUCT; + +/* 'Tx_cong_config' settings */ +#define NO_TX_NEW_MSUs_SIB_RX 0x0001 /* no new MSUs are transmitted on SIB reception */ +#define L2_EXCEP_TX_CONG_THRESHOLDS 0x0010 /* cause an L2 exception condition on congestion thresholds */ +#define L2_EXCEP_TX_CONG_SIB_RX 0x0020 /* cause an L2 exception condition on reception of a SIB LSSU */ + + + +/* ---------------------------------------------------------------------------- + * Constants for the L2_READ_TX_CONG_STATUS command + * --------------------------------------------------------------------------*/ + +typedef struct { + unsigned short no_MSU_Tx_bfrs_configured; /* the number of MSU transmit buffers configured */ + unsigned short no_MSU_Tx_bfrs_occupied; /* the number of MSU transmit buffers occupied */ + unsigned char Tx_cong_status; /* transmission congestion status */ + unsigned char Tx_discard_status; /* transmission discard status */ + unsigned char SIB_Rx_status; /* LSSU SIB reception status */ +} L2_READ_TX_CONG_STATUS_STRUCT; + + + + +/* ---------------------------------------------------------------------------- + * Constants for the L2_SET_RX_CONG_CFG command + * --------------------------------------------------------------------------*/ + +typedef struct { + unsigned short Rx_cong_config; /* reception congestion configuration */ + unsigned short Rx_cong_bfr_count; /* the number of MSU receive buffers occupied to trigger congestion */ +} L2_SET_RX_CONG_CFG_STRUCT; + +/* 'Rx_cong_config' bit settings */ +#define L2_RX_CONGESTION_ACCEPT 0x0001 /* congestion accept */ +#define L2_RX_CONGESTION_DISCARD 0x0002 /* congestion discard */ +#define L2_AUTO_RX_FLOW_CTRL 0x0010 /* automatic receive flow control */ + + + +/* ---------------------------------------------------------------------------- + * Constants for the L2_READ_RX_CONG_STATUS command + * --------------------------------------------------------------------------*/ + +typedef struct { + unsigned short no_MSU_Rx_bfrs_configured; /* the number of MSU receive buffers configured */ + unsigned short no_MSU_Rx_bfrs_occupied; /* the number of MSU receive buffers occupied */ + unsigned char Rx_cong_status; /* reception congestion status */ +} L2_READ_RX_CONG_STATUS_STRUCT; + + + +/* ---------------------------------------------------------------------------- + * Constants for using application interrupts + * --------------------------------------------------------------------------*/ + +/* the structure used for the L2_SET_INTERRUPT_TRIGGERS/L2_READ_INTERRUPT_TRIGGERS command */ +typedef struct { + unsigned char L2_interrupt_triggers; /* SS7 L2 interrupt trigger configuration */ + unsigned char IRQ; /* IRQ to be used */ + unsigned short interrupt_timer; /* interrupt timer */ + unsigned short misc_interrupt_bits; /* miscellaneous interrupt bits */ +} L2_INT_TRIGGERS_STRUCT; + +/* 'L2_interrupt_triggers' bit settings */ +#define APP_INT_ON_RX_FRAME 0x01 /* interrupt on MSU reception */ +#define APP_INT_ON_TX_FRAME 0x02 /* interrupt when an MSU may be transmitted */ +#define APP_INT_ON_COMMAND_COMPLETE 0x04 /* interrupt when an interface command is complete */ +#define APP_INT_ON_TIMER 0x08 /* interrupt on a defined millisecond timeout */ +#define APP_INT_ON_GLOBAL_EXCEP_COND 0x10 /* interrupt on a global exception condition */ +#define APP_INT_ON_L2_EXCEP_COND 0x20 /* interrupt on an SS7 L2 exception condition */ +#define APP_INT_ON_TRACE_DATA_AVAIL 0x80 /* interrupt when trace data is available */ + +/* 'interrupt_timer' limitation */ +#define MAX_INTERRUPT_TIMER_VALUE 60000 /* the maximum permitted timer interrupt value */ + +/* interrupt types indicated at 'interrupt_type' byte of the INTERRUPT_INFORMATION_STRUCT */ +#define NO_APP_INTS_PEND 0x00 /* no interrups are pending */ +#define RX_APP_INT_PEND 0x01 /* a receive interrupt is pending */ +#define TX_APP_INT_PEND 0x02 /* a transmit interrupt is pending */ +#define COMMAND_COMPLETE_APP_INT_PEND 0x04 /* a 'command complete' interrupt is pending */ +#define TIMER_APP_INT_PEND 0x08 /* a timer interrupt is pending */ +#define GLOBAL_EXCEP_COND_APP_INT_PEND 0x10 /* a global exception condition interrupt is pending */ +#define L2_EXCEP_COND_APP_INT_PEND 0x20 /* an SS7 L2 exception condition interrupt is pending */ +#define TRACE_DATA_AVAIL_APP_INT_PEND 0x80 /* a trace data available interrupt is pending */ + + + +/* ---------------------------------------------------------------------------- + * Constants for MSU transmission + * --------------------------------------------------------------------------*/ + +/* the MSU transmit status element configuration structure */ +typedef struct { + unsigned short number_Tx_status_elements; /* number of transmit status elements */ + unsigned long base_addr_Tx_status_elements; /* base address of the transmit element list */ + unsigned long next_Tx_status_element_to_use; /* pointer to the next transmit element to be used */ +} L2_TX_STATUS_EL_CFG_STRUCT; + +/* the MSU transmit status element structure */ +typedef struct { + unsigned char opp_flag; /* opp flag */ + unsigned short frame_length; /* length of the frame to be transmitted */ + unsigned char SIO; /* Service Information Octet */ + unsigned char misc_Tx_bits; /* miscellaneous bits */ + unsigned char reserved_1; /* reserved for internal use */ + unsigned short reserved_2; /* reserved for internal use */ + unsigned long reserved_3; /* reserved for internal use */ + unsigned long ptr_data_bfr; /* pointer to the data area */ +} L2_MSU_TX_STATUS_EL_STRUCT; + + + +/* ---------------------------------------------------------------------------- + * Constants for MSU reception + * --------------------------------------------------------------------------*/ + +/* the MSU receive status element configuration structure */ +typedef struct { + unsigned short number_Rx_status_elements; /* number of receive status elements */ + unsigned long base_addr_Rx_status_elements; /* base address of the receive element list */ + unsigned long next_Rx_status_element_to_use; /* pointer to the next receive element to be used */ +} L2_RX_STATUS_EL_CFG_STRUCT; + +/* the MSU receive status element structure */ +typedef struct { + unsigned char opp_flag; /* opp flag */ + unsigned short frame_length; /* length of the received frame */ + unsigned char SIO; /* Service Information Octet */ + unsigned char misc_Rx_bits; /* miscellaneous bits */ + unsigned short time_stamp; /* receive time stamp */ + unsigned char reserved_1; /* reserved for internal use */ + unsigned long reserved_2; /* reserved for internal use */ + unsigned long ptr_data_bfr; /* pointer to the data area */ +} L2_MSU_RX_STATUS_EL_STRUCT; + + + +/* ---------------------------------------------------------------------------- + * Constants defining the shared memory information area + * --------------------------------------------------------------------------*/ + +/* the global information structure */ +typedef struct { + unsigned char global_status; /* global status */ + unsigned char modem_status; /* current modem status */ + unsigned char global_excep_conditions; /* global exception conditions */ + unsigned char Rx_disabled_Rx_bfrs_full; /* receiver disabled */ + unsigned char glob_info_reserved[4]; /* reserved */ + unsigned char code_name[4]; /* code name */ + unsigned char code_version[4]; /* code version */ +} GLOBAL_INFORMATION_STRUCT; + +/* the SS7 L2 information structure */ +typedef struct { + unsigned char L2_in_service; /* SS7 L2 'in service' flag */ + unsigned short L2_excep_conditions; /* SS7 L2 exception conditions */ + unsigned short no_MSU_Tx_bfrs_occupied; /* the number of MSU transmit buffers occupied */ + unsigned char Tx_cong_status; /* transmission congestion status */ + unsigned char Tx_discard_status; /* transmission discard status */ + unsigned char SIB_Rx_status; /* LSSU SIB reception status */ + unsigned char L2_info_reserved[8]; /* reserved */ +} L2_INFORMATION_STRUCT; + +typedef struct { + unsigned char reserved[16]; /* reserved */ +} RES_INFORMATION_STRUCT; + +/* the interrupt information structure */ +typedef struct { + unsigned char interrupt_type; /* type of interrupt triggered */ + unsigned char interrupt_permission; /* interrupt permission mask */ + unsigned char int_info_reserved[14]; /* reserved */ +} INTERRUPT_INFORMATION_STRUCT; + +/* the FT1 information structure */ +typedef struct { + unsigned char parallel_port_A_input; /* input - parallel port A */ + unsigned char parallel_port_B_input; /* input - parallel port B */ + unsigned char FT1_INS_alarm_condition; /* the current FT1 in-service/alarm condition */ + unsigned char FT1_info_reserved[13]; /* reserved */ +} FT1_INFORMATION_STRUCT; + +/* the shared memory area information structure */ +typedef struct { + GLOBAL_INFORMATION_STRUCT global_info_struct;/* the global information structure */ + L2_INFORMATION_STRUCT L2_info_struct; /* the SS7 L2 information structure */ + RES_INFORMATION_STRUCT res0_info_struct; /* reserved information structure */ + RES_INFORMATION_STRUCT res1_info_struct; /* reserved information structure */ + INTERRUPT_INFORMATION_STRUCT interrupt_info_struct;/* the interrupt information structure */ + FT1_INFORMATION_STRUCT FT1_info_struct; /* the FT1 information structure */ +} SHARED_MEMORY_INFO_STRUCT; + + + +/* ---------------------------------------------------------------------------- + * Constants for SS7 L2 debugging + * --------------------------------------------------------------------------*/ +/* the SS7 debug structure */ +typedef struct { + unsigned short LSC_action; + unsigned short LSC_status; + unsigned short IAC_action; + unsigned short IAC_status; + unsigned short POC_action; + unsigned short POC_status; + unsigned short DAEDR_action; + unsigned short DAEDR_status; + unsigned short DAEDT_action; + unsigned short DAEDT_status; + unsigned short TXC_action; + unsigned short TXC_status; + unsigned char Tx_LSSU_SF; + unsigned short RXC_action; + unsigned short RXC_status; + unsigned short CC_action; + unsigned short CC_status; + unsigned short AERM_action; + unsigned short AERM_status; + unsigned short SUERM_action; + unsigned short SUERM_status; + unsigned short EIM_action; + unsigned short EIM_status; + unsigned short FSNL; + unsigned short FSNF; + unsigned short FSNT_TXC; + unsigned short FSNT_RXC; + unsigned short FSNX_TXC; + unsigned short FSNX_RXC; + unsigned short FSNR; + unsigned short BSNR; + unsigned short BSNT; + unsigned char FIBT; + unsigned char FIBR; + unsigned char FIBX; + unsigned char FIB; + unsigned char BIBT; + unsigned char BIBR; + unsigned char BIBX; + unsigned char BIB; + unsigned short Cm; + unsigned char UNF; + unsigned char UNB; + unsigned char RTR; + unsigned char Cp; + unsigned char Tx_frm_status; +} L2_DEBUG_STRUCT; + +#pragma pack() + + +#undef wan_udphdr_data +#define wan_udphdr_data wan_udphdr_u.ss7.data + +#ifdef __KERNEL__ +#undef wan_udp_data +#define wan_udp_data wan_udp_hdr.wan_udphdr_u.ss7.data +#endif + +#endif diff -Nur linux.org/include/linux/sdla_tdmv.h linux-2.6.17/include/linux/sdla_tdmv.h --- linux.org/include/linux/sdla_tdmv.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/sdla_tdmv.h 2006-08-30 10:07:15.000000000 +0000 @@ -0,0 +1,120 @@ +/****************************************************************************** + * sdla_tdmv.h + * + * Author: Alex Feldman + * + * Copyright: (c) 1995-2001 Sangoma Technologies Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * ============================================================================ + ****************************************************************************** + */ + +#ifndef __SDLA_TDMV_H +# define __SDLA_TDMV_H + +#ifdef __SDLA_TDMV_SRC +# define EXTERN +#else +# define EXTERN extern +#endif + + +/****************************************************************************** +** DEFINES and MACROS +******************************************************************************/ + +#if defined(WAN_KERNEL) + +#if defined(__FreeBSD__) || defined(__OpenBSD__) +# if defined(CONFIG_PRODUCT_WANPIPE_TDM_VOICE_ECHOMASTER) +# include +# endif +#else +# if defined(CONFIG_PRODUCT_WANPIPE_TDM_VOICE_ECHOMASTER) +# include +# endif +#endif + +/****************************************************************************** +** DEFINES and MACROS +******************************************************************************/ + +#define WAN_TDMV_IDLE_FLAG 0x7F + +#define WAN_TDMV_CALL(func, args, err) \ + if (card->tdmv_iface.func){ \ + err = card->tdmv_iface.func args; \ + }else{ \ + DEBUG_EVENT("%s: Internal Error (%s:%d)!\n",\ + card->devname, \ + __FUNCTION__,__LINE__); \ + err = -EINVAL; \ + } + + +/****************************************************************************** +** TYPEDEF STRUCTURE +******************************************************************************/ +typedef struct wan_tdmv_ +{ + void *sc; + int max_tx_len; + int max_timeslots; + int brt_enable; + int spanno; +#if defined(CONFIG_PRODUCT_WANPIPE_TDM_VOICE_ECHOMASTER) + wan_tdmv_rxtx_pwr_t chan_pwr[31]; +#endif + WAN_LIST_ENTRY(wan_tdmv_) next; +} wan_tdmv_t; + +typedef struct wan_tdmv_iface_ +{ + int (*check_mtu)(void*, unsigned long, int *); + int (*create)(void* pcard, wan_xilinx_conf_t *conf); + int (*remove)(void* pcard); + int (*reg)(void*, wanif_conf_t*, netdevice_t*); + int (*unreg)(void* pcard, unsigned long ts_map); + int (*software_init)(wan_tdmv_t*); + int (*state)(void*, int); + int (*running)(void*); + int (*rx_tx)(void*, netskb_t*); + int (*rx_chan)(wan_tdmv_t*, int, unsigned char*, unsigned char*); +#if defined(CONFIG_PRODUCT_WANPIPE_TDM_VOICE_DCHAN) + int (*rx_dchan)(wan_tdmv_t*, int, unsigned char*, unsigned int); +#endif + int (*rx_tx_span)(void *pcard); + int (*is_rbsbits)(wan_tdmv_t *); + int (*rbsbits_poll)(wan_tdmv_t *, void*); + int (*init)(void*, wanif_conf_t*); + int (*free)(wan_tdmv_t*); + int (*polling)(void*); + +} wan_tdmv_iface_t; + +/****************************************************************************** +** FUNCTION PROTOTYPES +******************************************************************************/ +EXTERN int wp_tdmv_te1_init(wan_tdmv_iface_t *iface); +EXTERN int wp_tdmv_remora_init(wan_tdmv_iface_t *iface); + +#ifdef CONFIG_PRODUCT_WANPIPE_TDM_VOICE_ECHOMASTER +EXTERN int wp_tdmv_echo_check(wan_tdmv_t *wan_tdmv, void *current_ztchan, int channo); +#endif + + +EXTERN int wanpipe_codec_convert_2s(u8 *data, int len, netskb_t *nskb, + u16 *power_ptr, int is_alaw); + +EXTERN int wanpipe_codec_convert_s2ulaw(netskb_t *skb, netskb_t *nskb, int is_alaw); + + +#endif /* WAN_KERNEL */ + +#undef EXTERN + +#endif /* __SDLA_VOIP_H */ diff -Nur linux.org/include/linux/sdla_te1_ds.h linux-2.6.17/include/linux/sdla_te1_ds.h --- linux.org/include/linux/sdla_te1_ds.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/sdla_te1_ds.h 2006-08-30 10:07:15.000000000 +0000 @@ -0,0 +1,610 @@ +/* + * Copyright (c) 2001 + * Alex Feldman . All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Alex Feldman. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Alex Feldman AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Alex Feldman OR THE VOICES IN HIS HEAD + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + * $Id$ + */ + +/***************************************************************************** + * sdla_te1_ds.h Sangoma TE1 configuration definitions (Dallas). + * + * Author: Alex Feldman + * + * ============================================================================ + * Aprl 30, 2001 Alex Feldman Initial version. + **************************************************************************** +*/ +#ifndef __SDLA_TE1_DS_H +# define __SDLA_TE1_DS_H + +/****************************************************************************** + DEFINES AND MACROS +******************************************************************************/ + +/* Global Register Definitions */ +#define REG_GTCR1 0xF0 + +#define REG_GFCR 0xF1 +#define BIT_GFCR_TCBCS 0x02 +#define BIT_GFCR_RCBCS 0x01 + +#define REG_GTCR2 0xF2 + +#define REG_GTCCR 0xF3 + +#define REG_GLSRR 0xF5 + +#define REG_GFSRR 0xF6 + +#define REG_IDR 0xF8 +#define DEVICE_ID_DS(reg_idr) ((reg_idr) >> DEVICE_ID_SHIFT) & DEVICE_ID_MASK +#define DEVICE_ID_DS26528 0x0B +#define DEVICE_ID_DS26524 0x0C +#define DEVICE_ID_DS26522 0x0D +#define DEVICE_ID_DS26521 0x0E +#define DEVICE_ID_SHIFT 3 +#define DEVICE_ID_MASK 0x1F + +#define REG_GFISR 0xF9 + +#define REG_GBISR 0xFA + +#define REG_GLISR 0xFB + +#define REG_GFIMR 0xFC + +#define REG_GBIMR 0xFD + +#define REG_GLIMR 0xFE + + +/* RX Framer Register Definitions */ +#define REG_RSIGC 0x13 +#define BIT_RSIGC_CASMS 0x10 + +#define REG_RS1 0x40 +#define BIT_RS_A 0x08 +#define BIT_RS_B 0x04 +#define BIT_RS_C 0x02 +#define BIT_RS_D 0x01 +#define REG_RS2 0x41 +#define REG_RS3 0x42 +#define REG_RS4 0x43 +#define REG_RS5 0x44 +#define REG_RS6 0x45 +#define REG_RS7 0x46 +#define REG_RS8 0x47 +#define REG_RS9 0x48 +#define REG_RS10 0x49 +#define REG_RS11 0x4A +#define REG_RS12 0x4B +#define REG_RS13 0x4C +#define REG_RS14 0x4D +#define REG_RS15 0x4E +#define REG_RS16 0x4F + +#define REG_LCVCR1 0x50 +#define REG_LCVCR2 0x51 + +#define REG_PCVCR1 0x52 +#define REG_PCVCR2 0x53 + +#define REG_FOSCR1 0x54 +#define REG_FOSCR2 0x55 + +#define REG_E1EBCR1 0x56 +#define REG_E1EBCR2 0x57 + +#define REG_RMMR 0x80 +#define BIT_RMMR_FRM_EN 0x80 +#define BIT_RMMR_INIT_DONE 0x40 +#define BIT_RMMR_SFTRST 0x02 +#define BIT_RMMR_T1E1 0x01 + +#define REG_RCR1 0x81 +#define BIT_RCR1_T1_SYNCT 0x80 +#define BIT_RCR1_T1_RB8ZS 0x40 +#define BIT_RCR1_T1_RFM 0x20 +#define BIT_RCR1_T1_ARC 0x10 +#define BIT_RCR1_T1_SYNCC 0x08 +#define BIT_RCR1_T1_RJC 0x04 +#define BIT_RCR1_T1_SYNCE 0x02 +#define BIT_RCR1_T1_RESYNC 0x01 +#define BIT_RCR1_E1_RHDB3 0x40 +#define BIT_RCR1_E1_RSIGM 0x20 +#define BIT_RCR1_E1_RG802 0x10 +#define BIT_RCR1_E1_RCRC4 0x08 +#define BIT_RCR1_E1_FRC 0x04 +#define BIT_RCR1_E1_SYNCE 0x02 +#define BIT_RCR1_E1_RESYNC 0x01 + +#define REG_RCR3 0x83 +#define BIT_RCR3_IDF 0x80 +#define BIT_RCR3_RSERC 0x20 +#define BIT_RCR3_PLB 0x02 +#define BIT_RCR3_FLB 0x01 + +#define REG_RIOCR 0x84 +#define BIT_RIOCR_RCLKINV 0x80 +#define BIT_RIOCR_RSYNCINV 0x40 +#define BIT_RIOCR_H100EN 0x20 +#define BIT_RIOCR_RSCLKM 0x10 +#define BIT_RIOCR_RSMS 0x08 +#define BIT_RIOCR_RSIO 0x04 +#define BIT_RIOCR_RSMS2 0x02 +#define BIT_RIOCR_RSMS1 0x01 + +#define REG_RESCR 0x85 +#define BIT_RESCR_RGCLKEN 0x40 +#define BIT_RESCR_RESE 0x01 + +#define REG_ERCNT 0x86 +#define BIT_ERCNT_1SECS 0x80 +#define BIT_ERCNT_MCUS 0x40 +#define BIT_ERCNT_MECU 0x20 +#define BIT_ERCNT_ECUS 0x10 +#define BIT_ERCNT_EAMS 0x08 +#define BIT_ERCNT_FSBE 0x04 +#define BIT_ERCNT_MOSCR 0x02 +#define BIT_ERCNT_LCVCRF 0x01 + +#define REG_RLS1 0x90 +#define BIT_RLS1_RRAIC 0x80 +#define BIT_RLS1_RAISC 0x40 +#define BIT_RLS1_RLOSC 0x20 +#define BIT_RLS1_RLOFC 0x10 +#define BIT_RLS1_RRAID 0x08 +#define BIT_RLS1_RAISD 0x04 +#define BIT_RLS1_RLOSD 0x02 +#define BIT_RLS1_RLOFD 0x01 + +#define REG_RLS2 0x91 +#define BIT_RLS2_T1_RPDV 0x80 +#define BIT_RLS2_T1_COFA 0x20 +#define BIT_RLS2_T1_8ZD 0x10 +#define BIT_RLS2_T1_16ZD 0x08 +#define BIT_RLS2_T1_SEFE 0x04 +#define BIT_RLS2_T1_B8ZS 0x02 +#define BIT_RLS2_T1_FBE 0x01 +#define BIT_RLS2_E1_CRCRC 0x40 +#define BIT_RLS2_E1_CASRC 0x20 +#define BIT_RLS2_E1_FASRC 0x10 +#define BIT_RLS2_E1_RSA1 0x08 +#define BIT_RLS2_E1_RSA0 0x04 +#define BIT_RLS2_E1_RCMF 0x02 +#define BIT_RLS2_E1_RAF 0x01 + +#define REG_RLS3 0x92 +#define BIT_RLS3_T1_LORCC 0x80 +#define BIT_RLS3_T1_LSPC 0x40 +#define BIT_RLS3_T1_LDNC 0x20 +#define BIT_RLS3_T1_LUPC 0x10 +#define BIT_RLS3_T1_LORCD 0x08 +#define BIT_RLS3_T1_LSPD 0x04 +#define BIT_RLS3_T1_LDND 0x02 +#define BIT_RLS3_T1_LUPD 0x01 +#define BIT_RLS3_E1_LORCC 0x80 +#define BIT_RLS3_E1_V52LNKC 0x20 +#define BIT_RLS3_E1_RDMAC 0x10 +#define BIT_RLS3_E1_LORCD 0x08 +#define BIT_RLS3_E1_V52LNKD 0x02 +#define BIT_RLS3_E1_RDMAD 0x01 + +#define REG_RLS4 0x93 +#define BIT_RLS4_RSCOS 0x08 +#define BIT_RLS4_TIMER 0x02 + +#define REG_RLS5 0x94 +#define REG_RLS6 0x95 +#define REG_RLS7 0x96 + +#define REG_RSS1 0x98 +#define BIT_RSS1_CH1 0x80 +#define BIT_RSS1_CH2 0x40 +#define BIT_RSS1_CH3 0x20 +#define BIT_RSS1_CH4 0x10 +#define BIT_RSS1_CH5 0x08 +#define BIT_RSS1_CH6 0x04 +#define BIT_RSS1_CH7 0x02 +#define BIT_RSS1_CH8 0x01 + +#define REG_RSS2 0x99 +#define BIT_RSS2_CH9 0x80 +#define BIT_RSS2_CH10 0x40 +#define BIT_RSS2_CH11 0x20 +#define BIT_RSS2_CH12 0x10 +#define BIT_RSS2_CH13 0x08 +#define BIT_RSS2_CH14 0x04 +#define BIT_RSS2_CH15 0x02 +#define BIT_RSS2_CH16 0x01 + +#define REG_RSS3 0x9A +#define BIT_RSS3_CH17 0x80 +#define BIT_RSS3_CH18 0x40 +#define BIT_RSS3_CH19 0x20 +#define BIT_RSS3_CH20 0x10 +#define BIT_RSS3_CH21 0x08 +#define BIT_RSS3_CH22 0x04 +#define BIT_RSS3_CH23 0x02 +#define BIT_RSS3_CH24 0x01 + +#define REG_RSS4 0x9B +#define BIT_RSS4_CH25 0x80 +#define BIT_RSS4_CH26 0x40 +#define BIT_RSS4_CH27 0x20 +#define BIT_RSS4_CH28 0x10 +#define BIT_RSS4_CH29 0x08 +#define BIT_RSS4_CH30 0x04 +#define BIT_RSS4_CH31 0x02 +#define BIT_RSS4_CH32 0x01 + +#define REG_RIIR 0x9F +#define BIT_RIIR_RLS7 0x40 +#define BIT_RIIR_RLS6 0x20 +#define BIT_RIIR_RLS5 0x10 +#define BIT_RIIR_RLS4 0x08 +#define BIT_RIIR_RLS3 0x04 +#define BIT_RIIR_RLS2 0x02 +#define BIT_RIIR_RLS1 0x01 + +#define REG_RIM1 0xA0 +#define BIT_RIM1_RRAIC 0x80 +#define BIT_RIM1_RAISC 0x40 +#define BIT_RIM1_RLOSC 0x20 +#define BIT_RIM1_RLOFC 0x10 +#define BIT_RIM1_RRAID 0x08 +#define BIT_RIM1_RAISD 0x04 +#define BIT_RIM1_RLOSD 0x02 +#define BIT_RIM1_RLOFD 0x01 + +#define REG_RIM2 0xA1 +#define BIT_RIM2_E1_RSA1 0x08 +#define BIT_RIM2_E1_RSA0 0x04 +#define BIT_RIM2_E1_RCMF 0x02 +#define BIT_RIM2_E1_RAF 0x01 + +#define REG_RIM3 0xA2 +#define BIT_RIM3_T1_LORCC 0x80 +#define BIT_RIM3_T1_LSPC 0x40 +#define BIT_RIM3_T1_LDNC 0x20 +#define BIT_RIM3_T1_LUPC 0x10 +#define BIT_RIM3_T1_LORCD 0x08 +#define BIT_RIM3_T1_LSPD 0x04 +#define BIT_RIM3_T1_LDND 0x02 +#define BIT_RIM3_T1_LUPD 0x01 +#define BIT_RIM3_E1_LORCC 0x80 +#define BIT_RIM3_E1_V52LNKC 0x20 +#define BIT_RIM3_E1_RDMAC 0x10 +#define BIT_RIM3_E1_LORCD 0x08 +#define BIT_RIM3_E1_V52LNKD 0x02 +#define BIT_RIM3_E1_RDMAD 0x01 + +#define REG_RIM4 0xA3 +#define BIT_RIM4_RESF 0x80 +#define BIT_RIM4_RESEM 0x40 +#define BIT_RIM4_RSLIP 0x20 +#define BIT_RIM4_RSCOS 0x08 +#define BIT_RIM4_1SEC 0x04 +#define BIT_RIM4_TIMER 0x02 +#define BIT_RIM4_RMF 0x01 + +#define REG_RIM5 0xA4 +#define BIT_RIM5_ROVR 0x20 +#define BIT_RIM5_RHOBT 0x10 +#define BIT_RIM5_RPE 0x08 +#define BIT_RIM5_RPS 0x04 +#define BIT_RIM5_RHWMS 0x02 +#define BIT_RIM5_RNES 0x01 + +#define REG_RIM7 0xA6 + +#define REG_RSCSE1 0xA8 +#define BITS_RSCSE1_ALL 0xFF +#define BIT_RSCSE1_CH1 0x80 +#define BIT_RSCSE1_CH2 0x40 +#define BIT_RSCSE1_CH3 0x20 +#define BIT_RSCSE1_CH4 0x10 +#define BIT_RSCSE1_CH5 0x08 +#define BIT_RSCSE1_CH6 0x04 +#define BIT_RSCSE1_CH7 0x02 +#define BIT_RSCSE1_CH8 0x01 + +#define REG_RSCSE2 0xA9 +#define BITS_RSCSE2_ALL 0xFF +#define BIT_RSCSE2_CH9 0x80 +#define BIT_RSCSE2_CH10 0x40 +#define BIT_RSCSE2_CH11 0x20 +#define BIT_RSCSE2_CH12 0x10 +#define BIT_RSCSE2_CH13 0x08 +#define BIT_RSCSE2_CH14 0x04 +#define BIT_RSCSE2_CH15 0x02 +#define BIT_RSCSE2_CH16 0x01 + +#define REG_RSCSE3 0xAA +#define BITS_RSCSE3_ALL 0xFF +#define BIT_RSCSE3_CH17 0x80 +#define BIT_RSCSE3_CH18 0x40 +#define BIT_RSCSE3_CH19 0x20 +#define BIT_RSCSE3_CH20 0x10 +#define BIT_RSCSE3_CH21 0x08 +#define BIT_RSCSE3_CH22 0x04 +#define BIT_RSCSE3_CH23 0x02 +#define BIT_RSCSE3_CH24 0x01 + +#define REG_RSCSE4 0xAB +#define BITS_RSCSE4_ALL 0xFF +#define BIT_RSCSE4_CH25 0x80 +#define BIT_RSCSE4_CH26 0x40 +#define BIT_RSCSE4_CH27 0x20 +#define BIT_RSCSE4_CH28 0x10 +#define BIT_RSCSE4_CH29 0x08 +#define BIT_RSCSE4_CH30 0x04 +#define BIT_RSCSE4_CH31 0x02 +#define BIT_RSCSE4_CH32 0x01 + +#define REG_RRTS1 0xB0 +#define BIT_RRTS1_RRAI 0x08 +#define BIT_RRTS1_RAIS 0x04 +#define BIT_RRTS1_RLOS 0x02 +#define BIT_RRTS1_RLOF 0x01 + +#define REG_RRTS3 0xB2 +#define BIT_RRTS3_T1_LORC 0x08 +#define BIT_RRTS3_T1_LSP 0x08 +#define BIT_RRTS3_T1_LDN 0x02 +#define BIT_RRTS3_T1_LUP 0x01 +#define BIT_RRTS3_E1_LORC 0x08 +#define BIT_RRTS3_E1_V52LNK 0x02 +#define BIT_RRTS3_E1_RDMA 0x01 + +#define REG_RGCCS1 0xCC +#define REG_RGCCS2 0xCD +#define REG_RGCCS3 0xCE +#define REG_RGCCS4 0xCF + +#define REG_RCICE1 0xD0 +#define REG_RCICE2 0xD1 +#define REG_RCICE3 0xD2 +#define REG_RCICE4 0xD3 + +/* TX Framer Register Definitions */ +#define REG_SSIE1 0x118 +#define BITS_SSIE1_ALL 0xFF +#define BIT_SSIE1_CH1 0x80 +#define BIT_SSIE1_CH2 0x40 +#define BIT_SSIE1_CH3 0x20 +#define BIT_SSIE1_CH4 0x10 +#define BIT_SSIE1_CH5 0x08 +#define BIT_SSIE1_CH6 0x04 +#define BIT_SSIE1_CH7 0x02 +#define BIT_SSIE1_CH8 0x01 + +#define REG_SSIE2 0x119 +#define BITS_SSIE2_ALL 0xFF +#define BIT_SSIE2_CH9 0x80 +#define BIT_SSIE2_CH10 0x40 +#define BIT_SSIE2_CH11 0x20 +#define BIT_SSIE2_CH12 0x10 +#define BIT_SSIE2_CH13 0x08 +#define BIT_SSIE2_CH14 0x04 +#define BIT_SSIE2_CH15 0x02 +#define BIT_SSIE2_CH16 0x01 + +#define REG_SSIE3 0x11A +#define BITS_SSIE3_ALL 0xFF +#define BIT_SSIE3_CH17 0x80 +#define BIT_SSIE3_CH18 0x40 +#define BIT_SSIE3_CH19 0x20 +#define BIT_SSIE3_CH20 0x10 +#define BIT_SSIE3_CH21 0x08 +#define BIT_SSIE3_CH22 0x04 +#define BIT_SSIE3_CH23 0x02 +#define BIT_SSIE3_CH24 0x01 + +#define REG_SSIE4 0x11B +#define BITS_SSIE4_ALL 0xFF +#define BIT_SSIE4_CH25 0x80 +#define BIT_SSIE4_CH26 0x40 +#define BIT_SSIE4_CH27 0x20 +#define BIT_SSIE4_CH28 0x10 +#define BIT_SSIE4_CH29 0x08 +#define BIT_SSIE4_CH30 0x04 +#define BIT_SSIE4_CH31 0x02 +#define BIT_SSIE4_CH32 0x01 + +#define REG_TS1 0x140 +#define BIT_TS_A 0x08 +#define BIT_TS_B 0x04 +#define BIT_TS_C 0x02 +#define BIT_TS_D 0x01 +#define REG_TS2 0x141 +#define REG_TS3 0x142 +#define REG_TS4 0x143 +#define REG_TS5 0x144 +#define REG_TS6 0x145 +#define REG_TS7 0x146 +#define REG_TS8 0x147 +#define REG_TS9 0x148 +#define REG_TS10 0x149 +#define REG_TS11 0x14A +#define REG_TS12 0x14B +#define REG_TS13 0x14C +#define REG_TS14 0x14D +#define REG_TS15 0x14E +#define REG_TS16 0x14F + +#define REG_TCICE1 0x150 +#define REG_TCICE2 0x151 +#define REG_TCICE3 0x152 +#define REG_TCICE4 0x153 + +#define REG_E1TAF 0x164 + +#define REG_E1TNAF 0x165 + +#define REG_TMMR 0x180 +#define BIT_TMMR_FRM_EN 0x80 +#define BIT_TMMR_INIT_DONE 0x40 +#define BIT_TMMR_SFTRST 0x02 +#define BIT_TMMR_T1E1 0x01 + +#define REG_TCR1 0x181 +#define BIT_TCR1_T1_TJC 0x80 +#define BIT_TCR1_T1_TFPT 0x40 +#define BIT_TCR1_T1_TCPT 0x20 +#define BIT_TCR1_T1_TSSE 0x10 +#define BIT_TCR1_T1_GB7S 0x08 +#define BIT_TCR1_T1_TB8ZS 0x04 +#define BIT_TCR1_T1_TAIS 0x02 +#define BIT_TCR1_T1_TRAI 0x01 +#define BIT_TCR1_E1_TTPT 0x80 +#define BIT_TCR1_E1_T16S 0x40 +#define BIT_TCR1_E1_TG802 0x20 +#define BIT_TCR1_E1_TSiS 0x10 +#define BIT_TCR1_E1_TSA1 0x08 +#define BIT_TCR1_E1_THDB3 0x04 +#define BIT_TCR1_E1_TAIS 0x02 +#define BIT_TCR1_E1_TCRC4 0x01 + +#define REG_TCR3 0x183 +#define BIT_TCR3_ODF 0x80 +#define BIT_TCR3_ODM 0x40 +#define BIT_TCR3_TCSS1 0x20 +#define BIT_TCR3_TCSS0 0x10 +#define BIT_TCR3_MFRS 0x08 +#define BIT_TCR3_TFM 0x04 +#define BIT_TCR3_IBPV 0x02 +#define BIT_TCR3_TLOOP 0x01 + +#define REG_TIOCR 0x184 +#define BIT_TIOCR_TCLKINV 0x80 +#define BIT_TIOCR_TSYNCINV 0x40 +#define BIT_TIOCR_TSSYNCINV 0x20 +#define BIT_TIOCR_TSCLKM 0x10 +#define BIT_TIOCR_TSSM 0x08 +#define BIT_TIOCR_TSIO 0x04 +#define BIT_TIOCR_TSDW 0x02 +#define BIT_TIOCR_TSM 0x01 + +#define REG_TESCR 0x185 +#define BIT_TESCR_TDATFMT 0x80 +#define BIT_TESCR_TGPCKEN 0x40 +#define BIT_TESCR_TESE 0x01 + +#define REG_TLS1 0x190 +#define BIT_TLS1_TPDV 0x08 +#define BIT_TLS1_TMF 0x04 +#define BIT_TLS1_LOTCC 0x02 +#define BIT_TLS1_LOTC 0x01 + +#define REG_TLS2 0x191 +#define REG_TLS3 0x192 + +#define REG_TIIR 0x19F +#define BIT_TIIR_TLS3 0x04 +#define BIT_TIIR_TLS2 0x02 +#define BIT_TIIR_TLS1 0x01 + +#define REG_TIM1 0x1A0 +#define REG_TIM2 0x1A1 +#define REG_TIM3 0x1A2 + +#define REG_TGCCS1 0x1CC +#define REG_TGCCS2 0x1CD +#define REG_TGCCS3 0x1CE +#define REG_TGCCS4 0x1CF + +/* LIU Register Definitions */ +#define REG_LTRCR 0x1000 +#define BIT_LTRCR_JADS 0x10 +#define BIT_LTRCR_JAPS1 0x08 +#define BIT_LTRCR_JAPS0 0x04 +#define BIT_LTRCR_T1J1E1S 0x02 +#define BIT_LTRCR_LSC 0x01 + +#define REG_LTITSR 0x1001 +#define BIT_LTITSR_TIMPTOFF 0x40 +#define BIT_LTITSR_TIMPL1 0x20 +#define BIT_LTITSR_TIMPL0 0x10 +#define BIT_LTITSR_L2 0x04 +#define BIT_LTITSR_L1 0x02 +#define BIT_LTITSR_L0 0x01 + +#define REG_LMCR 0x1002 +#define BIT_LMCR_TAIS 0x80 +#define BIT_LMCR_ATAIS 0x40 +#define BIT_LMCR_LLB 0x20 +#define BIT_LMCR_ALB 0x10 +#define BIT_LMCR_RLB 0x08 +#define BIT_LMCR_TPDE 0x04 +#define BIT_LMCR_RPLDE 0x02 +#define BIT_LMCR_TE 0x01 + +#define REG_LRSR 0x1003 +#define BIT_LRSR_OEQ 0x20 +#define BIT_LRSR_UEQ 0x10 +#define BIT_LRSR_SCS 0x04 +#define BIT_LRSR_OCS 0x02 +#define BIT_LRSR_LOSS 0x01 + +#define REG_LSIMR 0x1004 +#define BIT_LSIMR_JALTCIM 0x80 +#define BIT_LSIMR_OCCIM 0x40 +#define BIT_LSIMR_SCCIM 0x20 +#define BIT_LSIMR_LOSCIM 0x10 +#define BIT_LSIMR_JALTSIM 0x08 +#define BIT_LSIMR_OCDIM 0x04 +#define BIT_LSIMR_SCDIM 0x02 +#define BIT_LSIMR_LOSDIM 0x01 + +#define REG_LLSR 0x1005 +#define BIT_LLSR_JALTC 0x80 +#define BIT_LLSR_OCC 0x40 +#define BIT_LLSR_SCC 0x20 +#define BIT_LLSR_LOSC 0x10 +#define BIT_LLSR_JALTS 0x08 +#define BIT_LLSR_OCD 0x04 +#define BIT_LLSR_SCD 0x03 +#define BIT_LLSR_LOSD 0x01 + +#define REG_LRISMR 0x1007 +#define BIT_LRISMR_RG703 0x80 +#define BIT_LRISMR_RIMPOFF 0x40 +#define BIT_LRISMR_RIMPM1 0x20 +#define BIT_LRISMR_RIMPM0 0x10 +#define BIT_LRISMR_RTR 0x08 +#define BIT_LRISMR_RMONEN 0x04 +#define BIT_LRISMR_RSMS1 0x02 +#define BIT_LRISMR_RSMS0 0x01 + +/* BERT Register Definitions */ +#define REG_BLSR 0x110E + +#endif /* __SDLA_TE1_DS_H */ diff -Nur linux.org/include/linux/sdla_te1.h linux-2.6.17/include/linux/sdla_te1.h --- linux.org/include/linux/sdla_te1.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/sdla_te1.h 2006-08-30 10:07:15.000000000 +0000 @@ -0,0 +1,519 @@ +/* + * Copyright (c) 2001 + * Alex Feldman . All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Alex Feldman. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Alex Feldman AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Alex Feldman OR THE VOICES IN HIS HEAD + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + * $Id$ + */ + +/***************************************************************************** + * sdla_te1.h Sangoma TE1 configuration definitions. + * + * Author: Alex Feldman + * + * ============================================================================ + * Aprl 30, 2001 Alex Feldman Initial version. + **************************************************************************** +*/ +#ifndef _SDLA_TE1_H +# define _SDLA_TE1_H + +#ifdef SDLA_TE1 +# define EXTERN +#else +# define EXTERN extern +#endif + +/************************************************************************ + * DEFINES AND MACROS * + ***********************************************************************/ +#if 0 +#if defined(__NetBSD__) || defined (__FreeBSD__) || defined (__OpenBSD__) +# include +#elif defined (__WINDOWS__) +# include "sdla_te1_pmc.h" +#else +# include +#endif +#endif + +/* +************************************************************************* +* DEFINES AND MACROS * +************************************************************************* +*/ + +#define NUM_OF_T1_CHANNELS 24 +#define NUM_OF_E1_TIMESLOTS 31 +#define NUM_OF_E1_CHANNELS 32 +#define ENABLE_ALL_CHANNELS 0xFFFFFFFF + +#define E1_FRAMING_TIMESLOT 0 +#define E1_SIGNALING_TIMESLOT 16 + +#define WAN_TE_SIG_POLL 0x01 +#define WAN_TE_SIG_INTR 0x02 + +/* Framer Alarm bit mask */ +#define WAN_TE_BIT_ALOS_ALARM 0x0001 +#define WAN_TE_BIT_LOS_ALARM 0x0002 +#define WAN_TE_BIT_ALTLOS_ALARM 0x0004 +#define WAN_TE_BIT_OOF_ALARM 0x0008 +#define WAN_TE_BIT_RED_ALARM 0x0010 +#define WAN_TE_BIT_AIS_ALARM 0x0020 +#define WAN_TE_BIT_OOSMF_ALARM 0x0040 +#define WAN_TE_BIT_OOCMF_ALARM 0x0080 +#define WAN_TE_BIT_OOOF_ALARM 0x0100 +#define WAN_TE_BIT_RAI_ALARM 0x0200 +#define WAN_TE_BIT_YEL_ALARM 0x0400 +#define WAN_TE_BIT_LOOPUP_CODE 0x2000 +#define WAN_TE_BIT_LOOPDOWN_CODE 0x4000 +#define WAN_TE_BIT_TE1_ALARM 0x8000 /* for Windows only */ +#define IS_TE_ALARM(alarm, mask) (alarm & mask) +#define IS_TE_ALOS_ALARM(alarm) IS_TE_ALARM(alarm, WAN_TE_BIT_ALOS_ALARM) +#define IS_TE_LOS_ALARM(alarm) IS_TE_ALARM(alarm, WAN_TE_BIT_LOS_ALARM) +#define IS_TE_OOF_ALARM(alarm) IS_TE_ALARM(alarm, WAN_TE_BIT_OOF_ALARM) +#define IS_TE_RED_ALARM(alarm) IS_TE_ALARM(alarm, WAN_TE_BIT_RED_ALARM) +#define IS_TE_AIS_ALARM(alarm) IS_TE_ALARM(alarm, WAN_TE_BIT_AIS_ALARM) +#define IS_TE_OOSMF_ALARM(alarm) IS_TE_ALARM(alarm, WAN_TE_BIT_OOSMF_ALARM) +#define IS_TE_OOCMF_ALARM(alarm) IS_TE_ALARM(alarm, WAN_TE_BIT_OOCMF_ALARM) +#define IS_TE_OOOF_ALARM(alarm) IS_TE_ALARM(alarm, WAN_TE_BIT_OOOF_ALARM) +#define IS_TE_RAI_ALARM(alarm) IS_TE_ALARM(alarm, WAN_TE_BIT_RAI_ALARM) +#define IS_TE_YEL_ALARM(alarm) IS_TE_ALARM(alarm, WAN_TE_BIT_YEL_ALARM) + +/* Performance monitor counters bit mask */ +#define WAN_TE_BIT_PMON_LCV 0x01 /* line code violation counter */ +#define WAN_TE_BIT_PMON_BEE 0x02 /* bit errror event (T1) */ +#define WAN_TE_BIT_PMON_OOF 0x04 /* frame out of sync counter */ +#define WAN_TE_BIT_PMON_FEB 0x08 /* far end block counter */ +#define WAN_TE_BIT_PMON_CRC4 0x10 /* crc4 error counter (E1) */ +#define WAN_TE_BIT_PMON_FER 0x20 /* framing bit error (T1-pmc) */ +#define WAN_TE_BIT_PMON_FAS 0x40 /* Frame Alginment signal (E1) */ + +/* LIU Alarm bit mask */ +#define WAN_TE_BIT_LIU_ALARM 0x8000 /* print liu status */ +#define WAN_TE_BIT_LIU_ALARM_SC 0x0001 +#define WAN_TE_BIT_LIU_ALARM_OC 0x0002 +#define WAN_TE_BIT_LIU_ALARM_LOS 0x0004 + +/* For T1 only */ +#define WAN_T1_LBO_0_DB 0x01 +#define WAN_T1_LBO_75_DB 0x02 +#define WAN_T1_LBO_15_DB 0x03 +#define WAN_T1_LBO_225_DB 0x04 +#define WAN_T1_0_110 0x05 +#define WAN_T1_110_220 0x06 +#define WAN_T1_220_330 0x07 +#define WAN_T1_330_440 0x08 +#define WAN_T1_440_550 0x09 +#define WAN_T1_550_660 0x0A +/* For E1 only */ +#define WAN_E1_120 0x0B +#define WAN_E1_75 0x0C +/* T1/E1 8 ports */ +#define WAN_T1_0_133 0x0D +#define WAN_T1_133_266 0x0E +#define WAN_T1_266_399 0x0F +#define WAN_T1_399_533 0x10 +#define WAN_T1_533_655 0x11 + + +/* For T1 only (long or short haul) */ +#define WAN_T1_LONG_HAUL 0x01 +#define WAN_T1_SHORT_HAUL 0x02 + +/* Line loopback modes */ +#define WAN_TE1_LINELB_MODE 0x01 +#define WAN_TE1_PAYLB_MODE 0x02 +#define WAN_TE1_DDLB_MODE 0x03 +#define WAN_TE1_TX_LB_MODE 0x04 +#define WAN_TE1_LIU_ALB_MODE 0x05 +#define WAN_TE1_LIU_LLB_MODE 0x06 +#define WAN_TE1_LIU_RLB_MODE 0x07 +#define WAN_TE1_LIU_DLB_MODE 0x08 +#define WAN_TE1_FR_FLB_MODE 0x09 +#define WAN_TE1_FR_PLB_MODE 0x0A +#define WAN_TE1_FR_RLB_MODE 0x0B +#define WAN_TE1_LB_TYPE_DECODE(type) \ + (type == WAN_TE1_LINELB_MODE) ? "Line Loopback" : \ + (type == WAN_TE1_PAYLB_MODE) ? "Payload Loopback" : \ + (type == WAN_TE1_DDLB_MODE) ? "Diagnostic Digital Loopback" : \ + (type == WAN_TE1_TX_LB_MODE) ? "TX Loopback" : \ + (type == WAN_TE1_LIU_ALB_MODE) ? "Analog LIU Loopback" : \ + (type == WAN_TE1_LIU_LLB_MODE) ? "Local LIU Loopback" : \ + (type == WAN_TE1_LIU_RLB_MODE) ? "Remote LIU Loopback" : \ + (type == WAN_TE1_LIU_DLB_MODE) ? "Dual LIU Loopback" : \ + (type == WAN_TE1_FR_FLB_MODE) ? "Framer Loopback" : \ + (type == WAN_TE1_FR_RLB_MODE) ? "Remote Framer Loopback" : \ + (type == WAN_TE1_FR_PLB_MODE) ? "Payload Framer Loopback" : \ + "Unknown Loopback" + +/* Line loopback activate/deactive modes */ +#define WAN_TE1_ACTIVATE_LB 0x01 +#define WAN_TE1_DEACTIVATE_LB 0x02 +#define WAN_TE1_LB_MODE_DECODE(mode) \ + (mode == WAN_TE1_ACTIVATE_LB) ? "Activate" : \ + (mode == WAN_TE1_DEACTIVATE_LB) ? "Deactivate" :\ + "Unknown" + +/* T1/E1 front end Master clock source */ +#define WAN_TE1_REFCLK_OSC 0x00 +#define WAN_TE1_REFCLK_LINE1 0x01 +#define WAN_TE1_REFCLK_LINE2 0x02 +#define WAN_TE1_REFCLK_LINE3 0x03 +#define WAN_TE1_REFCLK_LINE4 0x04 + +/* E1 signalling insertion mode */ +#define WAN_TE1_SIG_NONE 0x00 /* default */ +#define WAN_TE1_SIG_CCS 0x01 /* E1 CCS - default */ +#define WAN_TE1_SIG_CAS 0x02 /* E1 CAS */ + +/* Loopback commands (T1.107-1995 p.44) */ +#define LINELB_TE1_TIMER 40 /* 40ms */ +#define LINELB_CODE_CNT 10 /* no. of repetitions for lb_code */ +#define LINELB_CHANNEL_CNT 10 /* no. of repetitions for channel */ +#define LINELB_ACTIVATE_CODE 0x07 +#define LINELB_DEACTIVATE_CODE 0x1C +#define LINELB_DS3LINE 0x1B +#define LINELB_DS1LINE_1 0x21 +#define LINELB_DS1LINE_2 0x22 +#define LINELB_DS1LINE_3 0x23 +#define LINELB_DS1LINE_4 0x24 +#define LINELB_DS1LINE_5 0x25 +#define LINELB_DS1LINE_6 0x26 +#define LINELB_DS1LINE_7 0x27 +#define LINELB_DS1LINE_8 0x28 +#define LINELB_DS1LINE_9 0x29 +#define LINELB_DS1LINE_10 0x2A +#define LINELB_DS1LINE_11 0x2B +#define LINELB_DS1LINE_12 0x2C +#define LINELB_DS1LINE_13 0x2D +#define LINELB_DS1LINE_14 0x2E +#define LINELB_DS1LINE_15 0x2F +#define LINELB_DS1LINE_16 0x30 +#define LINELB_DS1LINE_17 0x31 +#define LINELB_DS1LINE_18 0x32 +#define LINELB_DS1LINE_19 0x33 +#define LINELB_DS1LINE_20 0x34 +#define LINELB_DS1LINE_21 0x35 +#define LINELB_DS1LINE_22 0x36 +#define LINELB_DS1LINE_23 0x37 +#define LINELB_DS1LINE_24 0x38 +#define LINELB_DS1LINE_25 0x39 +#define LINELB_DS1LINE_26 0x3A +#define LINELB_DS1LINE_27 0x3B +#define LINELB_DS1LINE_28 0x3C +#define LINELB_DS1LINE_ALL 0x13 +#define LINELB_DS1LINE_MASK 0x1F + +/* Interrupt polling delay */ +#define POLLING_TE1_TIMER 1000 /* 1 sec */ + +/* TE1 critical flag */ +#define TE_TIMER_RUNNING 0x01 +#define TE_TIMER_KILL 0x02 +#define LINELB_WAITING 0x03 +#define LINELB_CODE_BIT 0x04 +#define LINELB_CHANNEL_BIT 0x05 +#define TE_CONFIGURED 0x06 + +/* TE1 timer flags (polling) */ +#define TE_LINELB_TIMER 0x01 +#define TE_LINKDOWN_TIMER 0x02 +#define TE_SET_INTR 0x03 +#define TE_RBS_READ 0x04 +#define TE_LINKUP_TIMER 0x05 +#define TE_SET_RBS 0x06 +#define TE_UPDATE_PMON 0x07 +#define TE_SET_LB_MODE 0x08 + +/* TE1 T1/E1 interrupt setting delay */ +#define INTR_TE1_TIMER 150 /* 50 ms */ + +/* T1/E1 RBS flags (bit-map) */ +#define WAN_TE_RBS_NONE 0x00 +#define WAN_TE_RBS_UPDATE 0x01 +#define WAN_TE_RBS_REPORT 0x02 + + +#define IS_T1_CARD(card) IS_T1_FEMEDIA(&(card)->fe) +#define IS_E1_CARD(card) IS_E1_FEMEDIA(&(card)->fe) +#define IS_TE1_CARD(card) IS_TE1_FEMEDIA(&(card)->fe) + +#define FE_LBO(fe_cfg) (fe_cfg)->cfg.te_cfg.lbo +#define FE_CLK(fe_cfg) (fe_cfg)->cfg.te_cfg.te_clock +#define FE_REFCLK(fe_cfg) (fe_cfg)->cfg.te_cfg.te_ref_clock +#define HIMPEDANCE_MODE(fe_cfg) (fe_cfg)->cfg.te_cfg.high_impedance_mode +#define FE_ACTIVE_CH(fe_cfg) (fe_cfg)->cfg.te_cfg.active_ch +#define FE_SIG_MODE(fe_cfg) (fe_cfg)->cfg.te_cfg.sig_mode + +#define IS_TE1_UNFRAMED(fe) \ + (((sdla_fe_t*)(fe))->fe_cfg.frame == WAN_FR_UNFRAMED) + +#define GET_TE_CHANNEL_RANGE(fe) \ + (IS_T1_FEMEDIA(fe) ? NUM_OF_T1_CHANNELS :\ + IS_E1_FEMEDIA(fe) ? NUM_OF_E1_CHANNELS :0) + + +#define WAN_TE_ALARM(alarm, bit) ((alarm) & (bit)) ? "ON" : "OFF" + +#define WAN_TE_ALOS_ALARM(alarm) WAN_TE_ALARM(alarm, WAN_TE_BIT_ALOS_ALARM) +#define WAN_TE_LOS_ALARM(alarm) WAN_TE_ALARM(alarm, WAN_TE_BIT_LOS_ALARM) +#define WAN_TE_OOF_ALARM(alarm) WAN_TE_ALARM(alarm, WAN_TE_BIT_OOF_ALARM) +#define WAN_TE_RED_ALARM(alarm) WAN_TE_ALARM(alarm, WAN_TE_BIT_RED_ALARM) +#define WAN_TE_AIS_ALARM(alarm) WAN_TE_ALARM(alarm, WAN_TE_BIT_AIS_ALARM) +#define WAN_TE_OOSMF_ALARM(alarm) WAN_TE_ALARM(alarm, WAN_TE_BIT_OOSMF_ALARM) +#define WAN_TE_OOCMF_ALARM(alarm) WAN_TE_ALARM(alarm, WAN_TE_BIT_OOCMF_ALARM) +#define WAN_TE_OOOF_ALARM(alarm) WAN_TE_ALARM(alarm, WAN_TE_BIT_OOOF_ALARM) +#define WAN_TE_RAI_ALARM(alarm) WAN_TE_ALARM(alarm, WAN_TE_BIT_RAI_ALARM) +#define WAN_TE_YEL_ALARM(alarm) WAN_TE_ALARM(alarm, WAN_TE_BIT_YEL_ALARM) + +#define WAN_TE_LIU_ALARM_SC(alarm) WAN_TE_ALARM(alarm, WAN_TE_BIT_LIU_ALARM_SC) +#define WAN_TE_LIU_ALARM_OC(alarm) WAN_TE_ALARM(alarm, WAN_TE_BIT_LIU_ALARM_OC) +#define WAN_TE_LIU_ALARM_LOS(alarm) WAN_TE_ALARM(alarm, WAN_TE_BIT_LIU_ALARM_LOS) + +#define TECLK_DECODE(fe_cfg) \ + (FE_CLK(fe_cfg) == WAN_NORMAL_CLK) ? "Normal" : \ + (FE_CLK(fe_cfg) == WAN_MASTER_CLK) ? "Master" : "Unknown" + +#define LBO_DECODE(fe_cfg) \ + (FE_LBO(fe_cfg) == WAN_T1_LBO_0_DB) ? "0db" : \ + (FE_LBO(fe_cfg) == WAN_T1_LBO_75_DB) ? "7.5db" : \ + (FE_LBO(fe_cfg) == WAN_T1_LBO_15_DB) ? "15dB" : \ + (FE_LBO(fe_cfg) == WAN_T1_LBO_225_DB) ? "22.5dB" : \ + (FE_LBO(fe_cfg) == WAN_T1_0_110) ? "0-110ft" : \ + (FE_LBO(fe_cfg) == WAN_T1_110_220) ? "110-220ft" : \ + (FE_LBO(fe_cfg) == WAN_T1_220_330) ? "220-330ft" : \ + (FE_LBO(fe_cfg) == WAN_T1_330_440) ? "330-440ft" : \ + (FE_LBO(fe_cfg) == WAN_T1_440_550) ? "440-550ft" : \ + (FE_LBO(fe_cfg) == WAN_T1_550_660) ? "550-660ft" : \ + (FE_LBO(fe_cfg) == WAN_T1_0_133) ? "0-133ft" : \ + (FE_LBO(fe_cfg) == WAN_T1_133_266) ? "133-266ft" : \ + (FE_LBO(fe_cfg) == WAN_T1_266_399) ? "266-399ft" : \ + (FE_LBO(fe_cfg) == WAN_T1_399_533) ? "399-533ft" : \ + (FE_LBO(fe_cfg) == WAN_T1_533_655) ? "5330-599ft": \ + (FE_LBO(fe_cfg) == WAN_E1_120) ? "120OH" : \ + (FE_LBO(fe_cfg) == WAN_E1_75) ? "75OH" : \ + "Unknown" + +/* Front-End UDP command */ +#define WAN_FE_GET_STAT (WAN_FE_UDP_CMD_START + 0) +#define WAN_FE_SET_LB_MODE (WAN_FE_UDP_CMD_START + 1) +#define WAN_FE_FLUSH_PMON (WAN_FE_UDP_CMD_START + 2) +#define WAN_FE_GET_CFG (WAN_FE_UDP_CMD_START + 3) +#define WAN_FE_SET_DEBUG_MODE (WAN_FE_UDP_CMD_START + 4) +#define WAN_FE_TX_MODE (WAN_FE_UDP_CMD_START + 5) + +/* FE interrupt types */ +#define WAN_TE_INTR_NONE 0x00 +#define WAN_TE_INTR_GLOBAL 0x01 +#define WAN_TE_INTR_BASIC 0x02 +#define WAN_TE_INTR_SIGNALLING 0x03 +#define WAN_TE_INTR_FXS_DTMF 0x04 +#define WAN_TE_INTR_PMON 0x05 + +/*---------------------------------------------------------------------------- + * T1/E1 configuration structures. + */ +typedef struct sdla_te_cfg { + unsigned char lbo; + unsigned char te_clock; + unsigned long active_ch; + unsigned long te_rbs_ch; + unsigned char high_impedance_mode; + unsigned char te_ref_clock; + unsigned char sig_mode; +} sdla_te_cfg_t; + +/* Performamce monitor counters */ +typedef struct { + unsigned char mask; + unsigned long lcv_errors; /* Line code violation (T1/E1) */ + unsigned long bee_errors; /* Bit errors (T1) */ + unsigned long oof_errors; /* Frame out of sync (T1) */ + unsigned long crc4_errors; /* CRC4 errors (E1) */ + unsigned long fas_errors; /* Frame Aligment Signal (E1)*/ + unsigned long feb_errors; /* Far End Block errors (E1) */ + unsigned long fer_errors; /* Framing bit errors (T1) */ +} sdla_te_pmon_t; + +/* + ****************************************************************************** + STRUCTURES AND TYPEDEFS + ****************************************************************************** +*/ + +#ifdef WAN_KERNEL + +#define WAN_TE1_LBO(fe) FE_LBO(&((fe)->fe_cfg)) +#define WAN_TE1_CLK(fe) FE_CLK(&((fe)->fe_cfg)) +#define WAN_TE1_REFCLK(fe) FE_REFCLK(&((fe)->fe_cfg)) +#define WAN_TE1_HI_MODE(fe) HIMPEDANCE_MODE(&((fe)->fe_cfg)) +#define WAN_TE1_ACTIVE_CH(fe) FE_ACTIVE_CH(&((fe)->fe_cfg)) +#define WAN_TE1_SIG_MODE(fe) FE_SIG_MODE(&((fe)->fe_cfg)) + +#define TE_LBO_DECODE(fe) LBO_DECODE(&((fe)->fe_cfg)) +#define TE_CLK_DECODE(fe) TECLK_DECODE(&((fe)->fe_cfg)) + +/* Read/Write to front-end register */ +#if 0 +#if 0 +#define READ_REG(reg) card->wandev.read_front_end_reg(card, reg) +#define WRITE_REG(reg, value) card->wandev.write_front_end_reg(card, reg, (unsigned char)(value)) +#endif +#define WRITE_REG(reg,val) \ + fe->write_fe_reg( \ + fe->card, \ + (int)((reg) + (fe->fe_cfg.line_no*PMC4_LINE_DELTA)), \ + (int)(val)) + +#define WRITE_REG_LINE(fe_line_no, reg,val) \ + fe->write_fe_reg( \ + fe->card, \ + (int)((reg) + (fe_line_no)*PMC4_LINE_DELTA), \ + (int)(val)) + +#define READ_REG(reg) \ + fe->read_fe_reg( \ + fe->card, \ + (int)((reg) + (fe->fe_cfg.line_no*PMC4_LINE_DELTA))) + +#define READ_REG_LINE(fe_line_no, reg) \ + fe->read_fe_reg( \ + fe->card, \ + (int)((reg) + (fe_line_no)*PMC4_LINE_DELTA)) +#endif + +/* ----------------------------------------------------------------------------- + * Constants for the SET_T1_E1_SIGNALING_CFG/READ_T1_E1_SIGNALING_CFG commands + * ---------------------------------------------------------------------------*/ + +/* the structure for setting the signaling permission */ +#pragma pack(1) +typedef struct { + unsigned char time_slot[32]; +} te_signaling_perm_t; +#pragma pack() + +/* settings for the signaling permission structure */ +#define TE_SIG_DISABLED 0x00 /* signaling is disabled */ +#define TE_RX_SIG_ENABLED 0x01 /* receive signaling is enabled */ +#define TE_TX_SIG_ENABLED 0x02 /* transmit signaling is enabled */ +#define TE_SET_TX_SIG_BITS 0x80 /* a flag indicating that outgoing + signaling bits should be set */ + +/* the structure used for the + * SET_T1_E1_SIGNALING_CFG/READ_T1_E1_SIGNALING_CFG command + */ +#pragma pack(1) +typedef struct { + /* signaling permission structure */ + te_signaling_perm_t sig_perm; + /* loop signaling processing counter */ + unsigned char sig_processing_counter; + /* pointer to the signaling permission structure */ + unsigned long ptr_te_sig_perm_struct; + /* pointer to the receive signaling structure */ + unsigned long ptr_te_Rx_sig_struct; + /* pointer to the transmit signaling structure */ + unsigned long ptr_te_Tx_sig_struct; +} te_signaling_cfg_t; +#pragma pack() + +/* the structure used for reading and setting the signaling bits */ +#pragma pack(1) +typedef struct { + unsigned char time_slot[32]; +} te_signaling_status_t; +#pragma pack() + +typedef struct { + unsigned char lb_cmd; + unsigned long lb_time; + + unsigned char lb_tx_cmd; + unsigned long lb_tx_cnt; + + unsigned char critical; + wan_timer_t timer; + unsigned char timer_cmd; + int timer_channel; /* tx rbs per channel */ + unsigned char timer_abcd; /* tx rbs pec channel */ + + unsigned char SIGX_chg_30_25; + unsigned char SIGX_chg_24_17; + unsigned char SIGX_chg_16_9; + unsigned char SIGX_chg_8_1; + + unsigned long ptr_te_sig_perm_off; + unsigned long ptr_te_Rx_sig_off; + unsigned long ptr_te_Tx_sig_off; + + unsigned char intr_src1; + unsigned char intr_src2; + unsigned char intr_src3; + + unsigned int max_channels; + + unsigned long rx_rbs_status; + unsigned char rx_rbs[32]; + unsigned char tx_rbs[32]; + + unsigned long tx_rbs_A; + unsigned long tx_rbs_B; + unsigned long tx_rbs_C; + unsigned long tx_rbs_D; + + unsigned long rx_rbs_A; + unsigned long rx_rbs_B; + unsigned long rx_rbs_C; + unsigned long rx_rbs_D; + + unsigned char xlpg_scale; +} sdla_te_param_t; + + +/* + ****************************************************************************** + FUNCTION PROTOTYPES + ****************************************************************************** +*/ + +EXTERN int sdla_te_default_cfg(void* pfe, void* fe_cfg, int media); +EXTERN int sdla_te_copycfg(void* pfe, void* fe_cfg); + +EXTERN int sdla_te_iface_init(void *p_fe_iface); +EXTERN int sdla_8te1_iface_init(void *p_fe_iface); + +#endif /* WAN_KERNEL */ + +#undef EXTERN + + +#endif /* _SDLA_TE1_H */ diff -Nur linux.org/include/linux/sdla_te1_pmc.h linux-2.6.17/include/linux/sdla_te1_pmc.h --- linux.org/include/linux/sdla_te1_pmc.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/sdla_te1_pmc.h 2006-08-30 10:07:15.000000000 +0000 @@ -0,0 +1,775 @@ +/* + * Copyright (c) 2001 + * Alex Feldman . All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Alex Feldman. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Alex Feldman AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Alex Feldman OR THE VOICES IN HIS HEAD + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + * $Id$ + */ + +/***************************************************************************** + * sdla_te1_pmc.h Sangoma TE1 configuration definitions (PMC). + * + * Author: Alex Feldman + * + * ============================================================================ + * Aprl 30, 2001 Alex Feldman Initial version. + **************************************************************************** +*/ +#ifndef __SDLA_TE1_PMC_H +# define __SDLA_TE1_PMC_H + +/* + ****************************************************************************** + DEFINES AND MACROS + ****************************************************************************** +*/ +#define PMC4_LINE_DELTA 0x100 + +#define REG_GLOBAL_CFG 0x00 +#define BIT_GLOBAL_PIO_OE 0x80 +#define BIT_GLOBAL_PIO 0x40 +#define BIT_GLOBAL_TRKEN 0x04 +#define BIT_GLOBAL_E1 0x01 + +#define REG_RECEIVE_OPT 0x02 +#define BIT_RECEIVE_OPT_UNF 0x40 + +#define REG_TX_LINE_CONF 0x04 +#define BIT_TX_LINE_CONF_TJATBYP 0x80 +#define BIT_TX_LINE_CONF_TAISEN 0x40 +#define BIT_TX_LINE_CONF_TAUXP 0x20 + +#define REG_TX_TIMING_OPT 0x06 +#define BIT_TX_PLLREF1 0x08 +#define BIT_TX_PLLREF0 0x04 +#define BIT_TX_TXELSTBYP 0x01 + +#define REG_MASTER_DIAG 0x0A +#define BIT_MASTER_DIAG_PAYLB 0x20 +#define BIT_MASTER_DIAG_LINELB 0x10 +#define BIT_MASTER_DIAG_DDLB 0x04 + +#define REG_REVISION_CHIP_ID 0x0D +#define MASK_CHIP_ID 0xE0 +#define CHIP_ID_COMET_QUAD 0x40 +#define CHIP_ID_COMET 0x20 +#define DECODE_CHIPID(chip_id) \ + (chip_id == CHIP_ID_COMET_QUAD) ? "COMET-QUAD" : \ + (chip_id == CHIP_ID_COMET) ? "COMET" : "Unknown" + +#define REG_RESET 0x0E +#define BIT_RESET 0x01 + +#define REG_PRGD_CTRL 0x0F +#define BIT_PRGD_CTRL_HDLC3 0x80 +#define BIT_PRGD_CTRL_HDLC2 0x40 +#define BIT_PRGD_CTRL_HDLC1 0x20 +#define BIT_PRGD_CTRL_Nx56k_GEN 0x10 +#define BIT_PRGD_CTRL_Nx56k_DET 0x08 +#define BIT_PRGD_CTRL_RXPATGEN 0x04 +#define BIT_PRGD_CTRL_UNF_GEN 0x02 +#define BIT_PRGD_CTRL_UNF_DET 0x01 + +#define REG_CDRC_CFG 0x10 +#define BIT_CDRC_CFG_AMI 0x80 +#define BIT_CDRC_CFG_LOS1 0x40 +#define BIT_CDRC_CFG_LOS0 0x20 + +#define REG_CDRC_INT_STATUS 0x12 +#define BIT_CDRC_INT_STATUS_LCVI 0x80 +#define BIT_CDRC_INT_STATUS_LOSI 0x40 +#define BIT_CDRC_INT_STATUS_LCSDI 0x20 +#define BIT_CDRC_INT_STATUS_ZNDI 0x10 +#define BIT_CDRC_INT_STATUS_LOSV 0x01 + +#define REG_ALTLOS_STATUS 0x13 +#define BIT_ALTLOS_STATUS_ALTLOSE 0x80 +#define BIT_ALTLOS_STATUS_ALTLOSI 0x40 +#define BIT_ALTLOS_STATUS_ALTLOS 0x01 + +#define REG_RJAT_CFG 0x17 +#define BIT_RJAT_CENT 0x10 + +#define REG_TJAT_CFG 0x1B +#define BIT_TJAT_CENT 0x10 + +#define REG_RX_ELST_CFG 0x1C +#define MASK_RX_ELST_CFG 0x03 +#define BIT_RX_ELST_IR 0x02 +#define BIT_RX_ELST_OR 0x01 + +#define REG_TX_ELST_CFG 0x20 +#define MASK_TX_ELST_CFG 0x03 +#define BIT_TX_ELST_IR 0x02 +#define BIT_TX_ELST_OR 0x01 + +#define REG_BRIF_CFG 0x30 +#define BIT_BRIF_NXDS0_1 0x80 +#define BIT_BRIF_NXDS0_0 0x40 +#define BIT_BRIF_CMODE 0x20 +#define BIT_BRIF_DE 0x10 +#define BIT_BRIF_FE 0x08 +#define BIT_BRIF_CMS 0x04 +#define BIT_BRIF_RATE1 0x02 +#define BIT_BRIF_RATE0 0x01 + +#define REG_BRIF_FR_PULSE_CFG 0x31 +#define BIT_BRIF_FPMODE 0x20 +#define BIT_BRIF_ROHM 0x08 + +#define REG_BRIF_DATA_CFG 0x32 +#define BIT_BRIF_DATA_TRI_0 0x01 /* PMC4351 */ +#define BIT_BRIF_DATA_TRI 0x01 /* PMC4354 */ + +#define REG_BTIF_CFG 0x40 +#define BIT_BTIF_NXDS0_1 0x80 +#define BIT_BTIF_NXDS0_0 0x40 +#define BIT_BTIF_CMODE 0x20 +#define BIT_BTIF_DE 0x10 +#define BIT_BTIF_FE 0x08 +#define BIT_BTIF_RATE0 0x01 + +#define REG_BTIF_FR_PULSE_CFG 0x41 +#define BIT_BTIF_FPMODE 0x01 + +#define REG_BTIF_CFG_STATUS 0x42 +#define BIT_BTIF_CFG_STATUS_TPTYP 0x80 +#define BIT_BTIF_CFG_STATUS_TPTYE 0x40 +#define BIT_BTIF_CFG_STATUS_TDI 0x20 +#define BIT_BTIF_CFG_STATUS_TSIGI 0x10 +#define BIT_BTIF_CFG_STATUS_PTY_EXTD 0x08 + +#define REG_BTIF_BIT_OFF 0x44 +#define BIT_BTIF_BIT_OFF_BOFF_EN 0x08 +#define BIT_BTIF_BIT_OFF_BOFF_2 0x04 +#define BIT_BTIF_BIT_OFF_BOFF_1 0x02 +#define BIT_BTIF_BIT_OFF_BOFF_0 0x01 + +#define REG_T1_FRMR_CFG 0x48 +#define BIT_T1_FRMR_ESF 0x20 +#define BIT_T1_FRMR_ESFFA 0x10 +#define BIT_T1_FRMR_FMS1 0x08 +#define BIT_T1_FRMR_FMS0 0x04 +#define BIT_T1_FRMR_JPN 0x02 + +#define REG_SIGX_CFG 0x50 +#define BIT_SIGX_ESF 0x04 +#define BIT_SIGX_IND 0x02 +#define BIT_SIGX_PCCE 0x01 +#define BIT_SIGX_SIGE 0x20 +#define BIT_SIGX_COSS 0x40 +#define REG_SIGX_CHG_30_25 0x50 +#define MASK_SIGX_COSS_30_25 0x3F +#define REG_SIGX_CHG_24_17 0x51 +#define REG_SIGX_CHG_16_9 0x52 +#define REG_SIGX_CHG_8_1 0x53 + +#define REG_SIGX_TIMESLOT_IND_STATUS 0x51 +#define BIT_SIGX_BUSY 0x80 +#define REG_SIGX_TIMESLOT_IND_ACCESS 0x52 +#define BIT_SIGX_TS_IND_ACCESS_READ 0x80 +#define REG_SIGX_TIMESLOT_IND_DATA_BUFFER 0x53 + +#define REG_SIGX_CURRENT 0x10 +#define BIT_SIGX_CURRENT_A_N 0x80 +#define BIT_SIGX_CURRENT_B_N 0x40 +#define BIT_SIGX_CURRENT_C_N 0x20 +#define BIT_SIGX_CURRENT_D_N 0x10 +#define BIT_SIGX_CURRENT_A_N16 0x08 +#define BIT_SIGX_CURRENT_B_N16 0x04 +#define BIT_SIGX_CURRENT_C_N16 0x02 +#define BIT_SIGX_CURRENT_D_N16 0x01 +#define BIT_SIGX_A 0x08 +#define BIT_SIGX_B 0x04 +#define BIT_SIGX_C 0x02 +#define BIT_SIGX_D 0x01 + +#define REG_SIGX_DELAYED_SIGDATA 0x20 +#define BIT_SIGX_DELAYED_SIGDATA_A 0x08 +#define BIT_SIGX_DELAYED_SIGDATA_B 0x04 +#define BIT_SIGX_DELAYED_SIGDATA_C 0x02 +#define BIT_SIGX_DELAYED_SIGDATA_D 0x01 + +#define REG_SIGX_CHANCFG 0x40 +#define BIT_SIGX_CHANCFG_RINV1 0x08 +#define BIT_SIGX_CHANCFG_RINV0 0x04 +#define BIT_SIGX_CHANCFG_RFIX 0x04 +#define BIT_SIGX_CHANCFG_RPOL 0x02 +#define BIT_SIGX_CHANCFG_RDEBE 0x01 + +#define REG_T1_XBAS_CFG 0x54 +#define BIT_T1_XBAS_ZCS0 0x01 +#define BIT_T1_XBAS_ZCS1 0x02 +#define BIT_T1_XBAS_JPN 0x40 +#define BIT_T1_XBAS_B8ZS 0x20 +#define BIT_T1_XBAS_ESF 0x10 + +#define REG_T1_XBAS_ALARM_TX 0x55 +#define BIT_T1_XBAS_ALARM_TX_XYEL 0x02 +#define BIT_T1_XBAS_ALARM_TX_XAIS 0x01 + +/* PMON Framing Bit Error Count */ +#define REG_PMON_BIT_ERROR 0x59 +#define BITS_PMON_BIT_ERROR 0x7F +/* PMON OOF/COFA/Far End Block Error Count LSB */ +#define REG_PMON_OOF_FEB_LSB_ERROR 0x5A +/* PMON OOF/COFA/Far End Block Error Count MSB */ +#define REG_PMON_OOF_FEB_MSB_ERROR 0x5B +#define BITS_PMON_OOF_FEB_MSB_ERROR 0x03 +/* PMON Bit Error/CRC Error Count LSB */ +#define REG_PMON_BIT_CRC_LSB_ERROR 0x5C +/* PMON Bit Error/CRC Error Count MSB */ +#define REG_PMON_BIT_CRC_MSB_ERROR 0x5D +#define BITS_PMON_BIT_CRC_MSB_ERROR 0x03 +/* PMON LCV Count LSB */ +#define REG_PMON_LCV_LSB_COUNT 0x5E +/* PMON LCV Count MSB */ +#define REG_PMON_LCV_MSB_COUNT 0x5F +#define BITS_PMON_LCV_MSB_COUNT 0x1F + +#define REG_T1_ALMI_CFG 0x60 +#define BIT_T1_ALMI_CFG_ESF 0x10 +#define BIT_T1_ALMI_CFG_FMS1 0x08 +#define BIT_T1_ALMI_CFG_FMS0 0x04 + +#define REG_T1_ALMI_DET_STATUS 0x63 +#define BIT_T1_ALMI_DET_STATUS_REDD 0x04 +#define BIT_T1_ALMI_DET_STATUS_YELD 0x02 +#define BIT_T1_ALMI_DET_STATUS_AISD 0x01 + +/* T1 XBOC Code */ +#define REG_T1_XBOC_CODE 0x67 +#define MASK_T1_XBOC_CODE 0x3F + +/* T1 RBOC Enable */ +#define REG_T1_RBOC_ENABLE 0x6A +#define BIT_T1_RBOC_ENABLE_IDLE 0x04 +#define BIT_T1_RBOC_ENABLE_AVC 0x02 +#define BIT_T1_RBOC_ENABLE_BOCE 0x01 + +/* T1 RBOC Code Status */ +#define REG_T1_RBOC_CODE_STATUS 0x6B +#define BIT_T1_RBOC_CODE_STATUS_IDLEI 0x80 +#define BIT_T1_RBOC_CODE_STATUS_BOCI 0x40 +#define MASK_T1_RBOC_CODE_STATUS 0x3F + +/* TPSC Indirect Register Access */ +#define REG_TPSC_CFG 0x6C +#define MASK_TPSC_CFG 0x03 +#define BIT_TPSC_IND 0x02 +#define BIT_TPSC_PCCE 0x01 +#define REG_TPSC_MICRO_ACCESS_STATUS 0x6D +#define BIT_TPSC_BUSY 0x80 +#define REG_TPSC_CHANNEL_INDIRECT_ADDRESS_CONTROL 0x6E +#define REG_TPSC_CHANNEL_INDIRECT_DATA_BUFFER 0x6F +#define REG_TPSC_DATA_CTRL_BYTE 0x20 +#define MASK_TPSC_DATA_CTRL_BYTE 0xFC +#define BIT_TPSC_DATA_CTRL_BYTE_INVERT 0x80 +#define BIT_TPSC_DATA_CTRL_BYTE_IDLE_DS0 0x40 +#define BIT_TPSC_DATA_CTRL_BYTE_SIGNINV 0x10 +#define BIT_TPSC_DATA_CTRL_BYTE_LOOP 0x04 +#define BIT_TPSC_DATA_CTRL_BYTE_ZCS0 0x02 +#define BIT_TPSC_DATA_CTRL_BYTE_ZCS1 0x01 +#define REG_TPSC_IDLE_CODE_BYTE 0x40 +#define REG_TPSC_SIGNALING_BYTE 0x60 +#define REG_TPSC_E1_CTRL_BYTE 0x60 +#define BIT_TPSC_E1_CTRL_BYTE_SUBS 0x80 +#define BIT_TPSC_E1_CTRL_BYTE_DS0 0x40 +#define BIT_TPSC_E1_CTRL_BYTE_DS1 0x20 +#define BIT_TPSC_E1_CTRL_BYTE_A 0x08 +#define BIT_TPSC_E1_CTRL_BYTE_B 0x04 +#define BIT_TPSC_E1_CTRL_BYTE_C 0x02 +#define BIT_TPSC_E1_CTRL_BYTE_D 0x01 +#define BIT_TPSC_SIGBYTE_SIGC_0 0x80 +#define BIT_TPSC_SIGBYTE_SIGC_1 0x40 +#define BIT_TPSC_SIGBYTE_DS1 0x20 +#define BIT_TPSC_SIGBYTE_SIGSRC 0x10 +#define BIT_TPSC_SIGBYTE_A 0x08 +#define BIT_TPSC_SIGBYTE_B 0x04 +#define BIT_TPSC_SIGBYTE_C 0x02 +#define BIT_TPSC_SIGBYTE_D 0x01 + +/* RPSC Indirect Register Access */ +#define REG_RPSC_CFG 0x70 +#define MASK_RPSC_CFG 0x03 +#define BIT_RPSC_IND 0x02 +#define BIT_RPSC_PCCE 0x01 +#define REG_RPSC_MICRO_ACCESS_STATUS 0x71 +#define BIT_RPSC_BUSY 0x80 +#define REG_RPSC_CHANNEL_INDIRECT_ADDRESS_CONTROL 0x72 +#define REG_RPSC_CHANNEL_INDIRECT_DATA_BUFFER 0x73 +#define REG_RPSC_DATA_CTRL_BYTE 0x20 +#define MASK_RPSC_DATA_CTRL_BYTE 0xFC +#define BIT_RPSC_DATA_CTRL_BYTE_DTRKC 0x40 +#define BIT_RPSC_DATA_CTRL_BYTE_SIGNINV 0x04 +#define REG_RPSC_DATA_COND_BYTE 0x40 +#define REG_RPSC_SIGBYTE 0x60 +#define BIT_RPSC_SIGBYTE_A 0x08 +#define BIT_RPSC_SIGBYTE_B 0x04 +#define BIT_RPSC_SIGBYTE_C 0x02 +#define BIT_RPSC_SIGBYTE_D 0x01 + +#define REG_E1_TRAN_CFG 0x80 +#define BIT_E1_TRAN_AMI 0x80 +#define BIT_E1_TRAN_SIGEN 0x40 +#define BIT_E1_TRAN_DLEN 0x20 +#define BIT_E1_TRAN_GENCRC 0x10 +#define BIT_E1_TRAN_FDIS 0x08 +#define BIT_E1_TRAN_FEBEDIS 0x04 +#define BIT_E1_TRAN_INDIS 0x02 +#define BIT_E1_TRAN_XDIS 0x01 + +#define REG_E1_TRAN_TX_ALARM_CTRL 0x81 +#define BIT_E1_TRAN_TX_ALARM_RAI 0x08 +#define BIT_E1_TRAN_TX_ALARM_YBIT 0x04 +#define BIT_E1_TRAN_TX_ALARM_AIS 0x01 + +#define REG_E1_TRAN_NATB_CODESEL 0x86 +#define BIT_E1_TRAN_NATB_CODESEL_SaSEL2 0x80 +#define BIT_E1_TRAN_NATB_CODESEL_SaSEL1 0x40 +#define BIT_E1_TRAN_NATB_CODESEL_SaSEL0 0x20 +#define BIT_E1_TRAN_NATB_CODESEL_Sa4 0x60 +#define BIT_E1_TRAN_NATB_CODESEL_Sa5 0x80 +#define BIT_E1_TRAN_NATB_CODESEL_Sa6 0xA0 +#define BIT_E1_TRAN_NATB_CODESEL_Sa7 0xC0 +#define BIT_E1_TRAN_NATB_CODESEL_Sa8 0xE0 + +#define REG_E1_TRAN_NATB_CODE 0x87 +#define BIT_E1_TRAN_NATB_CODE_SaXEN1 0x80 +#define BIT_E1_TRAN_NATB_CODE_SaXEN2 0x40 +#define BIT_E1_TRAN_NATB_CODE_SaXEN3 0x20 +#define BIT_E1_TRAN_NATB_CODE_SaXEN4 0x10 +#define BIT_E1_TRAN_NATB_CODE_SaX1 0x08 +#define BIT_E1_TRAN_NATB_CODE_SaX2 0x04 +#define BIT_E1_TRAN_NATB_CODE_SaX3 0x02 +#define BIT_E1_TRAN_NATB_CODE_SaX4 0x01 + +#define REG_E1_FRMR_CFG 0x90 +#define BIT_E1_FRMR_CRCEN 0x80 +#define BIT_E1_FRMR_CASDIS 0x40 +#define BIT_E1_FRMR_REFCRCEN 0x02 + +/* E1 FRMR Maintenance Mode Options */ +#define REG_E1_FRMR_MAINT_OPT 0x91 +#define BIT_E1_FRMR_MAINT_OPT_AISC 0x02 + +/* E1 FRMR framing status */ +#define REG_E1_FRMR_FR_STATUS 0x96 +#define BIT_E1_FRMR_FR_STATUS_C2NCIWV 0x80 +#define BIT_E1_FRMR_FR_STATUS_OOFV 0x40 +#define BIT_E1_FRMR_FR_STATUS_OOSMFV 0x20 +#define BIT_E1_FRMR_FR_STATUS_OOCMFV 0x10 +#define BIT_E1_FRMR_FR_STATUS_OOOFV 0x08 +#define BIT_E1_FRMR_FR_STATUS_RAICCRCV 0x04 +#define BIT_E1_FRMR_FR_STATUS_CFEBEV 0x02 +#define BIT_E1_FRMR_FR_STATUS_V52LINKV 0x01 + +/* E1 FRMR Maintenance/Alram Status */ +#define REG_E1_FRMR_MAINT_STATUS 0x97 +#define BIT_E1_FRMR_MAINT_STATUS_RAIV 0x80 +#define BIT_E1_FRMR_MAINT_STATUS_RED 0x08 +#define BIT_E1_FRMR_MAINT_STATUS_AIS 0x04 + + /* TDPR Configuration */ +#define REG_TDPR_CFG 0xA8 +#define BIT_TDPR_CFG_EN 0x01 + +/* TDPR Transmit Data */ +#define REG_TDPR_TX_DATA 0xAD + +/* Comet-QUAD Master Interrupt Source */ +#define REG_COMET_QUAD_MASTER_INTR 0xBC +#define BITS_COMET_QUAD_MASTER_INTR 0x0F + +/* RDLC Configuration */ +#define REG_RDLC_CFG 0xC0 +#define BIT_RDLC_CFG_EN 0x01 + +/* RDLC Interrupt Control */ +#define REG_RDLC_INT_CTRL 0xC1 +#define BIT_RDLC_INT_CTRL_INTE 0x80 + +/* RDLC Status */ +#define REG_RDLC_STATUS 0xC2 +#define BIT_RDLC_STATUS_PKIN 0x10 +#define BIT_RDLC_STATUS_INTR 0x01 + +/* RDLC Data */ +#define REG_RDLC_DATA 0xC3 + +#define REG_CSU_CFG 0xD6 +#define MASK_CSU_CFG 0xC7 +#define BIT_CSU_MODE2 0x04 +#define BIT_CSU_MODE1 0x02 +#define BIT_CSU_MODE0 0x01 + +/* RLPS Equalization Indirect Data (MSB) */ +#define REG_RLPS_IND_DATA_1 0xD8 +/* RLPS Equalization Indirect Data */ +#define REG_RLPS_IND_DATA_2 0xD9 +/* RLPS Equalization Indirect Data */ +#define REG_RLPS_IND_DATA_3 0xDA +/* RLPS Equalization Indirect Data (LSB) */ +#define REG_RLPS_IND_DATA_4 0xDB + +#define REG_EQ_VREF 0xDC + +#define REG_RLPS_FUSE_CTRL_STAT 0xDD + +#define REG_PRGD_INT_STATUS_EN 0xE1 +#define BIT_PRGD_INT_STATUS_EN_SYNCE 0x80 +#define BIT_PRGD_INT_STATUS_EN_BEE 0x40 +#define BIT_PRGD_INT_STATUS_EN_XFERE 0x20 +#define BIT_PRGD_INT_STATUS_EN_SYNCV 0x10 +#define BIT_PRGD_INT_STATUS_EN_SYNCI 0x08 +#define BIT_PRGD_INT_STATUS_EN_BEI 0x04 +#define BIT_PRGD_INT_STATUS_EN_XFERI 0x02 +#define BIT_PRGD_INT_STATUS_EN_OVR 0x01 + +#define REG_XLPG_LINE_CFG 0xF0 +#define BIT_XLPG_LINE_CFG_HIGHZ 0x80 + +#define REG_XLPG_WAVEFORM_ADDR 0xF2 + +#define REG_XLPG_WAVEFORM_DATA 0xF3 + +#define REG_XLPG_TNC 0xF4 +#define BIT_XLPG_TNC_7 0x80 +#define BIT_XLPG_TNC_6 0x40 +#define BIT_XLPG_TNC_5 0x20 +#define BIT_XLPG_TNC_4 0x10 +#define BIT_XLPG_TNC_3 0x08 +#define BIT_XLPG_TNC_2 0x04 +#define BIT_XLPG_TNC_1 0x02 + +#define REG_XLPG_TPC 0xF5 +#define BIT_XLPG_TPC_7 0x80 +#define BIT_XLPG_TPC_6 0x40 +#define BIT_XLPG_TPC_5 0x20 +#define BIT_XLPG_TPC_4 0x10 +#define BIT_XLPG_TPC_3 0x08 +#define BIT_XLPG_TPC_2 0x04 +#define BIT_XLPG_TPC_1 0x02 + +#define REG_XLPG_INIT 0xF6 + +#define REG_RLPS_CFG_STATUS 0xF8 +#define BIT_RLPS_CFG_STATUS_ALOSI 0x80 +#define BIT_RLPS_CFG_STATUS_ALOSV 0x40 +#define BIT_RLPS_CFG_STATUS_ALOSE 0x20 +#define BIT_RLPS_CFG_STATUS_SQUELCHE 0x10 +#define BIT_RLPS_CFG_STATUS_LONGE 0x01 + +#define REG_RLPS_ALOS_DET_CLR_THR 0xF9 +#define BIT_RLPS_ALOS_CLR_THR_2 0x40 +#define BIT_RLPS_ALOS_CLR_THR_1 0x20 +#define BIT_RLPS_ALOS_CLR_THR_0 0x10 +#define BIT_RLPS_ALOS_DET_THR_2 0x04 +#define BIT_RLPS_ALOS_DET_THR_1 0x02 +#define BIT_RLPS_ALOS_DET_THR_0 0x01 + +#define REG_RLPS_ALOS_DET_PER 0xFA +#define BIT_RLPS_ALOS_DET_PER_7 0x80 +#define BIT_RLPS_ALOS_DET_PER_6 0x40 +#define BIT_RLPS_ALOS_DET_PER_5 0x20 +#define BIT_RLPS_ALOS_DET_PER_4 0x10 +#define BIT_RLPS_ALOS_DET_PER_3 0x08 +#define BIT_RLPS_ALOS_DET_PER_2 0x04 +#define BIT_RLPS_ALOS_DET_PER_1 0x02 +#define BIT_RLPS_ALOS_DET_PER_0 0x01 + +#define REG_RLPS_ALOS_CLR_PER 0xFB +#define BIT_RLPS_ALOS_CLR_PER_7 0x80 +#define BIT_RLPS_ALOS_CLR_PER_6 0x40 +#define BIT_RLPS_ALOS_CLR_PER_5 0x20 +#define BIT_RLPS_ALOS_CLR_PER_4 0x10 +#define BIT_RLPS_ALOS_CLR_PER_3 0x08 +#define BIT_RLPS_ALOS_CLR_PER_2 0x04 +#define BIT_RLPS_ALOS_CLR_PER_1 0x02 +#define BIT_RLPS_ALOS_CLR_PER_0 0x01 + +/* RLPS Equalization Indirect Address */ +#define REG_RLPS_EQ_ADDR 0xFC + +/* RLPS Equalization Read/Write Select */ +#define REG_RLPS_EQ_RWB 0xFD +#define BIT_RLPS_EQ_RWB 0x80 + +#define REG_RLPS_EQ_STATUS 0xFE + +#define REG_RLPS_EQ_CFG 0xFF +#define MASK_RLPS_EQ_CFG 0xC7 +#define BIT_RLPS_EQ_RESERVED 0x08 /* PMC4351 */ +#define BIT_RLPS_EQ_FREQ_2 0x02 /* PMC4351 */ +#define BIT_RLPS_EQ_FREQ_1 0x02 /* PMC4351 */ +#define BIT_RLPS_EQ_FREQ_0 0x01 /* PMC4351 */ +#define BIT_RLPS_EQ_EQEN 0x08 /* PMC4354 */ +#define BIT_RLPS_EQ_RESERVED_3 0x04 /* PMC4354 */ +#define BIT_RLPS_EQ_RESERVED_1 0x03 /* PMC4354 */ +#define BIT_RLPS_EQ_RESERVED_0 0x01 /* PMC4354 */ + +/********************************************/ +/************ Interrupt Register ************/ +/********************************************/ +#define REG_INT_SRC_1 0x07 +#define BITS_TX_INT_SRC_1 0x0C +#define BITS_RX_INT_SRC_1 0xF3 +#define BIT_INT_SRC_1_PMON 0x80 +#define BIT_INT_SRC_1_PRGD 0x40 +#define BIT_INT_SRC_1_FRMR 0x20 +#define BIT_INT_SRC_1_SIGX 0x10 +#define BIT_INT_SRC_1_APRM 0x08 +#define BIT_INT_SRC_1_TJAT 0x04 +#define BIT_INT_SRC_1_RJAT 0x02 +#define BIT_INT_SRC_1_CDRC 0x01 + +#define REG_INT_SRC_2 0x08 +#define BITS_TX_INT_SRC_2 0x0F +#define BITS_RX_INT_SRC_2 0xF0 +#define BIT_INT_SRC_2_RX_ELST 0x80 +#define BIT_INT_SRC_2_RDLC_3 0x40 +#define BIT_INT_SRC_2_RDLC_2 0x20 +#define BIT_INT_SRC_2_RDLC_1 0x10 +#define BIT_INT_SRC_2_TX_ELST 0x08 +#define BIT_INT_SRC_2_TDPR_3 0x04 +#define BIT_INT_SRC_2_TDPR_2 0x02 +#define BIT_INT_SRC_2_TDPR_1 0x01 + +#define REG_INT_SRC_3 0x09 +#define BITS_TX_INT_SRC_3 0x15 +#define BITS_RX_INT_SRC_3 0xEA +#define BIT_INT_SRC_3_IBCD 0x80 +#define BIT_INT_SRC_3_PDVD 0x40 +#define BIT_INT_SRC_3_RBOC 0x20 +#define BIT_INT_SRC_3_XPDE 0x10 +#define BIT_INT_SRC_3_ALMI 0x08 +#define BIT_INT_SRC_3_TRAN 0x04 +#define BIT_INT_SRC_3_RLPS 0x02 +#define BIT_INT_SRC_3_BTIF 0x01 + +#define REG_CDRC_INT_EN 0x11 +#define BIT_CDRC_INT_EN_LCVE 0x80 +#define BIT_CDRC_INT_EN_LOSE 0x40 +#define BIT_CDRC_INT_EN_LCSDE 0x20 +#define BIT_CDRC_INT_EN_ZNDE 0x10 + +#define REG_CDRC_INT_STATUS 0x12 +#define BIT_CDRC_INT_STATUS_LCVI 0x80 +#define BIT_CDRC_INT_STATUS_LOSI 0x40 +#define BIT_CDRC_INT_STATUS_LCSDI 0x20 +#define BIT_CDRC_INT_STATUS_ZNDI 0x10 +#define BIT_CDRC_INT_STATUS_LOSV 0x01 + +#define REG_RJAT_INT_STATUS 0x14 +#define BIT_RJAT_INT_STATUS_OVRI 0x02 +#define BIT_RJAT_INT_STATUS_UNDI 0x01 + +#define REG_TJAT_INT_STATUS 0x18 +#define BIT_TJAT_INT_STATUS_OVRI 0x02 +#define BIT_TJAT_INT_STATUS_UNDI 0x01 + +#define REG_RX_ELST_INT_EN_STATUS 0x1D +#define BIT_RX_ELST_INT_EN_STATUS_SLIPE 0x04 +#define BIT_RX_ELST_INT_EN_STATUS_SLIPD 0x02 +#define BIT_RX_ELST_INT_EN_STATUS_SLIPI 0x01 + +#define REG_TX_ELST_INT_EN_STATUS 0x21 +#define BIT_TX_ELST_INT_EN_STATUS_SLIPE 0x04 +#define BIT_TX_ELST_INT_EN_STATUS_SLIPD 0x02 +#define BIT_TX_ELST_INT_EN_STATUS_SLIPI 0x01 + +#define REG_T1_FRMR_INT_EN 0x49 +#define BIT_T1_FRMR_INT_EN_COFAE 0x20 +#define BIT_T1_FRMR_INT_EN_FERE 0x10 +#define BIT_T1_FRMR_INT_EN_BEEE 0x08 +#define BIT_T1_FRMR_INT_EN_SFEE 0x04 +#define BIT_T1_FRMR_INT_EN_MFPE 0x02 +#define BIT_T1_FRMR_INT_EN_INFRE 0x01 + +#define REG_T1_FRMR_INT_STATUS 0x4A +#define BIT_T1_FRMR_INT_STATUS_COFAI 0x80 +#define BIT_T1_FRMR_INT_STATUS_FERI 0x40 +#define BIT_T1_FRMR_INT_STATUS_BEEI 0x20 +#define BIT_T1_FRMR_INT_STATUS_SFEI 0x10 +#define BIT_T1_FRMR_INT_STATUS_MFPI 0x08 +#define BIT_T1_FRMR_INT_STATUS_INFRI 0x04 +#define BIT_T1_FRMR_INT_STATUS_MFP 0x02 +#define BIT_T1_FRMR_INT_STATUS_INFR 0x01 + +#define REG_IBCD_CFG 0x4C +#define BIT_IBCD_CFG_DSEL1 0x08 +#define BIT_IBCD_CFG_DSEL0 0x04 +#define BIT_IBCD_CFG_ASEL1 0x02 +#define BIT_IBCD_CFG_ASEL0 0x01 + +#define REG_IBCD_INT_EN_STATUS 0x4D +#define BIT_IBCD_INT_EN_STATUS_LBACP 0x80 +#define BIT_IBCD_INT_EN_STATUS_LBDCP 0x40 +#define BIT_IBCD_INT_EN_STATUS_LBAE 0x20 +#define BIT_IBCD_INT_EN_STATUS_LBDE 0x10 +#define BIT_IBCD_INT_EN_STATUS_LBAI 0x08 +#define BIT_IBCD_INT_EN_STATUS_LBDI 0x04 +#define BIT_IBCD_INT_EN_STATUS_LBA 0x02 +#define BIT_IBCD_INT_EN_STATUS_LBD 0x01 + +#define REG_IBCD_ACTIVATE_CODE 0x4E +#define BIT_IBCD_ACTIVATE_CODE_ACT7 0x80 +#define BIT_IBCD_ACTIVATE_CODE_ACT6 0x40 +#define BIT_IBCD_ACTIVATE_CODE_ACT5 0x20 +#define BIT_IBCD_ACTIVATE_CODE_ACT4 0x10 +#define BIT_IBCD_ACTIVATE_CODE_ACT3 0x08 +#define BIT_IBCD_ACTIVATE_CODE_ACT2 0x04 +#define BIT_IBCD_ACTIVATE_CODE_ACT1 0x02 +#define BIT_IBCD_ACTIVATE_CODE_ACT0 0x01 + +#define REG_IBCD_DEACTIVATE_CODE 0x4F +#define BIT_IBCD_DEACTIVATE_CODE_DACT7 0x80 +#define BIT_IBCD_DEACTIVATE_CODE_DACT6 0x40 +#define BIT_IBCD_DEACTIVATE_CODE_DACT5 0x20 +#define BIT_IBCD_DEACTIVATE_CODE_DACT4 0x10 +#define BIT_IBCD_DEACTIVATE_CODE_DACT3 0x08 +#define BIT_IBCD_DEACTIVATE_CODE_DACT2 0x04 +#define BIT_IBCD_DEACTIVATE_CODE_DACT1 0x02 +#define BIT_IBCD_DEACTIVATE_CODE_DACT0 0x01 + +#define REG_PMON_INT_EN_STATUS 0x58 +#define BIT_PMON_INT_EN_STATUS_INTE 0x04 +#define BIT_PMON_INT_EN_STATUS_XFER 0x02 +#define BIT_PMON_INT_EN_STATUS_OVR 0x01 + +#define REG_T1_ALMI_INT_EN 0x61 +#define BIT_T1_ALMI_INT_EN_FASTD 0x10 +#define BIT_T1_ALMI_INT_EN_ACCEL 0x08 +#define BIT_T1_ALMI_INT_EN_YELE 0x04 +#define BIT_T1_ALMI_INT_EN_REDE 0x02 +#define BIT_T1_ALMI_INT_EN_AISE 0x01 + +#define REG_T1_ALMI_INT_STATUS 0x62 +#define BIT_T1_ALMI_INT_STATUS_YELI 0x20 +#define BIT_T1_ALMI_INT_STATUS_REDI 0x10 +#define BIT_T1_ALMI_INT_STATUS_AISI 0x08 +#define BIT_T1_ALMI_INT_STATUS_YEL 0x04 +#define BIT_T1_ALMI_INT_STATUS_RED 0x02 +#define BIT_T1_ALMI_INT_STATUS_AIS 0x01 + +#define REG_PDVD_INT_EN_STATUS 0x65 +#define BIT_PDVD_INT_EN_STATUS_PDV 0x10 +#define BIT_PDVD_INT_EN_STATUS_Z16DI 0x08 +#define BIT_PDVD_INT_EN_STATUS_PDVI 0x04 +#define BIT_PDVD_INT_EN_STATUS_Z16DE 0x02 +#define BIT_PDVD_INT_EN_STATUS_PDVE 0x01 + +#define REG_XPDE_INT_EN_STATUS 0x69 +#define BIT_XPDE_INT_EN_STATUS_STUFE 0x80 +#define BIT_XPDE_INT_EN_STATUS_STUFF 0x40 +#define BIT_XPDE_INT_EN_STATUS_STUFI 0x20 +#define BIT_XPDE_INT_EN_STATUS_PDV 0x10 +#define BIT_XPDE_INT_EN_STATUS_Z16DI 0x08 +#define BIT_XPDE_INT_EN_STATUS_PDVI 0x04 +#define BIT_XPDE_INT_EN_STATUS_Z16DE 0x02 +#define BIT_XPDE_INT_EN_STATUS_PDVE 0x01 + +#define REG_T1_APRM_INT_STATUS 0x7A +#define BIT_T1_APRM_INT_STATUS_INTR 0x01 + +#define REG_E1_TRAN_INT_EN 0x84 +#define BIT_E1_TRAN_INT_EN_SIGMFE 0x10 +#define BIT_E1_TRAN_INT_EN_NFASE 0x08 +#define BIT_E1_TRAN_INT_EN_MFE 0x04 +#define BIT_E1_TRAN_INT_EN_SMFE 0x02 +#define BIT_E1_TRAN_INT_EN_FRME 0x01 + +#define REG_E1_TRAN_INT_STATUS 0x85 +#define BIT_E1_TRAN_INT_STATUS_SIGMFI 0x10 +#define BIT_E1_TRAN_INT_STATUS_NFASI 0x08 +#define BIT_E1_TRAN_INT_STATUS_MFI 0x04 +#define BIT_E1_TRAN_INT_STATUS_SMFI 0x02 +#define BIT_E1_TRAN_INT_STATUS_FRMI 0x01 + +#define REG_E1_FRMR_FRM_STAT_INT_EN 0x92 +#define BIT_E1_FRMR_FRM_STAT_INT_EN_C2NCIWE 0x80 +#define BIT_E1_FRMR_FRM_STAT_INT_EN_OOFE 0x40 +#define BIT_E1_FRMR_FRM_STAT_INT_EN_OOSMFE 0x20 +#define BIT_E1_FRMR_FRM_STAT_INT_EN_OOCMFE 0x10 +#define BIT_E1_FRMR_FRM_STAT_INT_EN_COFAE 0x08 +#define BIT_E1_FRMR_FRM_STAT_INT_EN_FERE 0x04 +#define BIT_E1_FRMR_FRM_STAT_INT_EN_SMFERE 0x02 +#define BIT_E1_FRMR_FRM_STAT_INT_EN_CMFERE 0x01 + +#define REG_E1_FRMR_M_A_INT_EN 0x93 +#define BIT_E1_FRMR_M_A_INT_EN_RAIE 0x80 +#define BIT_E1_FRMR_M_A_INT_EN_RMAIE 0x40 +#define BIT_E1_FRMR_M_A_INT_EN_AISDE 0x20 +#define BIT_E1_FRMR_M_A_INT_EN_REDE 0x08 +#define BIT_E1_FRMR_M_A_INT_EN_AISE 0x04 +#define BIT_E1_FRMR_M_A_INT_EN_FEBEE 0x02 +#define BIT_E1_FRMR_M_A_INT_EN_CRCEE 0x01 + +/* E1 FRMR Framing status Interrupt Indication */ +#define REG_E1_FRMR_FRM_STAT_INT_IND 0x94 +#define BIT_E1_FRMR_FRM_STAT_INT_IND_C2NCIWI 0x80 +#define BIT_E1_FRMR_FRM_STAT_INT_IND_OOFI 0x40 +#define BIT_E1_FRMR_FRM_STAT_INT_IND_OOSMFI 0x20 +#define BIT_E1_FRMR_FRM_STAT_INT_IND_OOCMFI 0x10 +#define BIT_E1_FRMR_FRM_STAT_INT_IND_COFAI 0x08 +#define BIT_E1_FRMR_FRM_STAT_INT_IND_FERI 0x04 +#define BIT_E1_FRMR_FRM_STAT_INT_IND_SMFERI 0x02 +#define BIT_E1_FRMR_FRM_STAT_INT_IND_CMFERI 0x01 + +#define REG_E1_FRMR_M_A_INT_IND 0x95 +#define BIT_E1_FRMR_M_A_INT_IND_RAII 0x80 +#define BIT_E1_FRMR_M_A_INT_IND_FMAII 0x40 +#define BIT_E1_FRMR_M_A_INT_IND_AISDI 0x20 +#define BIT_E1_FRMR_M_A_INT_IND_REDI 0x08 +#define BIT_E1_FRMR_M_A_INT_IND_AISI 0x04 +#define BIT_E1_FRMR_M_A_INT_IND_FEBEI 0x02 +#define BIT_E1_FRMR_M_A_INT_IND_CRCEI 0x01 + +#define REG_E1_FRMR_P_A_INT_EN 0x9E +#define BIT_E1_FRMR_P_A_INT_EN_OOOFE 0x80 +#define BIT_E1_FRMR_P_A_INT_EN_RAICCRCE 0x40 +#define BIT_E1_FRMR_P_A_INT_EN_CFEBEE 0x20 +#define BIT_E1_FRMR_P_A_INT_EN_V52LINKE 0x10 +#define BIT_E1_FRMR_P_A_INT_EN_IFPE 0x08 +#define BIT_E1_FRMR_P_A_INT_EN_ICSMFPE 0x04 +#define BIT_E1_FRMR_P_A_INT_EN_ICMFPE 0x02 +#define BIT_E1_FRMR_P_A_INT_EN_ISMFPE 0x01 + +#define REG_E1_FRMR_P_A_INT_STAT 0x9F +#define BIT_E1_FRMR_P_A_INT_STAT_OOOFI 0x80 +#define BIT_E1_FRMR_P_A_INT_STAT_RAICCRCI 0x40 +#define BIT_E1_FRMR_P_A_INT_STAT_CFEBEI 0x20 +#define BIT_E1_FRMR_P_A_INT_STAT_V52LINKI 0x10 +#define BIT_E1_FRMR_P_A_INT_STAT_IFPI 0x08 +#define BIT_E1_FRMR_P_A_INT_STAT_ICSMFPI 0x04 +#define BIT_E1_FRMR_P_A_INT_STAT_ICMFPI 0x02 +#define BIT_E1_FRMR_P_A_INT_STAT_ISMFPI 0x01 + + +#endif /* __SDLA_TE1_PMC_H */ diff -Nur linux.org/include/linux/sdla_te3.h linux-2.6.17/include/linux/sdla_te3.h --- linux.org/include/linux/sdla_te3.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/sdla_te3.h 2006-08-30 10:07:15.000000000 +0000 @@ -0,0 +1,101 @@ +/****************************************************************************** + * + * sdla_te3.h Sangoma T3/E3 front end definitions. + * + * Alex Feldman + * + * Copyright Sangoma Technologies Inc. 1999, 2000, 2001, 2002, 2003, 2004 + * + * This program is provided subject to the Software License included in + * this package in the file license.txt. By using this program you agree + * to be bound bythe terms of this license. + * + * Should you not have a copy of the file license.txt, or wish to obtain + * a hard copy of the Software License, please contact Sangoma + * technologies Corporation. + * + * Contact: Sangoma Technologies Inc. 905-474-1990, info@sangoma.com + * + *****************************************************************************/ + +#ifndef __SDLA_TE3_H +# define __SDLA_TE3_H + +#define WAN_TE3_LIU_LB_NORMAL 0x00 +#define WAN_TE3_LIU_LB_ANALOG 0x01 +#define WAN_TE3_LIU_LB_REMOTE 0x02 +#define WAN_TE3_LIU_LB_DIGITAL 0x03 + +#define WAN_TE3_RDEVICE_NONE 0x00 +#define WAN_TE3_RDEVICE_ADTRAN 0x01 +#define WAN_TE3_RDEVICE_DIGITALLINK 0x02 +#define WAN_TE3_RDEVICE_KENTROX 0x03 +#define WAN_TE3_RDEVICE_LARSCOM 0x04 +#define WAN_TE3_RDEVICE_VERILINK 0x05 + +#define WAN_TE3_BIT_LOS_ALARM 0x0001 +#define WAN_TE3_BIT_OOF_ALARM 0x0002 +#define WAN_TE3_BIT_AIS_ALARM 0x0004 +#define WAN_TE3_BIT_AIC_ALARM 0x0008 +#define WAN_TE3_BIT_YEL_ALARM 0x0010 +#define WAN_TE3_BIT_LOF_ALARM 0x0020 + +#define RDEVICE_DECODE(rdevice) \ + (rdevice == WAN_TE3_RDEVICE_NONE) ? "None" : \ + (rdevice == WAN_TE3_RDEVICE_ADTRAN) ? "ADTRAN" : \ + (rdevice == WAN_TE3_RDEVICE_DIGITALLINK) ? "DIGITALLINK" : \ + (rdevice == WAN_TE3_RDEVICE_KENTROX) ? "KENTROX" : \ + (rdevice == WAN_TE3_RDEVICE_LARSCOM) ? "LARSCOM" : \ + (rdevice == WAN_TE3_RDEVICE_VERILINK) ? "VERLINK" : \ + "Unknown" + +typedef struct { + int rx_equal; /* receive equalization enable (TRUE/FALSE) */ + int taos; /* transmit all ones select (TRUE/FALSE) */ + int lb_mode; /* loopback modes */ + int tx_lbo; /* transmit line build-out (TRUE/FALSE) */ +} sdla_te3_liu_cfg_t; + +typedef struct { + sdla_te3_liu_cfg_t liu_cfg; + int fractional; + int rdevice_type; + int fcs; + int clock; + unsigned char lcode; +} sdla_te3_cfg_t; + +typedef struct { + unsigned long pmon_lcv; + unsigned long pmon_framing; + unsigned long pmon_parity; + unsigned long pmon_febe; + unsigned long pmon_cpbit; +} sdla_te3_pmon_t; + +#define IS_DS3(cfg) ((cfg)->media == WAN_MEDIA_DS3) +#define IS_E3(cfg) ((cfg)->media == WAN_MEDIA_E3) +#define IS_TE3(cfg) ( \ + (cfg)->media == WAN_MEDIA_DS3 || \ + (cfg)->media == WAN_MEDIA_E3) + + +#define WAN_TE3_ALARM(alarm, bit) ((alarm) & (bit)) ? "ON" : "OFF" + +#define WAN_TE3_LOS_ALARM(alarm) WAN_TE3_ALARM(alarm, WAN_TE3_BIT_LOS_ALARM) +#define WAN_TE3_OOF_ALARM(alarm) WAN_TE3_ALARM(alarm, WAN_TE3_BIT_OOF_ALARM) +#define WAN_TE3_AIS_ALARM(alarm) WAN_TE3_ALARM(alarm, WAN_TE3_BIT_AIS_ALARM) +#define WAN_TE3_AIC_ALARM(alarm) WAN_TE3_ALARM(alarm, WAN_TE3_BIT_AIC_ALARM) +#define WAN_TE3_YEL_ALARM(alarm) WAN_TE3_ALARM(alarm, WAN_TE3_BIT_YEL_ALARM) +#define WAN_TE3_LOF_ALARM(alarm) WAN_TE3_ALARM(alarm, WAN_TE3_BIT_LOF_ALARM) + +#if defined(WAN_KERNEL) + +typedef struct { + int dummy; +} sdla_te3_param_t; + +int sdla_te3_iface_init(void *p_fe_iface); +#endif /* WAN_KERNEL */ + +#endif /* __SDLA_TE3_H */ diff -Nur linux.org/include/linux/sdla_te3_reg.h linux-2.6.17/include/linux/sdla_te3_reg.h --- linux.org/include/linux/sdla_te3_reg.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/sdla_te3_reg.h 2006-08-30 10:07:15.000000000 +0000 @@ -0,0 +1,379 @@ +/****************************************************************************** + * + * sdla_te3_reg.h Sangoma T3/E3 registry definitions. + * + * Alex Feldman + * + * Copyright Sangoma Technologies Inc. 1999, 2000,2001, 2002, 2003, 2004 + * + * This program is provided subject to the Software License included in + * this package in the file license.txt. By using this program you agree + * to be bound bythe terms of this license. + * + * Should you not have a copy of the file license.txt, or wish to obtain + * a hard copy of the Software License, please contact Sangoma + * technologies Corporation. + * + * Contact: Sangoma Technologies Inc. 905-474-1990, info@sangoma.com + * + *****************************************************************************/ + +#ifndef __SDLA_TE3_REG_H +# define __SDLA_TE3_REG_H + + +/* T3/E3 Line Interface Unit registers */ +#define REG_APS 0x00 + +#define REG_INTR_ENABLE 0x01 +#define BIT_INTR_ENABLE_CNT_SATIE 0x20 +#define BIT_INTR_ENABLE_PRBSIE 0x10 +#define BIT_INTR_ENABLE_FLIE 0x08 +#define BIT_INTR_ENABLE_RLOLIE 0x04 +#define BIT_INTR_ENABLE_RLOSIE 0x02 +#define BIT_INTR_ENABLE_DMOIE 0x01 + +#define REG_INTR_STATUS 0x02 +#define BIT_INTR_ENABLE_CNT_SATIS 0x20 +#define BIT_INTR_ENABLE_PRBSIS 0x10 +#define BIT_INTR_ENABLE_FLIS 0x08 +#define BIT_INTR_ENABLE_RLOLIS 0x04 +#define BIT_INTR_ENABLE_RLOSIS 0x02 +#define BIT_INTR_ENABLE_DMOIS 0x01 + +#define REG_ALARM_STATUS 0x03 +#define BIT_ALARM_STATUS_PRBSLS 0x40 +#define BIT_ALARM_STATUS_DLOS 0x20 +#define BIT_ALARM_STATUS_ALOS 0x10 +#define BIT_ALARM_STATUS_FL 0x08 +#define BIT_ALARM_STATUS_RLOL 0x04 +#define BIT_ALARM_STATUS_RLOS 0x02 +#define BIT_ALARM_STATUS_DMO 0x01 + +#define REG_TRANSMIT_CTRL 0x04 +#define BIT_TRANSMIT_CTRL_TxMON 0x20 +#define BIT_TRANSMIT_CTRL_INSPRBS 0x10 +#define BIT_TRANSMIT_CTRL_TAOS 0x04 +#define BIT_TRANSMIT_CTRL_TxClkINV 0x02 +#define BIT_TRANSMIT_CTRL_TxLEV 0x01 + +#define REG_RECEIVE_CTRL 0x05 +#define BIT_RECEIVE_CTRL_DLOSDIS 0x20 +#define BIT_RECEIVE_CTRL_ALOSDIS 0x10 +#define BIT_RECEIVE_CTRL_RxClkINV 0x08 +#define BIT_RECEIVE_CTRL_LOSMUT 0x04 +#define BIT_RECEIVE_CTRL_RxMIN 0x02 +#define BIT_RECEIVE_CTRL_REQEN 0x01 + +#define REG_BLOCK_CTRL 0x06 +#define BIT_BLOCK_CTRL_PRBSEN 0x20 +#define BIT_BLOCK_CTRL_RLB 0x10 +#define BIT_BLOCK_CTRL_LLB 0x08 +#define BIT_BLOCK_CTRL_E3 0x04 +#define BIT_BLOCK_CTRL_STS1 0x02 +#define BIT_BLOCK_CTRL_SR 0x01 + +#define REG_JITTER_ATTENUATOR 0x07 +#define BIT_JITTER_ATTENUATOR_PNTRST 0x08 +#define BIT_JITTER_ATTENUATOR_JA1 0x04 +#define BIT_JITTER_ATTENUATOR_JAT 0x02 +#define BIT_JITTER_ATTENUATOR_JA0 0x01 + +#define REG_GLOBAL_INTR_ENABLE 0x20 +#define BIT_GLOBAL_INTR_ENABLE_INTEN 0x01 + +#define REG_GLOBAL_INTR_STATUS 0x21 +#define BIT_GLOBAL_INTR_STATUS_INTST 0x01 + +#define REG_PRBS_ERROR_CNT_MSB 0x30 +#define BIT_PRBS_ERROR_CNT_MSB_MSB 0x80 +#define BIT_PRBS_ERROR_CNT_MSB_LSB 0x01 + +#define REG_PRBS_ERROR_CNT_LSB 0x31 +#define BIT_PRBS_ERROR_CNT_LSB_MSB 0x80 +#define BIT_PRBS_ERROR_CNT_LSB_LSB 0x01 + +#define REG_PRBS_HOLDING 0x38 +#define BIT_PRBS_HOLDING_MSB 0x80 +#define BIT_PRBS_HOLDING_LSB 0x01 + +#define REG_CHIP_ID 0x3E +#define REG_CHIP_VERSION 0x3F + +/* T3/E3 Framer registers */ +#define REG_OPMODE 0x00 +#define BIT_OPMODE_LOCAL_LB 0x80 +#define BIT_OPMODE_DS3 0x40 +#define BIT_OPMODE_INTERNAL_LOS 0x20 +#define BIT_OPMODE_RESET 0x10 +#define BIT_OPMODE_INT_ENABLE_RESET 0x08 +#define BIT_OPMODE_FRAME_FRMT 0x04 +#define BIT_OPMODE_TIMREFSEL1 0x02 +#define BIT_OPMODE_TIMREFSEL0 0x01 + +#define REG_IO_CONTROL 0x01 +#define BIT_IO_CONTROL_DISABLE_TXLOC 0x80 +#define BIT_IO_CONTROL_LOC_STATUS 0x40 +#define BIT_IO_CONTROL_DISABLE_RXLOC 0x20 +#define BIT_IO_CONTROL_AMI 0x10 +#define BIT_IO_CONTROL_UNIPOLAR 0x08 +#define BIT_IO_CONTROL_TxLINECLK 0x04 +#define BIT_IO_CONTROL_RxLINECLK 0x02 +#define BIT_IO_CONTROL_REFRAME 0x01 + +#define REG_PART_NUMBER 0x02 + +#define REG_VERSION_NUMBER 0x03 + +#define REG_BLOCK_INT_ENABLE 0x04 +#define BIT_BLOCK_INT_ENABLE_RxDS3_E3 0x80 +#define BIT_BLOCK_INT_ENABLE_TxDS3_E3 0x02 +#define BIT_BLOCK_INT_ENABLE_1SEC_INT 0x01 + +#define REG_BLOCK_INT_STATUS 0x05 +#define BIT_BLOCK_INT_STATUS_RxDS3_E3 0x80 +#define BIT_BLOCK_INT_STATUS_TxDS3_E3 0x02 +#define BIT_BLOCK_INT_STATUS_1SEC_INT 0x01 + +/* Receive DS3 */ +#define REG_RxDS3_CFG_STATUS 0x10 +#define BIT_RxDS3_CFG_STATUS_RxAIS 0x80 +#define BIT_RxDS3_CFG_STATUS_RxLOS 0x40 +#define BIT_RxDS3_CFG_STATUS_RxIDLE 0x20 +#define BIT_RxDS3_CFG_STATUS_RxOOF 0x10 +#define BIT_RxDS3_CFG_STATUS_FRAMING 0x04 +#define BIT_RxDS3_CFG_STATUS_FSYNC_ALGO 0x02 +#define BIT_RxDS3_CFG_STATUS_MSYNC_ALGO 0x01 + +#define REG_RxDS3_STATUS 0x11 +#define BIT_RxDS3_STATUS_RxFERF 0x10 +#define BIT_RxDS3_STATUS_RxAIC 0x08 +#define BIT_RxDS3_STATUS_RxFEBE2 0x04 +#define BIT_RxDS3_STATUS_RxFEBE1 0x02 +#define BIT_RxDS3_STATUS_RxFEBE0 0x01 + +#define REG_RxDS3_INT_ENABLE 0x12 +#define BIT_RxDS3_INT_ENABLE_CPBIT_ERR 0x80 +#define BIT_RxDS3_INT_ENABLE_LOS 0x40 +#define BIT_RxDS3_INT_ENABLE_AIS 0x20 +#define BIT_RxDS3_INT_ENABLE_IDLE 0x10 +#define BIT_RxDS3_INT_ENABLE_FERF 0x08 +#define BIT_RxDS3_INT_ENABLE_AIC 0x04 +#define BIT_RxDS3_INT_ENABLE_OOF 0x02 +#define BIT_RxDS3_INT_ENABLE_PBIT_ERR 0x01 + +#define REG_RxDS3_INT_STATUS 0x13 +#define BIT_RxDS3_INT_STATUS_CPBIT_ERR 0x80 +#define BIT_RxDS3_INT_STATUS_LOS 0x40 +#define BIT_RxDS3_INT_STATUS_AIS 0x20 +#define BIT_RxDS3_INT_STATUS_IDLE 0x10 +#define BIT_RxDS3_INT_STATUS_FERF 0x08 +#define BIT_RxDS3_INT_STATUS_AIC 0x04 +#define BIT_RxDS3_INT_STATUS_OOF 0x02 +#define BIT_RxDS3_INT_STATUS_PBIT_ERR 0x01 + +/* Receive E3, ITU-T G.832 */ +#define REG_RxE3_CFG_STATUS_1 0x10 +#define BIT_RxE3_CFG_STATUS_RxPLDType2 0x80 +#define BIT_RxE3_CFG_STATUS_RxPLDType1 0x40 +#define BIT_RxE3_CFG_STATUS_RxPLDType0 0x20 +#define BIT_RxE3_CFG_STATUS_RxFERF_ALGO 0x10 +#define BIT_RxE3_CFG_STATUS_RxTMARK_ALGO 0x08 +#define BIT_RxE3_CFG_STATUS_RxPLDExp2 0x80 +#define BIT_RxE3_CFG_STATUS_RxPLDExp1 0x40 +#define BIT_RxE3_CFG_STATUS_RxPLDExp0 0x20 + +#define REG_RxE3_CFG_STATUS_2 0x11 +#define BIT_RxE3_CFG_STATUS_RxLOF_ALGO 0x80 +#define BIT_RxE3_CFG_STATUS_RxLOF 0x40 +#define BIT_RxE3_CFG_STATUS_RxOOF 0x20 +#define BIT_RxE3_CFG_STATUS_RxLOS 0x10 +#define BIT_RxE3_CFG_STATUS_RxAIS 0x08 +#define BIT_RxE3_CFG_STATUS_RxPLD 0x04 +#define BIT_RxE3_CFG_STATUS_RxTMARK 0x02 +#define BIT_RxE3_CFG_STATUS_RxFERF 0x01 + +#define REG_RxE3_INT_ENABLE_1 0x12 +#define BIT_RxE3_INT_ENABLE_SSM_MSG 0x40 +#define BIT_RxE3_INT_ENABLE_SSM_OOS 0x20 +#define BIT_RxE3_INT_ENABLE_COFA 0x10 +#define BIT_RxE3_INT_ENABLE_OOF 0x08 +#define BIT_RxE3_INT_ENABLE_LOF 0x04 +#define BIT_RxE3_INT_ENABLE_LOS 0x02 +#define BIT_RxE3_INT_ENABLE_AIS 0x01 + +#define REG_RxE3_INT_ENABLE_2 0x13 +#define BIT_RxE3_INT_ENABLE_TTB_CHANGE 0x40 +#define BIT_RxE3_INT_ENABLE_FEBE 0x10 +#define BIT_RxE3_INT_ENABLE_FERF 0x08 +#define BIT_RxE3_INT_ENABLE_BIP_8 0x04 +#define BIT_RxE3_INT_ENABLE_FRAMING 0x02 +#define BIT_RxE3_INT_ENABLE_RxPLD 0x01 + +#define REG_RxE3_INT_STATUS_1 0x14 +#define BIT_RxE3_INT_STATUS_SSM_MSG 0x40 +#define BIT_RxE3_INT_STATUS_SSM_OOS 0x20 +#define BIT_RxE3_INT_STATUS_COFA 0x10 +#define BIT_RxE3_INT_STATUS_OOF 0x08 +#define BIT_RxE3_INT_STATUS_LOF 0x04 +#define BIT_RxE3_INT_STATUS_LOS 0x02 +#define BIT_RxE3_INT_STATUS_AIS 0x01 + +#define REG_RxE3_INT_STATUS_2 0x15 +#define BIT_RxE3_INT_STATUS_TTB_CHANGE 0x40 +#define BIT_RxE3_INT_STATUS_FEBE 0x10 +#define BIT_RxE3_INT_STATUS_FERF 0x08 +#define BIT_RxE3_INT_STATUS_BIP_8 0x04 +#define BIT_RxE3_INT_STATUS_FRAMING 0x02 +#define BIT_RxE3_INT_STATUS_RxPLD 0x01 + +/* Receive E3, ITU-T G.751 */ +//#define REG_RxE3_CFG_STATUS_1 0x10 +//#define BIT_RxE3_CFG_STATUS_RxFERF_ALGO 0x10 + +//#define REG_RxE3_CFG_STATUS_2 0x11 +#define BIT_RxE3_CFG_STATUS_RxBIP4 0x01 +//#define BIT_RxE3_CFG_STATUS_RxLOF_ALGO 0x80 +//#define BIT_RxE3_CFG_STATUS_RxLOF 0x40 +//#define BIT_RxE3_CFG_STATUS_RxOOF 0x20 +//#define BIT_RxE3_CFG_STATUS_RxLOS 0x10 +//#define BIT_RxE3_CFG_STATUS_RxAIS 0x08 +//#define BIT_RxE3_CFG_STATUS_RxFERF 0x01 + +//#define REG_RxE3_INT_ENABLE_1 0x12 +//#define BIT_RxE3_INT_ENABLE_COFA 0x10 +//#define BIT_RxE3_INT_ENABLE_OOF 0x08 +//#define BIT_RxE3_INT_ENABLE_LOF 0x04 +//#define BIT_RxE3_INT_ENABLE_LOS 0x02 +//#define BIT_RxE3_INT_ENABLE_AIS 0x01 + +//#define REG_RxE3_INT_ENABLE_2 0x13 +//#define BIT_RxE3_INT_ENABLE_FERF 0x08 +//#define BIT_RxE3_INT_ENABLE_BIP-8 0x04 +//#define BIT_RxE3_INT_ENABLE_FRAMING 0x02 + +//#define REG_RxE3_INT_STATUS_1 0x14 +//#define BIT_RxE3_INT_STATUS_COFA 0x10 +//#define BIT_RxE3_INT_STATUS_OOF 0x08 +//#define BIT_RxE3_INT_STATUS_LOF 0x04 +//#define BIT_RxE3_INT_STATUS_LOS 0x02 +//#define BIT_RxE3_INT_STATUS_AIS 0x01 + +//#define REG_RxE3_INT_STATUS_2 0x15 +//#define BIT_RxE3_INT_STATUS_FERF 0x08 +//#define BIT_RxE3_INT_STATUS_BIP-8 0x04 +//#define BIT_RxE3_INT_STATUS_FRAMING 0x02 + +#define REG_RxDS3_FEAC 0x16 +#define BIT_RxDS3_FEAC_5 0x40 +#define BIT_RxDS3_FEAC_4 0x20 +#define BIT_RxDS3_FEAC_3 0x10 +#define BIT_RxDS3_FEAC_2 0x08 +#define BIT_RxDS3_FEAC_1 0x04 +#define BIT_RxDS3_FEAC_0 0x02 + +#define REG_RxDS3_FEAC_INT 0x17 +#define BIT_RxDS3_FEAC_INT_FEAC_VALID 0x10 +#define BIT_RxDS3_FEAC_REMOVE_INT_EN 0x08 +#define BIT_RxDS3_FEAC_REMOVE_INT_STATUS 0x04 +#define BIT_RxDS3_FEAC_VALID_INT_EN 0x02 +#define BIT_RxDS3_FEAC_VALID_INT_STATUS 0x01 + +/* Transmit DS3 */ +#define REG_TxDS3_CFG 0x30 +#define BIT_TxDS3_CFG_YELLOW_ALARM 0x80 +#define BIT_TxDS3_CFG_XBits 0x40 +#define BIT_TxDS3_CFG_IDLE 0x20 +#define BIT_TxDS3_CFG_AIS 0x10 +#define BIT_TxDS3_CFG_LOS 0x08 +#define BIT_TxDS3_CFG_FERF_on_LOS 0x04 +#define BIT_TxDS3_CFG_FERF_on_OOF 0x02 +#define BIT_TxDS3_CFG_FERF_on_AIS 0x01 + +#define REG_TxDS3_CFG_STATUS 0x31 +#define BIT_TxDS3_CFG_STATUS_FEAC_INTE 0x10 +#define BIT_TxDS3_CFG_STATUS_FEAC_INTS 0x08 +#define BIT_TxDS3_CFG_STATUS_FEAC_ENABLE 0x04 +#define BIT_TxDS3_CFG_STATUS_FEAC_GO 0x02 +#define BIT_TxDS3_CFG_STATUS_FEAC_BUSY 0x01 + +#define REG_TxDS3_LAPD_STATUS 0x34 +#define BIT_TxDS3_LAPD_STATUS_START 0x08 +#define BIT_TxDS3_LAPD_STATUS_BUSY 0x04 +#define BIT_TxDS3_LAPD_STATUS_INT_EN 0x02 +#define BIT_TxDS3_LAPD_STATUS_INT 0x01 + +/* Transmit E3, ITU-T G.832 */ +#define REG_TxE3_CFG 0x30 +#define BIT_TxE3_CFG_DLinNR 0x10 +#define BIT_TxE3_CFG_AIS_ENABLE 0x04 +#define BIT_TxE3_CFG_LOS_ENABLE 0x02 +#define BIT_TxE3_CFG_MARx 0x01 + +/* Transmit E3, ITU-T G.751 */ +#define REG_TxE3_CFG 0x30 +#define BIT_TxE3_CFG_BIP4_ENABLE 0x80 +#define BIT_TxE3_CFG_ASRCSEL1 0x40 +#define BIT_TxE3_CFG_ASRCSEL0 0x20 +#define BIT_TxE3_CFG_NSRCSEL1 0x10 +#define BIT_TxE3_CFG_NSRCSEL0 0x08 +#define BIT_TxE3_CFG_AIS_ENABLE 0x04 +#define BIT_TxE3_CFG_LOS_ENABLE 0x02 +#define BIT_TxE3_CFG_FAS_SRC_SELECT 0x01 + +/* Performance Monitor Registers */ +#define REG_PMON_LCV_MSB 0x50 +#define REG_PMON_LCV_LSB 0x51 +#define REG_PMON_FRAMING_ERR_CNT_MSB 0x52 +#define REG_PMON_FRAMING_ERR_CNT_LSB 0x53 +#define REG_PMON_PARITY_ERR_CNT_MSB 0x54 +#define REG_PMON_PARITY_ERR_CNT_LSB 0x55 +#define REG_PMON_FEBE_EVENT_CNT_MSB 0x56 +#define REG_PMON_FEBE_EVENT_CNT_LSB 0x57 +#define REG_PMON_CPBIT_ERROR_CNT_MSB 0x58 +#define REG_PMON_CPBIT_ERROR_CNT_LSB 0x59 +#define REG_PMON_HOLDING 0x6C + +/* One-Second Error Status Register */ +#define REG_ONESECOND_ERR_STATUS 0x6D +#define BIT_ONESECOND_ERR_STATUS_ERR 0x02 +#define BIT_ONESECOND_ERR_STATUS_SEVERELY_ERR 0x01 + +#define REG_ONESECOND_LCV_MSB 0x6E +#define REG_ONESECOND_LCV_LSB 0x6F +#define REG_ONESECOND_FRAME_PARITY_ERR_MSB 0x70 +#define REG_ONESECOND_FRAME_PARITY_ERR_LSB 0x71 +#define REG_ONESECOND_FRAME_CPBIT_ERR_MSB 0x72 +#define REG_ONESECOND_FRAME_CPBIT_ERR_LSB 0x73 + +#define REG_LINE_INTERFACE_DRIVE 0x80 +#define BIT_LINE_INTERFACE_DRIVE_REQB 0x20 +#define BIT_LINE_INTERFACE_DRIVE_TAOS 0x10 +#define BIT_LINE_INTERFACE_DRIVE_ENCODIS 0x08 +#define BIT_LINE_INTERFACE_DRIVE_LEV 0x04 +#define BIT_LINE_INTERFACE_DRIVE_RLOOP 0x02 +#define BIT_LINE_INTERFACE_DRIVE_LLOOP 0x01 + +#define REG_LINE_INTERFACE_SCAN 0x81 +#define BIT_LINE_INTERFACE_SCAN_DMO 0x04 +#define BIT_LINE_INTERFACE_SCAN_RLOL 0x02 +#define BIT_LINE_INTERFACE_SCAN_RLOS 0x01 + +/* T3/E3 CPLD register */ +#define REG_CPLD_CNTRL 0x00 +#define BIT_CPLD_CNTRL_REQEN 0x20 +#define BIT_CPLD_CNTRL_TxLEV 0x10 +#define BIT_CPLD_CNTRL_RxMON 0x08 +#define BIT_CPLD_CNTRL_LOSMUT 0x04 +#define BIT_CPLD_CNTRL_STS_1 0x02 +#define BIT_CPLD_CNTRL_E3 0x01 + +#define REG_CPLD_STATUS 0x01 +#define BIT_CPLD_STATUS_TAOS 0x80 +#define BIT_CPLD_STATUS_RLB 0x40 +#define BIT_CPLD_STATUS_LLB 0x20 +#define BIT_CPLD_STATUS_RLOL 0x04 +#define BIT_CPLD_STATUS_RLOS 0x02 +#define BIT_CPLD_STATUS_DMO 0x01 + +#endif /* __SDLA_TE3_REG_H */ diff -Nur linux.org/include/linux/sdla_template.h linux-2.6.17/include/linux/sdla_template.h --- linux.org/include/linux/sdla_template.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/sdla_template.h 2006-08-30 10:07:15.000000000 +0000 @@ -0,0 +1,215 @@ +/************************************************************************* + sdla_temp.h Template Header + + Author: Nenad Corbic + + Copyright: (c) 1995-2002 Sangoma Technologies Inc. + + This program is free software; you can redistribute it and/or + modify it under the term of the GNU General Public License + as published by the Free Software Foundation; either version + 2 of the License, or (at your option) any later version. + +=========================================================================== +Jan 08, 2003 Nenad Corbic Initial Version +=========================================================================== + +**************************************************************************/ + + + +#ifndef __SDLA_TEMPLATE__ +#define __SDLA_TEMPlATE__ + + +#define SHARED_MEMORY_INFO_STRUCT void +#define CONFIGURATION_STRUCT void +#define INTERRUPT_INFORMATION_STRUCT void +#define TRIGGERS_STRUCT void +#define DATA_RX_STATUS_EL_STRUCT void +#define DATA_TX_STATUS_EL_STRUCT void +#define INT_TRIGGERS_STRUCT void +#define TX_STATUS_EL_CFG_STRUCT void +#define RX_STATUS_EL_CFG_STRUCT void +#define TRACE_STATUS_EL_CFG_STRUCT void +#define TRACE_STATUS_ELEMENT_STRUCT void +#define LINE_TRACE_CONFIG_STRUCT void +#define COMMS_ERROR_STATS_STRUCT void +#define OPERATIONAL_STATS_STRUCT void + +#define DFLT_TEMPLATE_VALUE 0 + +#define WANCONFIG_FRMW DFLT_TEMPLATE_VALUE + +#define COMMAND_OK DFLT_TEMPLATE_VALUE + +#define APP_INT_ON_TIMER DFLT_TEMPLATE_VALUE +#define APP_INT_ON_TX_FRAME DFLT_TEMPLATE_VALUE +#define APP_INT_ON_RX_FRAME DFLT_TEMPLATE_VALUE +#define APP_INT_ON_GLOBAL_EXCEP_COND DFLT_TEMPLATE_VALUE +#define APP_INT_ON_EXCEP_COND DFLT_TEMPLATE_VALUE +#define APP_INT_ON_COMMAND_COMPLETE DFLT_TEMPLATE_VALUE + +#define READ_CODE_VERSION DFLT_TEMPLATE_VALUE + +#define READ_CONFIGURATION DFLT_TEMPLATE_VALUE +#define SET_CONFIGURATION DFLT_TEMPLATE_VALUE + +#define INTERRUPT_TRIGGERS DFLT_TEMPLATE_VALUE + +#define DISABLE_COMMUNICATIONS DFLT_TEMPLATE_VALUE +#define ENABLE_COMMUNICATIONS DFLT_TEMPLATE_VALUE + +#define SET_INTERRUPT_TRIGGERS DFLT_TEMPLATE_VALUE + +#define UDPMGMT_SIGNATURE DFLT_TEMPLATE_VALUE + +#define FT1_MONITOR_STATUS_CTRL DFLT_TEMPLATE_VALUE +#define ENABLE_READ_FT1_STATUS DFLT_TEMPLATE_VALUE +#define ENABLE_READ_FT1_OP_STATS DFLT_TEMPLATE_VALUE +#define CPIPE_FT1_READ_STATUS DFLT_TEMPLATE_VALUE +#define TRACE_INACTIVE DFLT_TEMPLATE_VALUE + +#define READ_GLOBAL_STATISTICS DFLT_TEMPLATE_VALUE +#define READ_MODEM_STATUS DFLT_TEMPLATE_VALUE +#define READ_LINK_STATUS DFLT_TEMPLATE_VALUE +#define ROUTER_UP_TIME DFLT_TEMPLATE_VALUE +#define READ_COMMS_ERROR_STATS DFLT_TEMPLATE_VALUE +#define READ_OPERATIONAL_STATS DFLT_TEMPLATE_VALUE +#define READ_TRACE_CONFIGURATION DFLT_TEMPLATE_VALUE + +#define GET_TRACE_INFO DFLT_TEMPLATE_VALUE +#define SET_TRACE_CONFIGURATION DFLT_TEMPLATE_VALUE + +#define FT1_READ_STATUS DFLT_TEMPLATE_VALUE +#define UDP_TYPE DFLT_TEMPLATE_VALUE +#define ENABLE_TRACING DFLT_TEMPLATE_VALUE +#define TRACE_ACTIVE DFLT_TEMPLATE_VALUE + +#define EXCEP_TRC_DISABLED DFLT_TEMPLATE_VALUE +#define EXCEP_IRQ_TIMEOUT DFLT_TEMPLATE_VALUE +#define READ_EXCEPTION_CONDITION DFLT_TEMPLATE_VALUE +#define EXCEP_LINK_ACTIVE DFLT_TEMPLATE_VALUE +#define EXCEP_LINK_INACTIVE_MODEM DFLT_TEMPLATE_VALUE +#define EXCEP_LINK_INACTIVE_KPALV DFLT_TEMPLATE_VALUE +#define EXCEP_IP_ADDRESS_DISCOVERED DFLT_TEMPLATE_VALUE +#define EXCEP_LOOPBACK_CONDITION DFLT_TEMPLATE_VALUE +#define NO_EXCEP_COND_TO_REPORT DFLT_TEMPLATE_VALUE +#define DISABLE_TRACING DFLT_TEMPLATE_VALUE + + + +#define TX_BYTE_COUNT_STAT DFLT_TEMPLATE_VALUE +#define RX_BYTE_COUNT_STAT DFLT_TEMPLATE_VALUE +#define TX_THROUGHPUT_STAT DFLT_TEMPLATE_VALUE +#define RX_THROUGHPUT_STAT DFLT_TEMPLATE_VALUE +#define INCL_UNDERRUN_TX_THRUPUT DFLT_TEMPLATE_VALUE +#define INCL_DISC_RX_THRUPUT DFLT_TEMPLATE_VALUE +#define START_BAUD_CALIBRATION DFLT_TEMPLATE_VALUE +#define READ_BAUD_CALIBRATION_RESULT DFLT_TEMPLATE_VALUE +#define BAUD_CALIBRATION_NOT_DONE DFLT_TEMPLATE_VALUE +#define BUSY_WITH_BAUD_CALIBRATION DFLT_TEMPLATE_VALUE +#define BAUD_CAL_FAILED_NO_TX_CLK DFLT_TEMPLATE_VALUE +#define BAUD_CAL_FAILED_BAUD_HI DFLT_TEMPLATE_VALUE +#define CANNOT_DO_BAUD_CAL DFLT_TEMPLATE_VALUE +#define READ_GLOBAL_EXCEPTION_CONDITION DFLT_TEMPLATE_VALUE +#define EXCEP_MODEM_STATUS_CHANGE DFLT_TEMPLATE_VALUE +#define DCD_HIGH DFLT_TEMPLATE_VALUE +#define CTS_HIGH DFLT_TEMPLATE_VALUE + +#define INTERFACE_LEVEL_RS232 DFLT_TEMPLATE_VALUE +#define INTERFACE_LEVEL_V35 DFLT_TEMPLATE_VALUE +#define TRANSPARENT_TX_RX_CELLS DFLT_TEMPLATE_VALUE +#define UNI DFLT_TEMPLATE_VALUE +#define DISABLE_RX_HEC_CHECK DFLT_TEMPLATE_VALUE +#define MAX_CELLS_IN_TX_BLOCK DFLT_TEMPLATE_VALUE +#define MAX_RX_COMPLETE_CELL_COUNT DFLT_TEMPLATE_VALUE + + + +#define COMMAND_COMPLETE_APP_INT_PEND DFLT_TEMPLATE_VALUE +#define RX_APP_INT_PEND DFLT_TEMPLATE_VALUE +#define TX_APP_INT_PEND DFLT_TEMPLATE_VALUE +#define EXCEP_COND_APP_INT_PEND DFLT_TEMPLATE_VALUE +#define GLOBAL_EXCEP_COND_APP_INT_PEND DFLT_TEMPLATE_VALUE +#define TIMER_APP_INT_PEND DFLT_TEMPLATE_VALUE + +#define MIN_WP_PRI_MTU 1500 +#define MAX_WP_PRI_MTU MIN_WP_PRI_MTU +#define DEFAULT_WP_PRI_MTU MIN_WP_PRI_MTU + +#define MIN_WP_SEC_MTU 1500 +#define MAX_WP_SEC_MTU MIN_WP_SEC_MTU +#define DEFAULT_WP_SEC_MTU MIN_WP_SEC_MTU + + +/* reasons for enabling the timer interrupt on the adapter */ +#define TMR_INT_ENABLED_UDP 0x01 +#define TMR_INT_ENABLED_UPDATE 0x02 +#define TMR_INT_ENABLED_CONFIG 0x10 +#define TMR_INT_ENABLED_TE 0x20 + + +#define PRI_BASE_ADDR_MB_STRUCT DFLT_TEMPLATE_VALUE +static __inline void init_card_mailbox(sdla_t *card) +{ + /* Initialize protocol-specific fields */ + if(card->hw.type != SDLA_S514){ + card->mbox = (void *) card->hw.dpmbase; + }else{ + /* for a S514 adapter, set a pointer to the actual mailbox in the */ + /* allocated virtual memory area */ + card->mbox = (void *) card->hw.dpmbase + PRI_BASE_ADDR_MB_STRUCT; + } +} + +static __inline wan_mbox_t *get_card_mailbox(sdla_t *card) +{ + return (wan_mbox_t*)card->mbox; +} + +static __inline void *get_card_flags(sdla_t *card) +{ + return card->u.c.flags; +} + +static __inline void set_card_flags(sdla_t *card, void *ptr) +{ + card->u.c.flags = ptr; +} +static __inline void *get_card_rxmb(sdla_t *card) +{ + return card->u.c.rxmb; +} + +static __inline void set_card_rxmb(sdla_t *card, void *ptr) +{ + card->u.c.rxmb = ptr; + if((void*)ptr > card->u.c.rxbuf_last){ + card->u.c.rxmb = card->u.c.rxbuf_base; + } +} + +static __inline unsigned long get_rxtop_buf(sdla_t *card) +{ + return card->u.c.rx_top; +} +static __inline unsigned long get_rxbase_buf(sdla_t *card) +{ + return card->u.c.rx_base; +} + +static __inline void *get_card_txbuf(sdla_t *card) +{ + return card->u.c.txbuf; +} + +static __inline void set_card_txbuf(sdla_t *card, void *ptr) +{ + card->u.c.txbuf = ptr; + if ((void*)ptr > card->u.c.txbuf_last) + card->u.c.txbuf = card->u.c.txbuf_base; +} + + +#endif diff -Nur linux.org/include/linux/sdla_x25.h linux-2.6.17/include/linux/sdla_x25.h --- linux.org/include/linux/sdla_x25.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/sdla_x25.h 2006-08-30 10:07:15.000000000 +0000 @@ -0,0 +1,789 @@ +/***************************************************************************** +* sdla_x25.h Sangoma X.25 firmware API definitions. +* +* Author: Nenad Corbic +* +* Copyright: (c) 1995-2000 Sangoma Technologies Inc. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version + 2 of the License, or (at your option) any later version. +* ============================================================================ +* Feb 28, 2000 Nenad Corbic Updated for socket based x25api +* Dec 13, 1996 Gene Kozin Initial version +*****************************************************************************/ +#ifndef _SDLA_X25_H +#define _SDLA_X25_H + +/*---------------------------------------------------------------------------- + * Notes: + * ------ + * 1. All structures defined in this file are byte-alined. + * Compiler Platform + * -------- -------- + * GNU C Linux + * + */ + +#ifndef PACKED +# define PACKED __attribute__((packed)) +#endif /* PACKED */ + +#include + +/****** CONSTANTS DEFINITIONS ***********************************************/ + +#define X25_MAX_CHAN 255 /* max number of open X.25 circuits */ +#define X25_MAX_DATA 1024 /* max length of X.25 data buffer */ +/* + * X.25 shared memory layout. + */ +#define X25_MBOX_OFFS 0x16B0 /* general mailbox block */ +#define X25_RXMBOX_OFFS 0x1AD0 /* receive mailbox */ +#define X25_STATUS_OFFS 0x1EF0 /* X.25 status structure */ +#define X25_MB_VECTOR 0xE000 /* S514 mailbox window vecotr */ +#define X25_MISC_HDLC_BITS 0x1F00 /*X.25 miscallaneous HDLC bits */ +#define X25_MODEM_STATE_OFFS 0xF6AF /* Mode state offset */ +#define X25_TX_TIMEOUT_OFFS 0xF6AE /* Tx Timeout: detect no tx clock */ + +/* code levels */ +#define HDLC_LEVEL 0x01 +#define X25_LEVEL 0x02 +#define X25_AND_HDLC_LEVEL 0x03 +#define DO_HDLC_LEVEL_ERROR_CHECKING 0x04 + +/****** DATA STRUCTURES *****************************************************/ + +/*---------------------------------------------------------------------------- + * X.25 Command Block. + */ +typedef struct X25Cmd +{ + unsigned char command PACKED; /* command code */ + unsigned short length PACKED; /* transfer data length */ + unsigned char result PACKED; /* return code */ + unsigned char pf PACKED; /* P/F bit */ + unsigned short lcn PACKED; /* logical channel */ + unsigned char qdm PACKED; /* Q/D/M bits */ + unsigned char cause PACKED; /* cause field */ + unsigned char diagn PACKED; /* diagnostics */ + unsigned char pktType PACKED; /* packet type */ + unsigned char resrv[4] PACKED; /* reserved */ +} TX25Cmd; + +/* + * Defines for the 'command' field. + */ +/*----- General commands --------------*/ +#define X25_SET_GLOBAL_VARS 0x0B /* set global variables */ +#define X25_READ_MODEM_STATUS 0x0C /* read modem status */ +#define X25_READ_CODE_VERSION 0x15 /* read firmware version number */ +#define X25_TRACE_CONFIGURE 0x14 /* configure trace facility */ +#define X25_READ_TRACE_DATA 0x16 /* read trace data */ +#define X25_SET_INTERRUPT_MODE 0x17 /* set interrupt generation mode */ +#define X25_READ_INTERRUPT_MODE 0x18 /* read interrupt generation mode */ +/*----- HDLC-level commands -----------*/ +#define X25_HDLC_LINK_CONFIGURE 0x01 /* configure HDLC link level */ +#define X25_HDLC_LINK_OPEN 0x02 /* open HDLC link */ +#define X25_HDLC_LINK_CLOSE 0x03 /* close HDLC link */ +#define X25_HDLC_LINK_SETUP 0x04 /* set up HDLC link */ +#define X25_HDLC_LINK_DISC 0x05 /* disconnect DHLC link */ +#define X25_HDLC_LINK_STATUS 0x06 /* read DHLC link status */ +#define X25_HDLC_READ_STATS 0x07 /* read operational statistics */ +#define X25_HDLC_FLUSH_STATS 0x08 /* flush operational statistics */ +#define X25_HDLC_READ_COMM_ERR 0x09 /* read error statistics */ +#define X25_HDLC_FLUSH_COMM_ERR 0x0A /* flush error statistics */ +#define X25_HDLC_FLUSH_BUFFERS 0x0D /* flush HDLC-level data buffers */ +#define X25_HDLC_SPRVS_CNT_STAT 0x0F /* read surervisory count status */ +#define X25_HDLC_SEND_UI_FRAME 0x10 /* send unnumbered information frame */ +#define X25_HDLC_WRITE 0x11 /* send HDLC information frame */ +#define X25_HDLC_READ 0x21 /* read HDLC information frame */ +#define X25_HDLC_READ_CONFIG 0x12 /* read HDLC configuration */ +#define X25_HDLC_SET_CONFIG 0x13 /* set HDLC configuration */ +#define SET_PROTOCOL_LEVEL 0x1F /* set protocol level */ +/*----- X.25-level commands -----------*/ +#define X25_READ 0x22 /* read X.25 packet */ +#define X25_WRITE 0x23 /* send X.25 packet */ +#define X25_PLACE_CALL 0x30 /* place a call on SVC */ +#define X25_ACCEPT_CALL 0x31 /* accept incomming call */ +#define X25_CLEAR_CALL 0x32 /* clear call */ +#define X25_CLEAR_CONFRM 0x33 /* send clear confirmation packet */ +#define X25_RESET 0x34 /* send reset request packet */ +#define X25_RESET_CONFRM 0x35 /* send reset confirmation packet */ +#define X25_RESTART 0x36 /* send restart request packet */ +#define X25_RESTART_CONFRM 0x37 /* send restart confirmation packet */ +#define X25_WP_INTERRUPT 0x38 /* send interrupt request packet */ +#define X25_INTERRUPT_CONFRM 0x39 /* send interrupt confirmation pkt */ +#define X25_REGISTRATION_RQST 0x3A /* send registration request packet */ +#define X25_REGISTRATION_CONFRM 0x3B /* send registration confirmation */ +#define X25_IS_DATA_AVAILABLE 0x40 /* querry receive queue */ +#define X25_INCOMMING_CALL_CTL 0x41 /* select incomming call options */ +#define X25_CONFIGURE_PVC 0x42 /* configure PVC */ +#define X25_GET_ACTIVE_CHANNELS 0x43 /* get a list of active circuits */ +#define X25_READ_CHANNEL_CONFIG 0x44 /* read virt. circuit configuration */ +#define X25_FLUSH_DATA_BUFFERS 0x45 /* flush X.25-level data buffers */ +#define X25_READ_HISTORY_TABLE 0x46 /* read asynchronous event log */ +#define X25_HISTORY_TABLE_CTL 0x47 /* control asynchronous event log */ +#define X25_GET_TX_D_BIT_STATUS 0x48 /* is packet with D-bit acknowleged */ +#define X25_READ_STATISTICS 0x49 /* read X.25-level statistics */ +#define X25_FLUSH_STATISTICS 0x4A /* flush X.25-level statistics */ +#define X25_READ_CONFIGURATION 0x50 /* read HDLC & X.25 configuration */ +#define X25_SET_CONFIGURATION 0x51 /* set HDLC & X.25 configuration */ + +/* + * Defines for the 'result' field. + */ +/*----- General results ---------------*/ +#define X25RES_OK 0x00 +#define X25RES_ERROR 0x01 +#define X25RES_LINK_NOT_IN_ABM 0x02 /* link is not in ABM mode */ +#define X25RES_LINK_CLOSED 0x03 +#define X25RES_INVAL_LENGTH 0x04 +#define X25RES_INVAL_CMD 0x05 +#define X25RES_UNNUMBERED_FRAME 0x06 /* unnunbered frame received */ +#define X25RES_FRM_REJECT_MODE 0x07 /* link is in Frame Reject mode */ +#define X25RES_MODEM_FAILURE 0x08 /* DCD and/or CTS dropped */ +#define X25RES_N2_RETRY_LIMIT 0x09 /* N2 retry limit has been exceeded */ +#define X25RES_INVAL_LCN 0x30 /* invalid logical channel number */ +#define X25RES_INVAL_STATE 0x31 /* channel is not in data xfer mode */ +#define X25RES_INVAL_DATA_LEN 0x32 /* invalid data length */ +#define X25RES_NOT_READY 0x33 /* no data available / buffers full */ +#define X25RES_NETWORK_DOWN 0x34 +#define X25RES_CHANNEL_IN_USE 0x35 /* there is data queued on this LCN */ +#define X25RES_REGST_NOT_SUPPRT 0x36 /* registration not supported */ +#define X25RES_INVAL_FORMAT 0x37 /* invalid packet format */ +#define X25RES_D_BIT_NOT_SUPPRT 0x38 /* D-bit pragmatics not supported */ +#define X25RES_FACIL_NOT_SUPPRT 0x39 /* Call facility not supported */ +#define X25RES_INVAL_CALL_ARG 0x3A /* errorneous call arguments */ +#define X25RES_INVAL_CALL_DATA 0x3B /* errorneous call user data */ +#define X25RES_ASYNC_PACKET 0x40 /* asynchronous packet received */ +#define X25RES_PROTO_VIOLATION 0x41 /* protocol violation occured */ +#define X25RES_PKT_TIMEOUT 0x42 /* X.25 packet time out */ +#define X25RES_PKT_RETRY_LIMIT 0x43 /* X.25 packet retry limit exceeded */ +/*----- Command-dependant results -----*/ +#define X25RES_LINK_DISC 0x00 /* HDLC_LINK_STATUS */ +#define X25RES_LINK_IN_ABM 0x01 /* HDLC_LINK_STATUS */ +#define X25RES_NO_DATA 0x01 /* HDLC_READ/READ_TRACE_DATA*/ +#define X25RES_TRACE_INACTIVE 0x02 /* READ_TRACE_DATA */ +#define X25RES_LINK_IS_OPEN 0x01 /* HDLC_LINK_OPEN */ +#define X25RES_LINK_IS_DISC 0x02 /* HDLC_LINK_DISC */ +#define X25RES_LINK_IS_CLOSED 0x03 /* HDLC_LINK_CLOSE */ +#define X25RES_INVAL_PARAM 0x31 /* INCOMMING_CALL_CTL */ +#define X25RES_INVAL_CONFIG 0x35 /* REGISTR_RQST/CONFRM */ + +/* + * Defines for the 'qdm_bits' field. + */ +#define X25CMD_Q_BIT_MASK 0x04 +#define X25CMD_D_BIT_MASK 0x02 +#define X25CMD_M_BIT_MASK 0x01 + +/* + * Defines for the 'pkt_type' field. + */ +/*----- Asynchronous events ------*/ + +#define ASE_LAPB_DOWN 0x00 +#define ASE_MODEM_DOWN X25_READ_MODEM_STATUS + +#define ASE_CLEAR_RQST 0x02 +#define ASE_RESET_RQST 0x04 +#define ASE_RESTART_RQST 0x08 +#define ASE_INTERRUPT 0x10 +#define ASE_DTE_REGISTR_RQST 0x20 +#define ASE_CALL_RQST 0x30 +#define ASE_CALL_ACCEPTED 0x31 +#define ASE_CLEAR_CONFRM 0x32 +#define ASE_RESET_CONFRM 0x33 +#define ASE_RESTART_CONFRM 0x34 +#define ASE_INTERRUPT_CONFRM 0x35 +#define ASE_DCE_REGISTR_CONFRM 0x36 +#define ASE_DIAGNOSTIC 0x37 +#define ASE_CALL_AUTO_CLEAR 0x38 +#define AUTO_RESPONSE_FLAG 0x80 +/*----- Time-Out events ----------*/ +#define TOE_RESTART_RQST 0x03 +#define TOE_CALL_RQST 0x05 +#define TOE_CLEAR_RQST 0x08 +#define TOE_RESET_RQST 0x0A +/*----- Protocol Violation events */ +#define PVE_CLEAR_RQST 0x32 +#define PVE_RESET_RQST 0x33 +#define PVE_RESTART_RQST 0x34 +#define PVE_DIAGNOSTIC 0x37 + +#define INTR_ON_RX_FRAME 0x01 +#define INTR_ON_TX_FRAME 0x02 +#define INTR_ON_MODEM_STATUS_CHANGE 0x04 +#define INTR_ON_COMMAND_COMPLETE 0x08 +#define INTR_ON_X25_ASY_TRANSACTION 0x10 +#define INTR_ON_TRACE_DATA 0x20 +#define INTR_ON_TIMER 0x40 +#define DIRECT_RX_INTR_USAGE 0x80 + +#define NO_INTR_PENDING 0x00 +#define RX_INTR_PENDING 0x01 +#define TX_INTR_PENDING 0x02 +#define MODEM_INTR_PENDING 0x04 +#define COMMAND_COMPLETE_INTR_PENDING 0x08 +#define X25_ASY_TRANS_INTR_PENDING 0x10 +#define TRACE_INTR_PENDING 0x20 +#define TIMER_INTR_PENDING 0x40 + +/*---------------------------------------------------------------------------- + * X.25 Mailbox. + * This structure is located at offsets X25_MBOX_OFFS and X25_RXMBOX_OFFS + * into shared memory window. + */ +typedef struct X25Mbox +{ + unsigned char opflag PACKED; /* 00h: execution flag */ + TX25Cmd cmd PACKED; /* 01h: command block */ + unsigned char data[1] PACKED; /* 10h: data buffer */ +} TX25Mbox; + +/*---------------------------------------------------------------------------- + * X.25 Time Stamp Structure. + */ +typedef struct X25TimeStamp +{ + unsigned char month PACKED; + unsigned char date PACKED; + unsigned char sec PACKED; + unsigned char min PACKED; + unsigned char hour PACKED; +} TX25TimeStamp; + +/*---------------------------------------------------------------------------- + * X.25 Status Block. + * This structure is located at offset X25_STATUS_OFF into shared memory + * window. + */ +typedef struct X25Status +{ + unsigned short pvc_map PACKED; /* 00h: PVC map */ + unsigned short icc_map PACKED; /* 02h: Incomming Chan. map */ + unsigned short twc_map PACKED; /* 04h: Two-way Cnan. map */ + unsigned short ogc_map PACKED; /* 06h: Outgoing Chan. map */ + TX25TimeStamp tstamp PACKED; /* 08h: timestamp (BCD) */ + unsigned char iflags PACKED; /* 0Dh: interrupt flags */ + unsigned char imask PACKED; /* 0Eh: interrupt mask */ + unsigned char resrv PACKED; /* 0Eh: */ + unsigned char gflags PACKED; /* 10h: misc. HDLC/X25 flags */ + unsigned char cflags[X25_MAX_CHAN] PACKED; /* channel status bytes */ +} TX25Status; + +/* + * Bitmasks for the 'iflags' field. + */ +#define X25_RX_INTR 0x01 /* receive interrupt */ +#define X25_TX_INTR 0x02 /* transmit interrupt */ +#define X25_MODEM_INTR 0x04 /* modem status interrupt (CTS/DCD) */ +#define X25_EVENT_INTR 0x10 /* asyncronous event encountered */ +#define X25_CMD_INTR 0x08 /* interface command complete */ + +/* + * Bitmasks for the 'gflags' field. + */ +#define X25_HDLC_ABM 0x01 /* HDLC is in ABM mode */ +#define X25_RX_READY 0x02 /* X.25 data available */ +#define X25_TRACE_READY 0x08 /* trace data available */ +#define X25_EVENT_IND 0x20 /* asynchronous event indicator */ +#define X25_TX_READY 0x40 /* space is available in Tx buf.*/ + +/* + * Bitmasks for the 'cflags' field. + */ +#define X25_XFER_MODE 0x80 /* channel is in data transfer mode */ +#define X25_TXWIN_OPEN 0x40 /* transmit window open */ +#define X25_RXBUF_MASK 0x3F /* number of data buffers available */ + +/***************************************************************************** + * Following definitions structurize contents of the TX25Mbox.data field for + * different X.25 interface commands. + ****************************************************************************/ + +/* --------------------------------------------------------------------------- + * X25_SET_GLOBAL_VARS Command. + */ +typedef struct X25GlobalVars +{ + unsigned char resrv PACKED; /* 00h: reserved */ + unsigned char dtrCtl PACKED; /* 01h: DTR control code */ + unsigned char resErr PACKED; /* 01h: '1' - reset modem error */ +} TX25GlobalVars; + +/* + * Defines for the 'dtrCtl' field. + */ +#define X25_RAISE_DTR 0x01 +#define X25_DROP_DTR 0x02 + +/* --------------------------------------------------------------------------- + * X25_READ_MODEM_STATUS Command. + */ +typedef struct X25ModemStatus +{ + unsigned char status PACKED; /* 00h: modem status */ +} TX25ModemStatus; + +/* + * Defines for the 'status' field. + */ +#define X25_CTS_MASK 0x20 +#define X25_DCD_MASK 0x08 + +/* --------------------------------------------------------------------------- + * X25_HDLC_LINK_STATUS Command. + */ +typedef struct X25LinkStatus +{ + unsigned char txQueued PACKED; /* 00h: queued Tx I-frames*/ + unsigned char rxQueued PACKED; /* 01h: queued Rx I-frames*/ + unsigned char station PACKED; /* 02h: DTE/DCE config. */ + unsigned char reserved PACKED; /* 03h: reserved */ + unsigned char sfTally PACKED; /* 04h: supervisory frame tally */ +} TX25LinkStatus; + +/* + * Defines for the 'station' field. + */ +#define X25_STATION_DTE 0x01 /* station configured as DTE */ +#define X25_STATION_DCE 0x02 /* station configured as DCE */ + +/* --------------------------------------------------------------------------- + * X25_HDLC_READ_STATS Command. + */ +typedef struct HdlcStats +{ /* a number of ... */ + unsigned short rxIFrames PACKED; /* 00h: ready Rx I-frames */ + unsigned short rxNoseq PACKED; /* 02h: frms out-of-sequence */ + unsigned short rxNodata PACKED; /* 04h: I-frms without data */ + unsigned short rxDiscarded PACKED; /* 06h: discarded frames */ + unsigned short rxTooLong PACKED; /* 08h: frames too long */ + unsigned short rxBadAddr PACKED; /* 0Ah: frms with inval.addr*/ + unsigned short txAcked PACKED; /* 0Ch: acknowledged I-frms */ + unsigned short txRetransm PACKED; /* 0Eh: re-transmit. I-frms */ + unsigned short t1Timeout PACKED; /* 10h: T1 timeouts */ + unsigned short rxSABM PACKED; /* 12h: received SABM frames */ + unsigned short rxDISC PACKED; /* 14h: received DISC frames */ + unsigned short rxDM PACKED; /* 16h: received DM frames */ + unsigned short rxFRMR PACKED; /* 18h: FRMR frames received */ + unsigned short txSABM PACKED; /* 1Ah: transm. SABM frames*/ + unsigned short txDISC PACKED; /* 1Ch: transm. DISC frames*/ + unsigned short txDM PACKED; /* 1Eh: transm. DM frames */ + unsigned short txFRMR PACKED; /* 20h: transm. FRMR frames*/ +} THdlcStats; + +/* --------------------------------------------------------------------------- + * X25_HDLC_READ_COMM_ERR Command. + */ +typedef struct HdlcCommErr +{ /* a number of ... */ + unsigned char rxOverrun PACKED; /* 00h: Rx overrun errors */ + unsigned char rxBadCrc PACKED; /* 01h: Rx CRC errors */ + unsigned char rxAborted PACKED; /* 02h: Rx aborted frames */ + unsigned char rxDropped PACKED; /* 03h: frames lost */ + unsigned char txAborted PACKED; /* 04h: Tx aborted frames */ + unsigned char txUnderrun PACKED; /* 05h: Tx underrun errors */ + unsigned char txMissIntr PACKED; /* 06h: missed underrun ints */ + unsigned char reserved PACKED; /* 07h: reserved */ + unsigned char droppedDCD PACKED; /* 08h: times DCD dropped */ + unsigned char droppedCTS PACKED; /* 09h: times CTS dropped */ +} THdlcCommErr; + +/* --------------------------------------------------------------------------- + * X25_SET_CONFIGURATION & X25_READ_CONFIGURATION Commands. + */ +typedef struct X25Config +{ +unsigned char baudRate PACKED; /* 00h: */ + unsigned char t1 PACKED; /* 01h: */ + unsigned char t2 PACKED; /* 02h: */ + unsigned char n2 PACKED; /* 03h: */ + unsigned short hdlcMTU PACKED; /* 04h: */ + unsigned char hdlcWindow PACKED; /* 06h: */ + unsigned char t4 PACKED; /* 07h: */ + unsigned char autoModem PACKED; /* 08h: */ + unsigned char autoHdlc PACKED; /* 09h: */ + unsigned char hdlcOptions PACKED; /* 0Ah: */ + unsigned char station PACKED; /* 0Bh: */ + unsigned char pktWindow PACKED; /* 0Ch: */ + unsigned short defPktSize PACKED; /* 0Dh: */ + unsigned short pktMTU PACKED; /* 0Fh: */ + unsigned short loPVC PACKED; /* 11h: */ + unsigned short hiPVC PACKED; /* 13h: */ + unsigned short loIncommingSVC PACKED; /* 15h: */ + unsigned short hiIncommingSVC PACKED; /* 17h: */ + unsigned short loTwoWaySVC PACKED; /* 19h: */ + unsigned short hiTwoWaySVC PACKED; /* 1Bh: */ + unsigned short loOutgoingSVC PACKED; /* 1Dh: */ + unsigned short hiOutgoingSVC PACKED; /* 1Fh: */ + unsigned short options PACKED; /* 21h: */ + unsigned char responseOpt PACKED; /* 23h: */ + unsigned short facil1 PACKED; /* 24h: */ + unsigned short facil2 PACKED; /* 26h: */ + unsigned short ccittFacil PACKED; /* 28h: */ + unsigned short otherFacil PACKED; /* 2Ah: */ + unsigned short ccittCompat PACKED; /* 2Ch: */ + unsigned char t10t20 PACKED; /* 2Eh: */ + unsigned char t11t21 PACKED; /* 2Fh: */ + unsigned char t12t22 PACKED; /* 30h: */ + unsigned char t13t23 PACKED; /* 31h: */ + unsigned char t16t26 PACKED; /* 32H: */ + unsigned char t28 PACKED; /* 33h: */ + unsigned char r10r20 PACKED; /* 34h: */ + unsigned char r12r22 PACKED; /* 35h: */ + unsigned char r13r23 PACKED; /* 36h: */ +} TX25Config; + +#define X25_PACKET_WINDOW 0x02 /* Default value for Window Size */ +/* --------------------------------------------------------------------------- + * X25_READ_CHANNEL_CONFIG Command. + */ +typedef struct X25ChanAlloc /*----- Channel allocation -*/ +{ + unsigned short loPVC PACKED; /* 00h: lowest PVC number */ + unsigned short hiPVC PACKED; /* 02h: highest PVC number */ + unsigned short loIncommingSVC PACKED; /* 04h: lowest incoming SVC */ + unsigned short hiIncommingSVC PACKED; /* 06h: highest incoming SVC */ + unsigned short loTwoWaySVC PACKED; /* 08h: lowest two-way SVC */ + unsigned short hiTwoWaySVC PACKED; /* 0Ah: highest two-way SVC */ + unsigned short loOutgoingSVC PACKED; /* 0Ch: lowest outgoing SVC */ + unsigned short hiOutgoingSVC PACKED; /* 0Eh: highest outgoing SVC */ +} TX25ChanAlloc; + +typedef struct X25ChanCfg /*------ Channel configuration -----*/ +{ + unsigned char type PACKED; /* 00h: channel type */ + unsigned char txConf PACKED; /* 01h: Tx packet and window sizes */ + unsigned char rxConf PACKED; /* 01h: Rx packet and window sizes */ +} TX25ChanCfg; + +/* + * Defines for the 'type' field. + */ +#define X25_PVC 0x01 /* PVC */ +#define X25_SVC_IN 0x03 /* Incoming SVC */ +#define X25_SVC_TWOWAY 0x07 /* Two-way SVC */ +#define X25_SVC_OUT 0x0B /* Outgoing SVC */ + +/*---------------------------------------------------------------------------- + * X25_READ_STATISTICS Command. + */ +typedef struct X25Stats +{ /* number of packets Tx/Rx'ed */ + unsigned short txRestartRqst PACKED; /* 00h: Restart Request */ + unsigned short rxRestartRqst PACKED; /* 02h: Restart Request */ + unsigned short txRestartConf PACKED; /* 04h: Restart Confirmation */ + unsigned short rxRestartConf PACKED; /* 06h: Restart Confirmation */ + unsigned short txResetRqst PACKED; /* 08h: Reset Request */ + unsigned short rxResetRqst PACKED; /* 0Ah: Reset Request */ + unsigned short txResetConf PACKED; /* 0Ch: Reset Confirmation */ + unsigned short rxResetConf PACKED; /* 0Eh: Reset Confirmation */ + unsigned short txCallRequest PACKED; /* 10h: Call Request */ + unsigned short rxCallRequest PACKED; /* 12h: Call Request */ + unsigned short txCallAccept PACKED; /* 14h: Call Accept */ + unsigned short rxCallAccept PACKED; /* 16h: Call Accept */ + unsigned short txClearRqst PACKED; /* 18h: Clear Request */ + unsigned short rxClearRqst PACKED; /* 1Ah: Clear Request */ + unsigned short txClearConf PACKED; /* 1Ch: Clear Confirmation */ + unsigned short rxClearConf PACKED; /* 1Eh: Clear Confirmation */ + unsigned short txDiagnostic PACKED; /* 20h: Diagnostic */ + unsigned short rxDiagnostic PACKED; /* 22h: Diagnostic */ + unsigned short txRegRqst PACKED; /* 24h: Registration Request */ + unsigned short rxRegRqst PACKED; /* 26h: Registration Request */ + unsigned short txRegConf PACKED; /* 28h: Registration Confirm.*/ + unsigned short rxRegConf PACKED; /* 2Ah: Registration Confirm.*/ + unsigned short txInterrupt PACKED; /* 2Ch: Interrupt */ + unsigned short rxInterrupt PACKED; /* 2Eh: Interrupt */ + unsigned short txIntrConf PACKED; /* 30h: Interrupt Confirm. */ + unsigned short rxIntrConf PACKED; /* 32h: Interrupt Confirm. */ + unsigned short txData PACKED; /* 34h: Data */ + unsigned short rxData PACKED; /* 36h: Data */ + unsigned short txRR PACKED; /* 38h: RR */ + unsigned short rxRR PACKED; /* 3Ah: RR */ + unsigned short txRNR PACKED; /* 3Ch: RNR */ + unsigned short rxRNR PACKED; /* 3Eh: RNR */ +} TX25Stats; + +/*---------------------------------------------------------------------------- + * X25_READ_HISTORY_TABLE Command. + */ +typedef struct X25EventLog +{ + unsigned char type PACKED; /* 00h: transaction type */ + unsigned short lcn PACKED; /* 01h: logical channel num */ + unsigned char packet PACKED; /* 03h: async packet type */ + unsigned char cause PACKED; /* 04h: X.25 cause field */ + unsigned char diag PACKED; /* 05h: X.25 diag field */ + TX25TimeStamp ts PACKED; /* 06h: time stamp */ +} TX25EventLog; + +/* + * Defines for the 'type' field. + */ +#define X25LOG_INCOMMING 0x00 +#define X25LOG_APPLICATION 0x01 +#define X25LOG_AUTOMATIC 0x02 +#define X25LOG_ERROR 0x04 +#define X25LOG_TIMEOUT 0x08 +#define X25LOG_RECOVERY 0x10 + +/* + * Defines for the 'packet' field. + */ +#define X25LOG_CALL_RQST 0x0B +#define X25LOG_CALL_ACCEPTED 0x0F +#define X25LOG_CLEAR_RQST 0x13 +#define X25LOG_CLEAR_CONFRM 0x17 +#define X25LOG_RESET_RQST 0x1B +#define X25LOG_RESET_CONFRM 0x1F +#define X25LOG_RESTART_RQST 0xFB +#define X25LOG_RESTART_COMFRM 0xFF +#define X25LOG_DIAGNOSTIC 0xF1 +#define X25LOG_DTE_REG_RQST 0xF3 +#define X25LOG_DTE_REG_COMFRM 0xF7 + + +/* --------------------------------------------------------------------------- + * X25_TRACE_CONFIGURE Command. + */ +typedef struct X25TraceCfg +{ + unsigned char flags PACKED; /* 00h: trace configuration flags */ + unsigned char timeout PACKED; /* 01h: timeout for trace delay mode*/ +} TX25TraceCfg; + +/* + * Defines for the 'flags' field. + */ +#define X25_TRC_ENABLE 0x01 /* bit0: '1' - trace enabled */ +#define X25_TRC_TIMESTAMP 0x02 /* bit1: '1' - time stamping enabled*/ +#define X25_TRC_DELAY 0x04 /* bit2: '1' - trace delay enabled */ +#define X25_TRC_DATA 0x08 /* bit3: '1' - trace data packets */ +#define X25_TRC_SUPERVISORY 0x10 /* bit4: '1' - trace suprvisory pkts*/ +#define X25_TRC_ASYNCHRONOUS 0x20 /* bit5: '1' - trace asynch. packets*/ +#define X25_TRC_HDLC 0x40 /* bit6: '1' - trace all packets */ +#define X25_TRC_READ 0x80 /* bit7: '1' - get current config. */ + +/* --------------------------------------------------------------------------- + * X25_READ_TRACE_DATA Command. + */ +typedef struct X25Trace /*----- Trace data structure -------*/ +{ + unsigned short length PACKED; /* 00h: trace data length */ + unsigned char type PACKED; /* 02h: trace type */ + unsigned char lost_cnt PACKED; /* 03h: N of traces lost */ + TX25TimeStamp tstamp PACKED; /* 04h: mon/date/sec/min/hour */ + unsigned short millisec PACKED; /* 09h: ms time stamp */ + unsigned char data[0] PACKED; /* 0Bh: traced frame */ +} TX25Trace; + +/* + * Defines for the 'type' field. + */ +#define X25_TRC_TYPE_MASK 0x0F /* bits 0..3: trace type */ +#define X25_TRC_TYPE_RX_FRAME 0x00 /* received frame trace */ +#define X25_TRC_TYPE_TX_FRAME 0x01 /* transmitted frame */ +#define X25_TRC_TYPE_ERR_FRAME 0x02 /* error frame */ + +#define X25_TRC_ERROR_MASK 0xF0 /* bits 4..7: error code */ +#define X25_TRCERR_RX_ABORT 0x10 /* receive abort error */ +#define X25_TRCERR_RX_BADCRC 0x20 /* receive CRC error */ +#define X25_TRCERR_RX_OVERRUN 0x30 /* receiver overrun error */ +#define X25_TRCERR_RX_TOO_LONG 0x40 /* excessive frame length error */ +#define X25_TRCERR_TX_ABORT 0x70 /* aborted frame transmittion error */ +#define X25_TRCERR_TX_UNDERRUN 0x80 /* transmit underrun error */ + +/***************************************************************************** + * Following definitions describe HDLC frame and X.25 packet formats. + ****************************************************************************/ + +typedef struct HDLCFrame /*----- DHLC Frame Format ----------*/ +{ + unsigned char addr PACKED; /* address field */ + unsigned char cntl PACKED; /* control field */ + unsigned char data[0] PACKED; +} THDLCFrame; + +typedef struct X25Pkt /*----- X.25 Paket Format ----------*/ +{ + unsigned char lcn_hi PACKED; /* 4 MSB of Logical Channel Number */ + unsigned char lcn_lo PACKED; /* 8 LSB of Logical Channel Number */ + unsigned char type PACKED; + unsigned char data[0] PACKED; +} TX25Pkt; + +/* + * Defines for the 'lcn_hi' field. + */ +#define X25_Q_BIT_MASK 0x80 /* Data Qualifier Bit mask */ +#define X25_D_BIT_MASK 0x40 /* Delivery Confirmation Bit mask */ +#define X25_M_BITS_MASK 0x30 /* Modulo Bits mask */ +#define X25_LCN_MSB_MASK 0x0F /* LCN most significant bits mask */ + +/* + * Defines for the 'type' field. + */ +#define X25PKT_DATA 0x01 /* Data packet mask */ +#define X25PKT_SUPERVISORY 0x02 /* Supervisory packet mask */ +#define X25PKT_CALL_RQST 0x0B /* Call Request/Incoming */ +#define X25PKT_CALL_ACCEPTED 0x0F /* Call Accepted/Connected */ +#define X25PKT_CLEAR_RQST 0x13 /* Clear Request/Indication */ +#define X25PKT_CLEAR_CONFRM 0x17 /* Clear Confirmation */ +#define X25PKT_RESET_RQST 0x1B /* Reset Request/Indication */ +#define X25PKT_RESET_CONFRM 0x1F /* Reset Confirmation */ +#define X25PKT_RESTART_RQST 0xFB /* Restart Request/Indication */ +#define X25PKT_RESTART_CONFRM 0xFF /* Restart Confirmation */ +#define X25PKT_INTERRUPT 0x23 /* Interrupt */ +#define X25PKT_INTERRUPT_CONFRM 0x27 /* Interrupt Confirmation */ +#define X25PKT_DIAGNOSTIC 0xF1 /* Diagnostic */ +#define X25PKT_REGISTR_RQST 0xF3 /* Registration Request */ +#define X25PKT_REGISTR_CONFRM 0xF7 /* Registration Confirmation */ +#define X25PKT_RR_MASKED 0x01 /* Receive Ready packet after masking */ +#define X25PKT_RNR_MASKED 0x05 /* Receive Not Ready after masking */ + + +typedef struct { + TX25Cmd cmd PACKED; + char data[X25_MAX_DATA] PACKED; +} mbox_cmd_t; + + +#if 0 +typedef struct { + unsigned char qdm PACKED; /* Q/D/M bits */ + unsigned char cause PACKED; /* cause field */ + unsigned char diagn PACKED; /* diagnostics */ + unsigned char pktType PACKED; + unsigned short length PACKED; + unsigned char result PACKED; + unsigned short lcn PACKED; + unsigned short mtu PACKED; + unsigned short mru PACKED; + char reserved[3] PACKED; +}x25api_hdr_t; + + +typedef struct { + x25api_hdr_t hdr PACKED; + char data[X25_MAX_DATA] PACKED; +}x25api_t; +#endif + +/* + * XPIPEMON Definitions + */ + +/* valid ip_protocol for UDP management */ +#define UDPMGMT_UDP_PROTOCOL 0x11 +#define UDPMGMT_XPIPE_SIGNATURE "XLINK8ND" +#define UDPMGMT_DRVRSTATS_SIGNATURE "DRVSTATS" + +/* values for request/reply byte */ +#define UDPMGMT_REQUEST 0x01 +#define UDPMGMT_REPLY 0x02 +#define UDP_OFFSET 12 + +#if 0 +typedef struct { + unsigned char opp_flag PACKED; /* the opp flag */ + unsigned char command PACKED; /* command code */ + unsigned short length PACKED; /* transfer data length */ + unsigned char result PACKED; /* return code */ + unsigned char pf PACKED; /* P/F bit */ + unsigned short lcn PACKED; /* logical channel */ + unsigned char qdm PACKED; /* Q/D/M bits */ + unsigned char cause PACKED; /* cause field */ + unsigned char diagn PACKED; /* diagnostics */ + unsigned char pktType PACKED; /* packet type */ + unsigned char resrv[4] PACKED; /* reserved */ +} cblock_t; + +typedef struct { + ip_pkt_t ip_pkt PACKED; + udp_pkt_t udp_pkt PACKED; + wp_mgmt_t wp_mgmt PACKED; + cblock_t cblock PACKED; + unsigned char data[4080] PACKED; +} x25_udp_pkt_t; +#endif + +typedef struct read_hdlc_stat { + unsigned short inf_frames_rx_ok PACKED; + unsigned short inf_frames_rx_out_of_seq PACKED; + unsigned short inf_frames_rx_no_data PACKED; + unsigned short inf_frames_rx_dropped PACKED; + unsigned short inf_frames_rx_data_too_long PACKED; + unsigned short inf_frames_rx_invalid_addr PACKED; + unsigned short inf_frames_tx_ok PACKED; + unsigned short inf_frames_tx_retransmit PACKED; + unsigned short T1_timeouts PACKED; + unsigned short SABM_frames_rx PACKED; + unsigned short DISC_frames_rx PACKED; + unsigned short DM_frames_rx PACKED; + unsigned short FRMR_frames_rx PACKED; + unsigned short SABM_frames_tx PACKED; + unsigned short DISC_frames_tx PACKED; + unsigned short DM_frames_tx PACKED; + unsigned short FRMR_frames_tx PACKED; +} read_hdlc_stat_t; + +typedef struct read_comms_err_stats{ + unsigned char overrun_err_rx PACKED; + unsigned char CRC_err PACKED; + unsigned char abort_frames_rx PACKED; + unsigned char frames_dropped_buf_full PACKED; + unsigned char abort_frames_tx PACKED; + unsigned char transmit_underruns PACKED; + unsigned char missed_tx_underruns_intr PACKED; + unsigned char reserved PACKED; + unsigned char DCD_drop PACKED; + unsigned char CTS_drop PACKED; +} read_comms_err_stats_t; + +typedef struct trace_data { + unsigned short length PACKED; + unsigned char type PACKED; + unsigned char trace_dropped PACKED; + unsigned char reserved[5] PACKED; + unsigned short timestamp PACKED; + unsigned int sec PACKED; + unsigned int usec PACKED; + unsigned char data[0] PACKED; +} trace_data_t; + +enum {UDP_XPIPE_TYPE}; + +#define XPIPE_ENABLE_TRACING 0x14 +#define XPIPE_DISABLE_TRACING 0x14 +#define XPIPE_GET_TRACE_INFO 0x16 +#define XPIPE_FT1_READ_STATUS 0x74 +#define XPIPE_DRIVER_STAT_IFSEND 0x75 +#define XPIPE_DRIVER_STAT_INTR 0x76 +#define XPIPE_DRIVER_STAT_GEN 0x77 +#define XPIPE_FLUSH_DRIVER_STATS 0x78 +#define XPIPE_ROUTER_UP_TIME 0x79 +#define XPIPE_SET_FT1_MODE 0x81 +#define XPIPE_FT1_STATUS_CTRL 0x80 + + +/* error messages */ +#define NO_BUFFS_OR_CLOSED_WIN 0x33 +#define DATA_LENGTH_TOO_BIG 0x32 +#define NO_DATA_AVAILABLE 0x33 +#define Z80_TIMEOUT_ERROR 0x0a +#define NO_BUFFS 0x08 + + +/* Trace options */ +#define TRACE_DEFAULT 0x03 +#define TRACE_SUPERVISOR_FRMS 0x10 +#define TRACE_ASYNC_FRMS 0x20 +#define TRACE_ALL_HDLC_FRMS 0x40 +#define TRACE_DATA_FRMS 0x08 + + +#endif /* _SDLA_X25_H */ diff -Nur linux.org/include/linux/sdla_xilinx.h linux-2.6.17/include/linux/sdla_xilinx.h --- linux.org/include/linux/sdla_xilinx.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/sdla_xilinx.h 2006-08-30 10:07:15.000000000 +0000 @@ -0,0 +1,1248 @@ +/***************************************************************************** +* sdla_xilinx.h WANPIPE(tm) S51XX Xilinx Hardware Support +* +* Authors: Nenad Corbic +* +* Copyright: (c) 2003 Sangoma Technologies Inc. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version +* 2 of the License, or (at your option) any later version. +* ============================================================================ +* Jan 07, 2003 Nenad Corbic Initial version. +*****************************************************************************/ + + +#ifndef _SDLA_XILINX_H +#define _SDLA_XILINX_H + + +/*====================================================== + * + * XILINX Chip PCI Registers + * + *=====================================================*/ + +/* Main configuration and status register */ +#define XILINX_CHIP_CFG_REG 0x40 + +/* Interface registers used to program + * board framer i.e. front end + * (PCM,Level1...) */ +#define XILINX_MCPU_INTERFACE 0x44 +#define XILINX_MCPU_INTERFACE_ADDR 0x46 + +#define XILINX_GLOBAL_INTER_MASK 0x4C + +/* HDLC interrupt pending registers used + * in case of an HDLC tx or rx abort condition */ +#define XILINX_HDLC_TX_INTR_PENDING_REG 0x50 +#define XILINX_HDLC_RX_INTR_PENDING_REG 0x54 + + +/* Possible RX packet errors */ +enum { + WP_FIFO_ERROR_BIT, + WP_CRC_ERROR_BIT, + WP_ABORT_ERROR_BIT, +}; + +/* Maximum number of frames in a fifo + * where frame lengths vary from 1 to 4 bytes */ +#define WP_MAX_FIFO_FRAMES 7 + + +/* DMA interrupt pending reg, used to + * signal dma tx/rx complete event on a + * specific channel */ +#define XILINX_DMA_TX_INTR_PENDING_REG 0x58 +#define XILINX_DMA_RX_INTR_PENDING_REG 0x5C + + +/* Timeslot addr reg (bits: 16-20) is used to access + * control memory in order to setup + * (physical) T1/E1 timeslot channels + * + * Logic (HDLC) Channel addr reg (bits: 0-4) is used to + * access HDLC Core internal registers. + * Used to access and configure each + * HDCL channel (tx and rx), + * in HDCL core.*/ +#define XILINX_TIMESLOT_HDLC_CHAN_REG 0x60 + +/* T3 Tx/Rx Channel Select + * + * 0=Tx Channel + * 1=Rx Channel */ +#define AFT_T3_RXTX_ADDR_SELECT_REG 0x60 + +#define XILINX_CURRENT_TIMESLOT_MASK 0x00001F00 +#define XILINX_CURRENT_TIMESLOT_SHIFT 8 + +/* HDLC data register used to + * access and configure HDLC core + * control status registers */ +#define XILINX_HDLC_CONTROL_REG 0x64 + +/* HDLC data register used to + * access and configure HDLC core + * address registers */ +#define XILINX_HDLC_ADDR_REG 0x68 + + +/* Control RAM data buffer, used to + * write/read data to/from control + * (chip) memory. + * + * The address of the memory access + * must be specified in XILINX_TIMESLOT_HDLC_CHAN_REG. + */ +#define XILINX_CONTROL_RAM_ACCESS_BUF 0x6C + + +/* Global DMA control register used to + * setup DMA engine */ +#define XILINX_DMA_CONTROL_REG 0x70 + +/* DMA tx status register is a bitmap + * status of each logical tx (HDLC) channel. + * + * Bit 0: Fifo full + * Bit 1: Fifo is ready to dma tx data from + * pci memory to tx fifo. + */ +#define XILINX_DMA_TX_STATUS_REG 0x74 + +/* TX Watchdog Timer Register + * + * Delay constant for watchdog + * timer. From 1 to 255. + * + * Minimum Interval = 1ms + * + * 0 =Reset/Disable Timer + * Ack Interrupt pending flag + * + * 1-255=Timer enabled 1ms intervals + * + * */ +#define AFT_TE3_TX_WDT_CTRL_REG 0x74 + +/* DMA rx status register is a bitmap + * status of each logical rx (HDLC) channel. + * + * Bit 0: Fifo is empty or not ready to + * dma data to pci memory. + * Bit 1: Fifo is ready to dma rx data + * into pci memory. + */ +#define XILINX_DMA_RX_STATUS_REG 0x78 + +/* RX Watchdog Timer Register + * + * Delay constant for watchdog + * timer. From 1 to 255. + * + * Minimum Interval = 1ms + * + * 0 =Reset/Disable Timer + * Ack Interrupt pending flag + * + * 1-255=Timer enabled 1ms intervals + * + * */ +#define AFT_TE3_RX_WDT_CTRL_REG 0x78 + + +/* TE3 Fractional Encapsulation Control + * Status Register + * + */ +#define TE3_FRACT_ENCAPSULATION_REG 0x7C + + +/* AFT TE3 Current DMA descriptor address + * + * Bit 0-3: Current Tx Dma Descr + * Bit 4-7: Current Rx Dma Descr + */ +#define AFT_TE3_CRNT_DMA_DESC_ADDR_REG 0x80 + + +/* DMA descritors, RAM 128x32 + * + * To be used as offsets to the TX/RX DMA + * Descriptor, based on the channel number. + * + * Addr = Channel_Number*0xF + Tx/Rx_DMA_DESCRIPTOR_LO/HI + * + * */ +#define XILINX_TxDMA_DESCRIPTOR_LO 0x100 +#define XILINX_TxDMA_DESCRIPTOR_HI 0x104 +#define XILINX_RxDMA_DESCRIPTOR_LO 0x108 +#define XILINX_RxDMA_DESCRIPTOR_HI 0x10C + + + + + +/*====================================================== + * XILINX_CHIP_CFG_REG Bit Map + * + * Main configuration and status register + *=====================================================*/ + +/* Select between T1/T3 or E1/E3 front end + * Bit=0 : T1/T3 Bit=1 : E1/E3 */ +#define INTERFACE_TYPE_T1_E1_BIT 0 +#define INTERFACE_TYPE_T3_E3_BIT 0 + +/* Enable onboard led + * 0= On + * 1= Off */ +#define XILINX_RED_LED 1 + +/* T3 HDLC Controller Bit + * 0= HDLC mode + * 1= Transparent mode */ +#define AFT_T3_HDLC_TRANS_MODE 1 + +/* Enable frame flag generation on + * front end framers (T1/E1...) */ +#define FRONT_END_FRAME_FLAG_ENABLE_BIT 2 + +/* Select T3/E3 clock source + * 0=External/Normal + * 1=Internal/Master */ +#define AFT_T3_CLOCK_MODE 2 + + +/* Front End Ref Clock Bit + * 0=Use Oscillator to generate clock + * 1=Use the clock from the other TE1 port + * */ +#define AFT_TE1_FE_REF_CLOCK_BIT 3 + +/* Reset front end framer (T1/E1 ...) + * Bit=1: Rest Active */ +#define FRONT_END_RESET_BIT 4 + +/* Reset the whole chip logic except + * HDLC Core: Bit=1*/ +#define CHIP_RESET_BIT 5 + +/* Reset HDLC Core: Bit=1 */ +#define HDLC_CORE_RESET_BIT 6 + +/* HDLC core ready flag + * Bit=1: HDLC Core ready for operation + * Bit=0: HDLC Core in reset state */ +#define HDLC_CORE_READY_FLAG_BIT 7 + +/* Enable or Disable all chip interrupts + * Bit=1: Enable Bit=0: Disable */ +#define GLOBAL_INTR_ENABLE_BIT 8 + +/* Enable chip interrupt on any error event. + * Bit=1: Enable Bit=0: Disable */ +#define ERROR_INTR_ENABLE_BIT 9 + +/* Reload Xilinx firmware + * Used to re-configure xilinx hardware */ +#define FRONT_END_INTR_ENABLE_BIT 10 + +/* Channel/Timeslot synchronization + * (Used by VoIP) + * + */ +#define CHANNEL_TSLOT_SYNC_MASK 0xFFF0FFFF +#define CHANNEL_TSLOT_SYNC_SHIFT 16 + +/* Enable Tx/Rx Channel Timeslot synchronization + * Bit=0: Disabled Bit=1: Enabled + */ +#define ENABLE_CHANNEL_TSLOT_SYNC 21 + +/* Start Rx Channel Timeslot sync + * Bit=0: Stop Rx + * The rx channel will be disabled + * Bit=1: Start Rx + * Start reception with sync + */ +#define START_RX_CHANNEL_TSLOT_SYNC 22 + + +/* 8bit error type, used to check for + * chip error conditions. + * Value=0: Normal Value=non zero: Error */ +#define CHIP_ERROR_MASK 0x00FF0000 + +/* This bit indicates that Tx + * Watchdog timer interrupt pending + * flag is asserted. */ +#define AFT_TE3_TX_WDT_INTR_PND 26 + + +/* This bit indicates that Rx + * Watchdog timer interrupt pending + * flag is asserted. */ +#define AFT_TE3_RX_WDT_INTR_PND 27 + + +/* Front end interrupt status bit + * Bit=1: Interrupt requested */ +#define FRONT_END_INTR_FLAG 28 + +/* Security Status Flag + * Bit=1: Security compromised and + * chip will stop operation */ +#define SECURITY_STATUS_FLAG 29 + +/* Error interrupt status bit + * Bit=1: Error occured on chip */ +#define ERROR_INTR_FLAG 30 + + +/* DMA interrupt status bit + * Bit=1: DMA inter pending register + * not equal to 0. + * + * i.e. one of DMA channels has + * generated an interrupt */ +#define DMA_INTR_FLAG 31 + + +#define XILINX_GLOBAL_INTER_STATUS 0xD0000000 + + +/*====================================================== + * XILINX_TIMESLOT_HDLC_CHAN_REG Bit Map + * + * Timeslot addr reg (bits: 16-20) is used to access + * control memory in order to setup + * (physical) T1/E1 timeslot channels + * + * Logic (HDLC) Channel addr reg (bits: 0-4) is used to + * access HDLC Core internal registers. + * Used to access and configure each + * HDCL channel (tx and rx), + * in HDCL core. + *=====================================================*/ + +/* Bit shift timeslot value (0-31) to the + * appropriate register location + * Bits: 16-20 */ +#define TIMESLOT_BIT_SHIFT 16 +#define TIMESLOT_BIT_MASK 0x001F0000 +#define HDLC_LOGIC_CH_BIT_MASK 0x0000001F + +#define HDLC_LCH_TIMESLOT_MASK 0x001F001F + +/*====================================================== + * XILINX_HDLC_CONTROL_REG + * + *=====================================================*/ + +/*======================================= + * HDLC RX Channel Status bits: 0-4 + * Indicate status of single, specified + * HDLC channel */ + +/* Status of rx channel: 1=inactive 0=active */ +#define HDLC_RX_CHAN_ENABLE_BIT 0 + +/* Rx status of a channel: + * 1=frame receiving 0=not receiving*/ +#define HDLC_RX_FRAME_DATA_BIT 1 + +/* Indicates data on HDLC channel + * 1=data present 0=idle (all 1) */ +#define HDLC_RC_CHAN_ACTIVE_BIT 2 + +/* Indicates that last frame contained an error. + * 1=frame error 0=no frame error */ +#define HDLC_RX_FRAME_ERROR_BIT 3 + +/* Indicates that last frame was aborted + * 1=frame aborted 0=frame not aborted */ +#define HDLC_RX_FRAME_ABORT_BIT 4 + + + +/*======================================= + * HDLC RX Channel Control bits: 16-21 + * Used to configure a single, specified + * rx HDLC channel */ + +/* Enable or disable HDLC protocol on + * specified channel. + * 1: Transpared Mode 0: HDLC enabled */ +#define HDLC_RX_PROT_DISABLE_BIT 16 + +/* HDLC Address recognition disable bit + * 1: No address matching (default) + * 0: normal address matching */ +#define HDLC_RX_ADDR_RECOGN_DIS_BIT 17 + +/* HDLC Address filed discard + * 1: addr filed in rx frame discarded + * 0: addr filed in rx frame passed up (dflt) */ +#define HDLC_RX_ADDR_FIELD_DISC_BIT 18 + +/* HDLC Address size + * 1: 16 bit 0: 8 bit */ +#define HDLC_RX_ADDR_SIZE_BIT 19 + +/* HDLC broadcast address matching + * 1: disable (does not match all 1's brdcst) + * 0: enable (dflt) */ +#define HDLC_RX_BRD_ADDR_MATCH_BIT 20 + +/* FCS Size + * 1: CRC-32 0: CRC-16 (default) */ +#define HDLC_RX_FCS_SIZE_BIT 21 + + +/* Idle flags are present on rx line + * 1: Idle present 0: no idle flags */ +#define HDLC_CORE_RX_IDLE_LINE_BIT 22 + +/* Abort flags are present on rx line + * 1: Abort present 0: no aborts */ +#define HDLC_CODE_RX_ABORT_LINE_BIT 23 + + + +/*======================================= + * HDLC TX Channel Control bits: 24-31 + * Used to configure a single, specified + * tx HDLC channel */ + +/* Enable or disable a specified + * HDLC tx channel. + * 1: Channel Enabled + * 0: Channel Disabled + * (tx idle all 1's in transparent mode + * (tx idle 7E in hdlc mode) */ +#define HDLC_TX_CHAN_ENABLE_BIT 24 + +/* Enable or disable HDLC protocol on + * specified tx channel. + * 1: Transpared Mode 0: HDLC enabled */ +#define HDLC_TX_PROT_DISABLE_BIT 25 + + +/* HDLC address insertion + * 1: enable 0: disable (default) */ +#define HDLC_TX_ADDR_INSERTION_BIT 26 + + +/* HDLC Tx Address size + * 1: 16 bit 0: 8 bit */ +#define HDLC_TX_ADDR_SIZE_BIT 27 + + +/* FCS Size + * 1: CRC-32 0: CRC-16 (default) */ +#define HDLC_TX_FCS_SIZE_BIT 28 + +/* Frame abort in progres or force it + * 1: frame abort 0: normal + * Set to 1 to FORCE tx frame abort */ +#define HDLC_TX_FRAME_ABORT_BIT 29 + +/* Stop tx operation on frame abort + * 1: enable 0: disable (default)*/ +#define HDLC_TX_STOP_TX_ON_ABORT_BIT 30 + +/* 1: transmit channel enabled + * 0: tx frame started */ +#define HDLC_TX_CHANNEL_ACTIVE_BIT 31 + + + +/*======================================= + * XILINX_CONTROL_RAM_ACCESS_BUF bit map + * + * Control RAM data buffer, used to + * write/read data to/from control + * (chip) memory. + * + * The address of the memory access + * must be specified in + * XILINX_TIMESLOT_HDLC_CHAN_REG. + *======================================*/ + +#define CONTROL_RAM_DATA_MASK 0x0000001F + +/* Used to define the start address of + * the fifo, per logic channel */ +#define HDLC_FIFO_BASE_ADDR_SHIFT 16 +#define HDLC_FIFO_BASE_ADDR_MASK 0x1F + +/* Used to define the size of the + * channel fifo */ +#define HDLC_FIFO_SIZE_SHIFT 8 +#define HDLC_FIFO_SIZE_MASK 0x1F + +#define HDLC_FREE_LOGIC_CH 31 +#define TRANSPARENT_MODE_BIT 31 + +/*======================================= + * XILINX_DMA_CONTROL_REG bit map + * + * Global DMA control register used to + * setup DMA engine + *======================================*/ + +#define DMA_SIZE_BIT_SHIFT 0 + +/* Limit used by rx dma engine + * to trigger rx dma */ +#define DMA_FIFO_HI_MARK_BIT_SHIFT 4 + +/* Limit used by tx dma engine + * to trigger tx dma */ +#define DMA_FIFO_LO_MARK_BIT_SHIFT 8 +#define DMA_FIFO_T3_MARK_BIT_SHIFT 8 + +/* Number of active DMA channel + * pars tx/rx used: i.e. 1=1tx+1rx */ +#define DMA_ACTIVE_CHANNEL_BIT_SHIFT 16 +#define DMA_ACTIVE_CHANNEL_BIT_MASK 0xFFE0FFFF + +/* Enable or Disable DMA engine + * 1: enable 0: disable */ +#define DMA_ENGINE_ENABLE_BIT 31 + +/* Maximum size of DMA chain for + * Tx and Rx TE3 adapter + * + * 0=1 + * 1=2 + * ... + * Current maximumx 15= 16 descriptors + * per chain. + */ +#define DMA_CHAIN_TE3_MASK 0x0000000F + +/*======================================== + * XILINX_TxDMA_DESCRIPTOR_LO + * XILINX_TxDMA_DESCRIPTOR_HI + * + * TX DMA descritors Bit Map + *=======================================*/ + +/* Pointer to PC memory, i.e. pointer to + * start of a tx data frame in PC. + * Note: Pointer address must end with binary 00. + * i.e. 32 bit alignment */ +#define TxDMA_LO_PC_ADDR_PTR_BIT_MASK 0xFFFFFFFC + + +/* The tx data frame length must defined + * in increments of 32bits words. The + * alignment is used to specify real lenght + * of frames. Offset from the 32bit boundary + * + * Eg: Alignment 0x10 defines the on last + * word of tx data frame only two + * bytes are valid, and the rest is padding. + * + * N * 32 bit + * ---------------------------- + * | | + * | | + * | | | | | Last 32bit word of data + * ---------------------------- + * 11 10 01 00 : Memory Byte offset (binary) + * + * Alignment Value (binary) + * v v v v : 00 + * p p p v : 01 + * p p v v : 10 + * p v v v : 11 + * + * v=valid data byte + * p=pad value + */ +#define TxDMA_LO_ALIGNMENT_BIT_MASK 0x00000003 + + +/* Length of tx data dma block + * defined in 32bit words increments */ +#define TxDMA_HI_DMA_DATA_LENGTH_MASK 0x000007FF + +/* DMA status bits: 11-14 + * 0: Normal Operation */ +#define TxDMA_HI_DMA_PCI_ERROR_MASK 0x00007800 +#define TxDMA_HI_DMA_PCI_ERROR_M_ABRT 0x00000800 +#define TxDMA_HI_DMA_PCI_ERROR_T_ABRT 0x00001000 +#define TxDMA_HI_DMA_PCI_ERROR_DS_TOUT 0x00002000 +#define TxDMA_HI_DMA_PCI_ERROR_RETRY_TOUT 0x00004000 + +/* DMA cmd used to initialize fifo */ +#define INIT_DMA_FIFO_CMD_BIT 28 + + +/* Used to indicate that the first byte + * of tx DMA frame should trigger an + * HDLC frame start flag. + * 1: Enable */ +#define TxDMA_HI_DMA_FRAME_START_BIT 30 + + +/* Used to indicate that the last byte + * of tx DMA frame should trigger an + * HDLC frame end flag. + * 1: Enable */ +#define TxDMA_HI_DMA_FRAME_END_BIT 29 + +/* Used to trigger DMA operation for + * this channel + * Write bit Read bit + * 1: Start dma or dma active + * 0: Stop dma or dma stopped */ +#define TxDMA_HI_DMA_GO_READY_BIT 31 + + +/* Used to define the start address of + * the fifo, per logic channel */ +#define DMA_FIFO_BASE_ADDR_SHIFT 20 +#define DMA_FIFO_BASE_ADDR_MASK 0x1F + +/* Used to define the size of the + * channel fifo */ +#define DMA_FIFO_SIZE_SHIFT 15 +#define DMA_FIFO_SIZE_MASK 0x1F + +/* This mask us used to clear both + * base addres and fifo size from + * the DMA descriptor */ +#define DMA_FIFO_PARAM_CLEAR_MASK 0xFE007FFF + +#define FIFO_32B 0x00 +#define FIFO_64B 0x01 +#define FIFO_128B 0x03 +#define FIFO_256B 0x07 +#define FIFO_512B 0x0F +#define FIFO_1024B 0x1F + + +/*======================================== + * XILINX_RxDMA_DESCRIPTOR_LO + * XILINX_RxDMA_DESCRIPTOR_HI + * + * RX DMA descritors Bit Map + *=======================================*/ + +/* Pointer to PC memory, i.e. pointer to + * start of a rx data buffer in PC. + * Note: Pointer address must end with binary 00. + * i.e. 32 bit alignment */ +#define RxDMA_LO_PC_ADDR_PTR_BIT_MASK 0xFFFFFFFC + + +/* The alignment is used to specify real lenght + * of a rx data frame. Offset from the 32bit boundary. + * + * Eg: Alignment 10 (binary) indicates that last + * word of rx data frame only two + * bytes are valid, and the rest is padding. + * + * N * 32 bit + * ---------------------------- + * | | + * | | + * | | | | | Last 32bit word of data + * ---------------------------- + * 11 10 01 00 : Memory Byte offset (binary) + * + * Alignment Value (binary) + * v v v v : 11 + * p v v v : 01 + * p p v v : 10 + * p p p v : 00 + * + * v=valid data byte + * p=pad value + * + * MaxLength=User specifed maximum rx + * buffer size + * + * Length =After DMA rx interrupt, length + * will indicate number of bytes + * left in user buffer + * + * Alignment=After DMA rx interrupt, indicates + * number of padded bytes to 32bit + * boundary. + * + * Real Frame Len (in bytes)= + * (MaxLength-Length)*4 - ~(Alignment); + */ +#define RxDMA_LO_ALIGNMENT_BIT_MASK 0x00000003 + + +/* Length of rx data dma block + * defined in 32bit words increments */ +#define RxDMA_HI_DMA_DATA_LENGTH_MASK 0x000007FF + +/* DMA status bits: 16-21 + * 0: Normal Operation */ +#define RxDMA_HI_DMA_PCI_ERROR_MASK 0x00007800 +#define RxDMA_HI_DMA_PCI_ERROR_M_ABRT 0x00000800 +#define RxDMA_HI_DMA_PCI_ERROR_T_ABRT 0x00001000 +#define RxDMA_HI_DMA_PCI_ERROR_DS_TOUT 0x00002000 +#define RxDMA_HI_DMA_PCI_ERROR_RETRY_TOUT 0x00004000 + + +/* Not used */ +#define RxDMA_HI_DMA_COMMAND_BIT_SHIFT 28 + + +/* Used to indicate that the frame + * start flags exists, this is the + * first DMA transfer of an HDLC frame. + * 1: Frame start event 0: No frame start */ +#define RxDMA_HI_DMA_FRAME_START_BIT 30 + + +/* Indicates that crc error occured + * on the last frame + * 1: crc error 0: no error */ +#define RxDMA_HI_DMA_CRC_ERROR_BIT 25 + + +/* Indicates that HDLC rx abort flag + * from the line + * 1: abort occured 0: normal */ +#define RxDMA_HI_DMA_FRAME_ABORT_BIT 26 + + +/* Used to indicate that the frame + * end flags exists, this is the + * last DMA transfer of an HDLC frame. + * + * 1: Frame end event 0: No frame end */ +#define RxDMA_HI_DMA_FRAME_END_BIT 29 + +/* Used to trigger DMA operation for + * this channel + * Write bit Read bit + * 1: Start dma or dma active + * 0: Stop dma or dma stopped */ +#define RxDMA_HI_DMA_GO_READY_BIT 31 + + +/* TE3 Only bit maps for TX and RX + * Descriptors + * + * Interrupt Disable Bit + * + * 1: Interrpupt doesn't get generated + * after the end of dma descriptor. + * + * 0: Generate interrupt after + * dma descriptor + */ +#define DMA_HI_TE3_INTR_DISABLE_BIT 27 + +/* Last Frame Bit + * + * 1: This dma descr is not last thus + * proceed to the next dma chain + * + * 0: This dma descr is last in the + * dma chain. Do not go to the + * next dma desc. + * + */ +#define DMA_HI_TE3_NOT_LAST_FRAME_BIT 24 + + + +/*======================================== + * TE3_FRACT_ENCAPSULATION_REG + * + * TE3 Fractional Encapsulaton + * Control/Status Register + *=======================================*/ + + +/* RX Section */ + +/* Read Only + * Rx Encasulated Frame Size Status + * + * Used to determine the tx encasulated + * frame size + */ +#define TE3_RX_FRACT_FRAME_SIZE_SHIFT 0 +#define TE3_RX_FRACT_FRAME_SIZE_MASK 0x000000FF + + +/* Read Only + * Rx Encapsulation CRC Cnt + * + * TE3 Fractionalization is a two stage + * HDLC process. This is a crc count of + * the first stage! + */ +#define TE3_RX_FRACT_CRC_ERR_CNT_SHIFT 8 +#define TE3_RX_FRACT_CRC_ERR_CNT_MASK 0x0000FF00 + +/* TX Section */ + +/* Tx Fractional baud rate + * + * This is a 14 bit counter, used to + * specify the period of tx buffers. + * + * The period is used to thorttle the + * tx speed from 1 to 35Mhz. + */ +#define TE3_TX_FRACT_BAUD_RATE_SHIFT 16 +#define TE3_TX_FRACT_BAUD_RATE_MASK 0xFF80FFFF + + +/* Tx Encasulated Frame Size + * + * Used to SET the tx encasulated + * frame size + * + * The Tx size must be equal to the + * above RX size MINUS 3 bytes. + * (Because of CRC and address) + */ +#define TE3_TX_FRACT_FRAME_SIZE_SHIFT 24 +#define TE3_TX_FRACT_FRAME_SIZE_MASK 0x00FFFFFF + + + + +/*======================================= + * AFT_TE3_CRNT_DMA_DESC_ADDR_REG + * + */ + +#define AFT_TE3_CRNT_TX_DMA_MASK 0x0000000F + +#define AFT_TE3_CRNT_RX_DMA_MASK 0x000000F0 +#define AFT_TE3_CRNT_RX_DMA_SHIFT 4 + + + + +/*=============================================== + */ + + +typedef struct xilinx_config +{ + unsigned long xilinx_chip_cfg_reg; + unsigned long xilinx_dma_control_reg; + +}xilinx_config_t; + + +/* Default length of the DMA burst + * Value indicates the maximum number + * of DMA transactions per burst */ +#define XILINX_DMA_SIZE 10 + +/* Used by DMA engine to transfer data from Fifo to PC. + * DMA engine start rx when fifo level becomes greater + * than the DMA FIFI UP value */ +#define XILINX_DMA_FIFO_UP 8 + +/* Used by DMA engine to transfer data from PC to Fifo. + * DMA engine start tx when free space in the fifo + * becomes greater than DMA FIFO LO value */ +#define XILINX_DMA_FIFO_LO 8 + +/* Used by DMA engine to transfer data from PC to Fifo. + * DMA engine start tx/rx when fifo is greater/lower + * than the DMA FIFO MARK value */ +#define AFT_T3_DMA_FIFO_MARK 8 + +/* Default Active DMA channel used by the + * DMA Engine */ +#define XILINX_DEFLT_ACTIVE_CH 0 + +#define MAX_XILINX_TX_DMA_SIZE 0xFFFF + +#define MIN_WP_PRI_MTU 8 +#define DEFAULT_WP_PRI_MTU 1500 + +/* Maximum MTU for AFT card + * 8192-4=8188. This is a hardware + * limitation. + */ +#define MAX_WP_PRI_MTU 8188 + +#define MAX_DMA_PER_CH 20 +#define MIN_DMA_PER_CH 2 + +#if 0 +All defines moved to if_wanpipe.h +enum { +#if defined(__LINUX__) + SIOC_WAN_READ_REG = SIOC_ANNEXG_PLACE_CALL, +#else + SDLA_HDLC_READ_REG = 0, /* FIXME !!!*/ +#endif + SIOC_WAN_WRITE_REG, + SIOC_WAN_ALL_READ_REG, + SIOC_WAN_ALL_WRITE_REG, + SIOC_WAN_SET_PCI_BIOS, + SIOC_WAN_GET_CFG +}; +#endif + +#pragma pack(1) +typedef struct { + unsigned char error_flag; + unsigned short time_stamp; + unsigned short channel; + unsigned char reserved[11]; +} api_rx_hdr_t; + +typedef struct { + api_rx_hdr_t api_rx_hdr; + unsigned char data[1]; +} api_rx_element_t; + +typedef struct { + unsigned char attr; + unsigned char misc_Tx_bits; + unsigned char reserved[14]; +} api_tx_hdr_t; + +typedef struct { + api_tx_hdr_t api_tx_hdr; + unsigned char data[1]; +} api_tx_element_t; +#pragma pack() + +#undef wan_udphdr_data +#define wan_udphdr_data wan_udphdr_u.aft.data + +/*========================================== + * Board CPLD Interface Section + * + *=========================================*/ + + +#define PMC_CONTROL_REG 0x00 + +/* Used to reset the pcm + * front end + * 0: Reset Enable + * 1: Normal Operation + */ +#define PMC_RESET_BIT 0 + +/* Used to set the pmc clock + * source: + * 0 = E1 + * 1 = T1 + */ +#define PMC_CLOCK_SELECT 1 + +#define LED_CONTROL_REG 0x01 + +#define JP8_VALUE 0x02 +#define JP7_VALUE 0x01 +#define SW0_VALUE 0x04 +#define SW1_VALUE 0x08 + + +#define SECURITY_CPLD_REG 0x09 +#define CUSTOMER_CPLD_ID_REG 0x0A + +#define SECURITY_CPLD_MASK 0x03 +#define SECURITY_CPLD_SHIFT 0x02 + +#define SECURITY_1LINE_UNCH 0x00 +#define SECURITY_1LINE_CH 0x01 +#define SECURITY_2LINE_UNCH 0x02 +#define SECURITY_2LINE_CH 0x03 + +#define WAN_AFT_SECURITY(sec) \ + ((sec) == SECURITY_1LINE_UNCH) ? "Unchannelized!" :\ + ((sec) == SECURITY_1LINE_CH) ? "Channelized!" :\ + ((sec) == SECURITY_2LINE_UNCH) ? "Unchannelized!" :\ + ((sec) == SECURITY_2LINE_CH) ? "Channelized!" :\ + "Unknown" + +/* -------------------------------------- */ + +#define WRITE_DEF_SECTOR_DSBL 0x01 +#define FRONT_END_TYPE_MASK 0x38 + +#define BIT_DEV_ADDR_CLEAR 0x600 +#define BIT_DEV_ADDR_CPLD 0x200 + +#define MEMORY_TYPE_SRAM 0x00 +#define MEMORY_TYPE_FLASH 0x01 +#define MASK_MEMORY_TYPE_SRAM 0x10 +#define MASK_MEMORY_TYPE_FLASH 0x20 + +#define BIT_A18_SECTOR_SA4_SA7 0x20 +#define USER_SECTOR_START_ADDR 0x40000 + +#define MAX_TRACE_QUEUE 100 + +#define MAX_TRACE_BUFFER (MAX_LGTH_UDP_MGNT_PKT - \ + sizeof(iphdr_t) - \ + sizeof(udphdr_t) - \ + sizeof(wan_mgmt_t) - \ + sizeof(wan_trace_info_t) - \ + sizeof(wan_cmd_t)) +enum { + TX_DMA_BUF_INIT =0, + TX_DMA_BUF_USED +}; + +enum { + ROUTER_UP_TIME = 0x50, + ENABLE_TRACING, + DISABLE_TRACING, + GET_TRACE_INFO, + READ_CODE_VERSION, + FLUSH_OPERATIONAL_STATS, + OPERATIONAL_STATS, + READ_OPERATIONAL_STATS, + READ_CONFIGURATION, + READ_COMMS_ERROR_STATS, + FLUSH_COMMS_ERROR_STATS, + AFT_LINK_STATUS, + AFT_MODEM_STATUS, + AFT_HWEC_STATUS +}; + +#define UDPMGMT_SIGNATURE "AFTPIPEA" + +/* the line trace status element presented by the frame relay code */ +typedef struct { + unsigned char flag ; /* ready flag */ + unsigned short length ; /* trace length */ + unsigned char rsrv0[2] ; /* reserved */ + unsigned char attr ; /* trace attributes */ + unsigned short tmstamp ; /* time stamp */ + unsigned char rsrv1[4] ; /* reserved */ + unsigned long offset ; /* buffer absolute address */ +}aft_trc_el_t; + + +typedef struct wp_rx_element +{ + unsigned long dma_addr; + unsigned int reg; + unsigned int align; + unsigned char pkt_error; +}wp_rx_element_t; + + +#if defined(WAN_KERNEL) + +static __inline void +set_te3_tx_fract_baud_rate(u32 *reg, + unsigned long bitrate_khz, + unsigned int buffer_size, + unsigned char e3) +{ + /* Period for T3 and E3 clock in ns */ + unsigned long period_ns=e3?29:22; + unsigned long data_period_ns=0; + unsigned long counter=0; + + /* Get the number of bits */ + buffer_size*=8; + + data_period_ns=(buffer_size*1000000)/bitrate_khz; + + counter=data_period_ns/period_ns; + + counter=(counter>>7)&0x7F; + + *reg&=TE3_TX_FRACT_BAUD_RATE_MASK; + *reg|=(counter<>TE3_RX_FRACT_CRC_ERR_CNT_SHIFT); +} + + +static __inline void +set_te3_tx_fract_frame_size(u32 *reg, unsigned int frame_size) +{ + *reg&=TE3_TX_FRACT_FRAME_SIZE_MASK; + *reg|=(frame_size-3)<hw_iface.bus_write_4(card->hw,AFT_TE3_RX_WDT_CTRL_REG,0); +} + +static __inline void aft_enable_rx_watchdog(sdla_t *card, unsigned char timeout) +{ + aft_reset_rx_watchdog(card); + card->hw_iface.bus_write_4(card->hw,AFT_TE3_RX_WDT_CTRL_REG,timeout); +} + +static __inline void aft_reset_tx_watchdog(sdla_t *card) +{ + card->hw_iface.bus_write_4(card->hw,AFT_TE3_TX_WDT_CTRL_REG,0); +} + +static __inline void aft_enable_tx_watchdog(sdla_t *card, unsigned char timeout) +{ + aft_reset_tx_watchdog(card); + card->hw_iface.bus_write_4(card->hw,AFT_TE3_TX_WDT_CTRL_REG,timeout); +} + +#endif /* WAN_KERNEL */ + + +#if defined(__LINUX__) +enum { + SIOC_AFT_CUSTOMER_ID = SIOC_WANPIPE_DEVPRIVATE +}; +#endif + +#pragma pack(1) + +/* the operational statistics structure */ +typedef struct { + + /* Data frame transmission statistics */ + unsigned long Data_frames_Tx_count ; + /* # of frames transmitted */ + unsigned long Data_bytes_Tx_count ; + /* # of bytes transmitted */ + unsigned long Data_Tx_throughput ; + /* transmit throughput */ + unsigned long no_ms_for_Data_Tx_thruput_comp ; + /* millisecond time used for the Tx throughput computation */ + unsigned long Tx_Data_discard_lgth_err_count ; + + /* Data frame reception statistics */ + unsigned long Data_frames_Rx_count ; + /* number of frames received */ + unsigned long Data_bytes_Rx_count ; + /* number of bytes received */ + unsigned long Data_Rx_throughput ; + /* receive throughput */ + unsigned long no_ms_for_Data_Rx_thruput_comp ; + /* millisecond time used for the Rx throughput computation */ + unsigned long Rx_Data_discard_short_count ; + /* received Data frames discarded (too short) */ + unsigned long Rx_Data_discard_long_count ; + /* received Data frames discarded (too long) */ + unsigned long Rx_Data_discard_inactive_count ; + /* received Data frames discarded (link inactive) */ + + /* Incomming frames with a format error statistics */ + unsigned short Rx_frm_incomp_CHDLC_hdr_count ; + /* frames received of with incomplete Cisco HDLC header */ + unsigned short Rx_frms_too_long_count ; + /* frames received of excessive length count */ + + /* CHDLC link active/inactive and loopback statistics */ + unsigned short link_active_count ; + /* number of times that the link went active */ + unsigned short link_inactive_modem_count ; + /* number of times that the link went inactive (modem failure) */ + unsigned short link_inactive_keepalive_count ; + /* number of times that the link went inactive (keepalive failure) */ + unsigned short link_looped_count ; + /* link looped count */ + + unsigned long Data_frames_Tx_realign_count; + +} aft_op_stats_t; + +typedef struct { + unsigned int Rx_overrun_err_count; + unsigned int Rx_crc_err_count ; /* receiver CRC error count */ + unsigned int Rx_abort_count ; /* abort frames recvd count */ + unsigned int Rx_hdlc_corrupiton; /* receiver disabled */ + unsigned int Rx_pci_errors; /* missed tx underrun interrupt count */ + unsigned int Rx_dma_descr_err; /*secondary-abort frames tx count */ + unsigned int DCD_state_change_count ; /* DCD state change */ + unsigned int CTS_state_change_count ; /* CTS state change */ + + unsigned int Tx_pci_errors; /* missed tx underrun interrupt count */ + unsigned int Tx_dma_errors; /* missed tx underrun interrupt count */ + unsigned int Tx_pci_latency; /* missed tx underrun interrupt count */ + unsigned int Tx_dma_len_nonzero; /* Tx dma descriptor len not zero */ +} aft_comm_err_stats_t; + + + +#pragma pack() + + +#endif diff -Nur linux.org/include/linux/sfmdef.h linux-2.6.17/include/linux/sfmdef.h --- linux.org/include/linux/sfmdef.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/sfmdef.h 2006-08-30 10:07:15.000000000 +0000 @@ -0,0 +1,96 @@ +#ifndef _SFMDEF_H +#define _SFMDEF_H +/***************************************************************************** +* FILE: sfmdef.h SDLA Firmware Module Definitions +* AUTHOR: Gene Kozin +* ---------------------------------------------------------------------------- +* (c) Copyright 1995-1996 Sangoma Technologies Inc. All Rights Reserved. +* ============================================================================ +* Rev.# Date Who Details +* ----- ----------- --- ---------------------------------------------- +* 2.00 Apr.16,1996 GK Changed adapter & firmware codes. +* 1.01 Dec.15,1995 GK +* 1.00 Nov.09,1995 GK Initial version. +*****************************************************************************/ + +/****** Defines *************************************************************/ + +#define SFM_VERSION 2 +#define SFM_SIGNATURE "SFM - Sangoma SDLA Firmware Module" + +/* + *----- Min/Max -------------------------------------------------------------- + */ +#define SFM_IMAGE_SIZE 0x8000 /* max size of SDLA code image file */ +#define SFM_DESCR_LEN 256 /* max length of description string */ +#define SFM_MAX_SDLA 16 /* max number of compatible adapters */ + +/* + *----- Adapter Types -------------------------------------------------------- + */ +#ifndef SDLA_TYPES +# define SDLA_TYPES +# define SDLA_S502A 5020 +# define SDLA_S502E 5021 +# define SDLA_S503 5030 +# define SDLA_S508 5080 +# define SDLA_S507 5070 +# define SDLA_S509 5090 +#endif /* SDLA_TYPES */ + +/* + *----- Firmware Identification Numbers -------------------------------------- + * 0 .. 999 Test & Diagnostics + * 1000 .. 1999 Streaming HDLC + * 2000 .. 2999 Bisync + * 3000 .. 3999 SDLC + * 4000 .. 4999 HDLC + * 5000 .. 5999 X.25 + * 6000 .. 6999 Frame Relay + * 7000 .. 7999 PPP + */ +#ifndef FIRMWARE_IDS +# define FIRMWARE_IDS +# define SFID_CALIB502 200 +# define SFID_STRM502 1200 +# define SFID_STRM508 1800 +# define SFID_BSC502 2200 +# define SFID_SDLC502 3200 +# define SFID_HDLC502 4200 +# define SFID_X25_502 5200 +# define SFID_FR502 6200 +# define SFID_FR508 6800 +# define SFID_PPP502 7200 +# define SFID_PPP508 7800 +#endif /* FIRMWARE_IDS */ + +/****** Data Types **********************************************************/ + +typedef struct SFMInfo /* SDLA Firmware Module Information Block */ +{ + unsigned short codeid; /* firmware ID */ + unsigned short version; /* firmaware version number */ + unsigned short adapter[SFM_MAX_SDLA]; /* compatible adapter types */ + unsigned long memsize; /* minimum memory size */ + unsigned short reserved[2]; /* reserved */ + unsigned short startoffs; /* entry point offset */ + unsigned short winoffs; /* dual-port memory window offset */ + unsigned short codeoffs; /* code load offset */ + unsigned short codesize; /* code size */ + unsigned short dataoffs; /* configuration data load offset */ + unsigned short datasize; /* configuration data size */ +} SFMInfo_t; + +typedef struct SFM /* SDLA Firmware Module Structire */ +{ + char signature[80]; /* SFM file signature */ + unsigned short version; /* file format version */ + unsigned short checksum; /* info + image */ + unsigned short reserved[6]; /* reserved */ + char descr[SFM_DESCR_LEN]; /* optional description string */ + SFMInfo_t info; /* firmware module info */ + unsigned char image[0]; /* loadable code image */ +} SFM_t; + +#endif /* _SFMDEF_H */ + diff -Nur linux.org/include/linux/ss7_linux.h linux-2.6.17/include/linux/ss7_linux.h --- linux.org/include/linux/ss7_linux.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/ss7_linux.h 2006-08-30 10:07:15.000000000 +0000 @@ -0,0 +1,132 @@ +/************************************************************************* + ss7_linux.h Sangoma SS7 firmware API definitions + + Author: Gideon Hack + Nenad Corbic + + Copyright: (c) 1995-2000 Sangoma Technologies Inc. + + This program is free software; you can redistribute it and/or + modify it under the term of the GNU General Public License + as published by the Free Software Foundation; either version + 2 of the License, or (at your option) any later version. + +=========================================================================== + Dec 22, 2000 Gideon Hack Initial Verison + Jan 16, 2001 Gideon Hack Header updates +=========================================================================== + +Descripiton: + The 'C' header file for the Sangoma S508/S514 SS7 code API. + +****************************************************************************/ + +#ifndef _SS7_LINUX_H +#define _SS7_LINUX_H + +#ifndef PACKED +#define PACKED __attribute__((packed)) +#endif + +#include +#include + +enum { + SIOCC_PC_RESERVED = (SIOC_WANPIPE_DEVPRIVATE), + SIOCS_GENERAL_CMD, + SIOCS_CHECK_FRONT_STATE, + SIOC_RECEIVE, + SIOC_SEND, + SIOC_RECEIVE_WAIT, + SIOC_RECEIVE_AVAILABLE, + SIOC_RETRIEVE_MSU_BUFS +}; + +#define SS7_CMD_BLOCK_SZ (sizeof(wan_mbox_t)-1-SIZEOF_MB_DATA_BFR) + + +typedef struct { + unsigned char status PACKED; + unsigned char data_avail PACKED; + unsigned short real_length PACKED; + unsigned short time_stamp PACKED; + unsigned char data[1] PACKED; +} trace_pkt_t; + +typedef struct { + unsigned char SIO PACKED; + unsigned short time_stamp PACKED; + unsigned char reserved[13] PACKED; +} api_rx_hdr_t; + +typedef struct { + api_rx_hdr_t api_rx_hdr PACKED; + void * data PACKED; +} api_rx_element_t; + +typedef struct { + unsigned char SIO PACKED; + unsigned char reserved[15] PACKED; +} api_tx_hdr_t; + +typedef struct { + api_tx_hdr_t api_tx_hdr PACKED; + void * data PACKED; +} api_tx_element_t; + + +/* The embedded control block for UDP mgmt + This is essentially a mailbox structure, without the large data field */ +#if 0 +typedef struct { + unsigned char opp_flag PACKED; /* the opp flag */ + unsigned char command PACKED; /* the user command */ + unsigned short buffer_length PACKED; /* the data length */ + unsigned char return_code PACKED; /* the return code */ + unsigned char MB_reserved[NUMBER_MB_RESERVED_BYTES] PACKED; /* reserved for later */ +} cblock_t; + + +typedef struct { + unsigned char num_frames PACKED; + unsigned char ismoredata PACKED; +} trace_info_t; + +typedef struct { + ip_pkt_t ip_pkt PACKED; + udp_pkt_t udp_pkt PACKED; + wp_mgmt_t wp_mgmt PACKED; + cblock_t cblock PACKED; + trace_info_t trace_info PACKED; + unsigned char data[SIZEOF_MB_DATA_BFR] PACKED; +} ss7_udp_pkt_t; +#endif + +/* modem status changes */ +#define DCD_HIGH 0x08 +#define CTS_HIGH 0x20 + +/* Special UDP drivers management commands */ +#define SPIPE_ENABLE_TRACING 0x50 +#define SPIPE_DISABLE_TRACING 0x51 +#define SPIPE_GET_TRACE_INFO 0x52 +#define SPIPE_GET_IBA_DATA 0x53 +#define SPIPE_FT1_READ_STATUS 0x54 +#define SPIPE_DRIVER_STAT_IFSEND 0x55 +#define SPIPE_DRIVER_STAT_INTR 0x56 +#define SPIPE_DRIVER_STAT_GEN 0x57 +#define SPIPE_FLUSH_DRIVER_STATS 0x58 +#define SPIPE_ROUTER_UP_TIME 0x59 + +/* Driver specific commands for API */ +#define CHDLC_READ_TRACE_DATA 0xE4 /* read trace data */ +#define TRACE_ALL 0x00 +#define TRACE_PROT 0x01 +#define TRACE_DATA 0x02 + +#define UDPMGMT_UDP_PROTOCOL 0x11 +#define UDPMGMT_SIGNATURE "CTPIPEAB" /* "STPIPEAB" */ + + +#endif + diff -Nur linux.org/include/linux/wanec_iface.h linux-2.6.17/include/linux/wanec_iface.h --- linux.org/include/linux/wanec_iface.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/wanec_iface.h 2006-08-30 10:07:15.000000000 +0000 @@ -0,0 +1,444 @@ +/****************************************************************************** + * wanec_lip.h + * + * Author: Alex Feldman + * + * Copyright: (c) 1995-2001 Sangoma Technologies Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * ============================================================================ + ****************************************************************************** + */ + +#ifndef __WANEC_LIP_H +# define __WANEC_LIP_H + +#if defined(__LINUX__) +# include +#elif defined(__FreeBSD__) || defined(__OpenBSD__) +# include +#endif +#include "oct6100api/oct6100_api.h" + + +#define WANEC_DEV_DIR "/dev/" +#define WANEC_DEV_NAME "wanec" + +#define MAX_CHANNELS_LEN 50 + +#define MAX_PARAM_LEN 50 +#define MAX_VALUE_LEN 50 + +#define WAN_NUM_DTMF_TONES 16 +#define WAN_NUM_PLAYOUT_TONES 16 +#define WAN_MAX_TONE_LEN 100 + +#define WAN_EC_VERBOSE_NONE 0x00 +#define WAN_EC_VERBOSE_EXTRA1 0x01 +#define WAN_EC_VERBOSE_MASK_EXTRA1 0x01 +#define WAN_EC_VERBOSE_EXTRA2 0x02 +#define WAN_EC_VERBOSE_MASK_EXTRA2 0x03 +#define WAN_EC_VERBOSE(ec_api) (ec_api)?ec_api->verbose:WAN_EC_VERBOSE_NONE +#define PRINT(v, format,msg...) \ + DEBUG_EVENT(format, ##msg) +#define PRINT1(v,format,msg...) \ + if (v & WAN_EC_VERBOSE_EXTRA1) DEBUG_EVENT(format,##msg) +#define PRINT2(v,format,msg...) \ + if (v & WAN_EC_VERBOSE_EXTRA2) DEBUG_EVENT(format,##msg) + +#define WAN_OCT6100_RC_OK 0x0000 +#define WAN_OCT6100_RC_CPU_INTERFACE_NO_RESPONSE 0x0001 +#define WAN_OCT6100_RC_MEMORY 0x0002 + +/* WANPIPE EC API return code */ +#define WAN_EC_API_RC_OK 0x0000 +#define WAN_EC_API_RC_FAILED 0x0001 +#define WAN_EC_API_RC_INVALID_CMD 0x0002 +#define WAN_EC_API_RC_INVALID_STATE 0x0003 +#define WAN_EC_API_RC_INVALID_DEV 0x0004 +#define WAN_EC_API_RC_INVALID_CHANNELS 0x0005 +#define WAN_EC_API_RC_BUSY 0x0006 +#define WAN_EC_API_RC_NOACTION 0x0007 +#define WAN_EC_API_RC_DECODE(err) \ + (err == WAN_EC_API_RC_OK) ? "OK" : \ + (err == WAN_EC_API_RC_FAILED) ? "Failed" : \ + (err == WAN_EC_API_RC_INVALID_CMD) ? "Invalid Cmd" : \ + (err == WAN_EC_API_RC_INVALID_STATE) ? "Invalid State" : \ + (err == WAN_EC_API_RC_INVALID_DEV) ? "Invalid Device" : \ + (err == WAN_EC_API_RC_INVALID_CHANNELS) ? "Invalid Channels" : \ + (err == WAN_EC_API_RC_BUSY) ? "Busy" : \ + (err == WAN_EC_API_RC_NOACTION) ? "No action" : \ + "Unknown RC" + +/* OCT6100 state machine */ +enum { + WAN_OCT6100_STATE_NONE = 0x00, + WAN_OCT6100_STATE_RESET, + WAN_OCT6100_STATE_READY, + WAN_OCT6100_STATE_CHIP_OPEN_PENDING, + WAN_OCT6100_STATE_CHIP_OPEN, + WAN_OCT6100_STATE_CHIP_READY +}; +#define WAN_OCT6100_STATE_DECODE(state) \ + (state == WAN_OCT6100_STATE_RESET) ? "Reset" : \ + (state == WAN_OCT6100_STATE_READY) ? "Ready" : \ + (state == WAN_OCT6100_STATE_CHIP_OPEN_PENDING) ? "Chip Open Pending" : \ + (state == WAN_OCT6100_STATE_CHIP_OPEN) ? "Chip Open" : \ + (state == WAN_OCT6100_STATE_CHIP_READY) ? "Chip Ready" : \ + "Unknown" + +#define WAN_EC_SOUT_DTMF_1 0x40000011 +#define WAN_EC_SOUT_DTMF_2 0x40000012 +#define WAN_EC_SOUT_DTMF_3 0x40000013 +#define WAN_EC_SOUT_DTMF_A 0x4000001A +#define WAN_EC_SOUT_DTMF_4 0x40000014 +#define WAN_EC_SOUT_DTMF_5 0x40000015 +#define WAN_EC_SOUT_DTMF_6 0x40000016 +#define WAN_EC_SOUT_DTMF_B 0x4000001B +#define WAN_EC_SOUT_DTMF_7 0x40000017 +#define WAN_EC_SOUT_DTMF_8 0x40000018 +#define WAN_EC_SOUT_DTMF_9 0x40000019 +#define WAN_EC_SOUT_DTMF_C 0x4000001C +#define WAN_EC_SOUT_DTMF_STAR 0x4000001E +#define WAN_EC_SOUT_DTMF_0 0x40000010 +#define WAN_EC_SOUT_DTMF_POUND 0x4000001F +#define WAN_EC_SOUT_DTMF_D 0x4000001D +#define WAN_EC_ROUT_DTMF_1 0x10000011 +#define WAN_EC_ROUT_DTMF_2 0x10000012 +#define WAN_EC_ROUT_DTMF_3 0x10000013 +#define WAN_EC_ROUT_DTMF_A 0x1000001A +#define WAN_EC_ROUT_DTMF_4 0x10000014 +#define WAN_EC_ROUT_DTMF_5 0x10000015 +#define WAN_EC_ROUT_DTMF_6 0x10000016 +#define WAN_EC_ROUT_DTMF_B 0x1000001B +#define WAN_EC_ROUT_DTMF_7 0x10000017 +#define WAN_EC_ROUT_DTMF_8 0x10000018 +#define WAN_EC_ROUT_DTMF_9 0x10000019 +#define WAN_EC_ROUT_DTMF_C 0x1000001C +#define WAN_EC_ROUT_DTMF_STAR 0x1000001E +#define WAN_EC_ROUT_DTMF_0 0x10000010 +#define WAN_EC_ROUT_DTMF_POUND 0x1000001F +#define WAN_EC_ROUT_DTMF_D 0x1000001D +#define WAN_EC_DECODE_DTMF_ID(id) \ + (id == WAN_EC_SOUT_DTMF_0) ? "SOUT_0" : \ + (id == WAN_EC_SOUT_DTMF_1) ? "SOUT_1" : \ + (id == WAN_EC_SOUT_DTMF_2) ? "SOUT_2" : \ + (id == WAN_EC_SOUT_DTMF_3) ? "SOUT_3" : \ + (id == WAN_EC_SOUT_DTMF_4) ? "SOUT_4" : \ + (id == WAN_EC_SOUT_DTMF_5) ? "SOUT_5" : \ + (id == WAN_EC_SOUT_DTMF_6) ? "SOUT_6" : \ + (id == WAN_EC_SOUT_DTMF_7) ? "SOUT_7" : \ + (id == WAN_EC_SOUT_DTMF_8) ? "SOUT_8" : \ + (id == WAN_EC_SOUT_DTMF_9) ? "SOUT_9" : \ + (id == WAN_EC_SOUT_DTMF_A) ? "SOUT_A" : \ + (id == WAN_EC_SOUT_DTMF_B) ? "SOUT_B" : \ + (id == WAN_EC_SOUT_DTMF_C) ? "SOUT_C" : \ + (id == WAN_EC_SOUT_DTMF_D) ? "SOUT_D" : \ + (id == WAN_EC_SOUT_DTMF_STAR) ? "SOUT_STAR" : \ + (id == WAN_EC_SOUT_DTMF_POUND) ? "SOUT_POUND" :\ + (id == WAN_EC_ROUT_DTMF_0) ? "ROUT_0" : \ + (id == WAN_EC_ROUT_DTMF_1) ? "ROUT_1" : \ + (id == WAN_EC_ROUT_DTMF_2) ? "ROUT_2" : \ + (id == WAN_EC_ROUT_DTMF_3) ? "ROUT_3" : \ + (id == WAN_EC_ROUT_DTMF_4) ? "ROUT_4" : \ + (id == WAN_EC_ROUT_DTMF_5) ? "ROUT_5" : \ + (id == WAN_EC_ROUT_DTMF_6) ? "ROUT_6" : \ + (id == WAN_EC_ROUT_DTMF_7) ? "ROUT_7" : \ + (id == WAN_EC_ROUT_DTMF_8) ? "ROUT_8" : \ + (id == WAN_EC_ROUT_DTMF_9) ? "ROUT_9" : \ + (id == WAN_EC_ROUT_DTMF_A) ? "ROUT_A" : \ + (id == WAN_EC_ROUT_DTMF_B) ? "ROUT_B" : \ + (id == WAN_EC_ROUT_DTMF_C) ? "ROUT_C" : \ + (id == WAN_EC_ROUT_DTMF_D) ? "ROUT_D" : \ + (id == WAN_EC_ROUT_DTMF_STAR) ? "ROUT_STAR" : \ + (id == WAN_EC_ROUT_DTMF_POUND) ? "ROUT_POUND" :\ + "Unknown" + + +# define WAN_EC_CMD_NONE _IOWR('E', 0, struct wan_ec_api_) +# define WAN_EC_CMD_GETINFO _IOWR('E', 1, wan_ec_api_t) +# define WAN_EC_CMD_CONFIG _IOWR('E', 2, struct wan_ec_api_) +# define WAN_EC_CMD_CHANNEL_OPEN _IOWR('E', 3, struct wan_ec_api_) +# define WAN_EC_CMD_RELEASE _IOWR('E', 4, struct wan_ec_api_) +# define WAN_EC_CMD_ENABLE _IOWR('E', 5, struct wan_ec_api_) +# define WAN_EC_CMD_DISABLE _IOWR('E', 6, struct wan_ec_api_) +# define WAN_EC_CMD_BYPASS_ENABLE _IOWR('E', 7, struct wan_ec_api_) +# define WAN_EC_CMD_BYPASS_DISABLE _IOWR('E', 8, struct wan_ec_api_) +# define WAN_EC_CMD_MODE_NORMAL _IOWR('E', 9, struct wan_ec_api_) +# define WAN_EC_CMD_MODE_POWERDOWN _IOWR('E', 10, struct wan_ec_api_) +# define WAN_EC_CMD_MODIFY_CHANNEL _IOWR('E', 11, struct wan_ec_api_) +# define WAN_EC_CMD_DTMF_ENABLE _IOWR('E', 12, struct wan_ec_api_) +# define WAN_EC_CMD_DTMF_DISABLE _IOWR('E', 13, struct wan_ec_api_) +# define WAN_EC_CMD_STATS _IOWR('E', 14, struct wan_ec_api_) +# define WAN_EC_CMD_STATS_FULL _IOWR('E', 15, struct wan_ec_api_) +# define WAN_EC_CMD_TONE_LOAD _IOWR('E', 16, struct wan_ec_api_) +# define WAN_EC_CMD_TONE_UNLOAD _IOWR('E', 17, struct wan_ec_api_) +# define WAN_EC_CMD_PLAYOUT_START _IOWR('E', 18, struct wan_ec_api_) +# define WAN_EC_CMD_PLAYOUT_STOP _IOWR('E', 19, struct wan_ec_api_) +# define WAN_EC_CMD_MONITOR _IOWR('E', 20, struct wan_ec_api_) +# define WAN_EC_CMD_RELEASE_ALL _IOWR('E', 21, struct wan_ec_api_) +# define WAN_EC_CMD_DECODE(cmd) \ + (cmd == WAN_EC_CMD_GETINFO) ? "Get Info" : \ + (cmd == WAN_EC_CMD_CONFIG) ? "Config" : \ + (cmd == WAN_EC_CMD_CHANNEL_OPEN) ? "Channel Open" : \ + (cmd == WAN_EC_CMD_ENABLE) ? "Enable" : \ + (cmd == WAN_EC_CMD_DISABLE) ? "Disable" : \ + (cmd == WAN_EC_CMD_BYPASS_ENABLE) ? "Enable bypass" : \ + (cmd == WAN_EC_CMD_BYPASS_DISABLE) ? "Disable bypass" : \ + (cmd == WAN_EC_CMD_MODE_NORMAL) ? "Mode Normal" : \ + (cmd == WAN_EC_CMD_MODE_POWERDOWN) ? "Mode PowerDown" : \ + (cmd == WAN_EC_CMD_STATS) ? "Get stats" : \ + (cmd == WAN_EC_CMD_STATS_FULL) ? "Get stats" : \ + (cmd == WAN_EC_CMD_TONE_LOAD) ? "Tone load" : \ + (cmd == WAN_EC_CMD_TONE_UNLOAD) ? "Tone unload" : \ + (cmd == WAN_EC_CMD_PLAYOUT_START) ? "Playout start" : \ + (cmd == WAN_EC_CMD_PLAYOUT_STOP) ? "Playout stop" : \ + (cmd == WAN_EC_CMD_RELEASE) ? "Release" : \ + (cmd == WAN_EC_CMD_RELEASE_ALL) ? "Release all" : \ + (cmd == WAN_EC_CMD_MONITOR) ? "MONITOR" : \ + (cmd == WAN_EC_CMD_MODIFY_CHANNEL) ? "MODIFY" : \ + (cmd == WAN_EC_CMD_DTMF_ENABLE) ? "Enable DTMF" : \ + (cmd == WAN_EC_CMD_DTMF_DISABLE) ? "Disable DTMF" : \ + "Unknown" + +#if 0 +enum { + WAN_OCT6100_BYPASS = 0x01, + WAN_OCT6100_BYPASS_FULL, + WAN_OCT6100_BYPASS_LINE, +}; +#endif + +/*===========================================================================*\ + User process context - This would probably have to be defined elsewhere. + This structure must be allocated by the calling process and the parameters + should be defined prior to open the OCT6100 chip. +\*===========================================================================*/ +typedef struct _OCTPCIDRV_USER_PROCESS_CONTEXT_ +{ +#if defined(WAN_KERNEL) + /* Interface name to driver (copied by calling process) */ + unsigned char devname[WAN_DRVNAME_SZ+1]; + /*unsigned char ifname[WAN_IFNAME_SZ+1];*/ + + /* Board index. */ + unsigned int ulBoardId; + + void *ec_dev; +#else + /* Is main process */ + unsigned int fMainProcess; + + /* Handle to driver (opened by calling process) */ + void *ec_dev; + + /* Interface name to driver (copied by calling process) */ + unsigned char devname[WAN_DRVNAME_SZ+1]; + unsigned char ifname[WAN_IFNAME_SZ+1]; + + /* Handle to serialization object used for read and writes */ + unsigned int ulUserReadWriteSerObj; + + /* Board index. */ + unsigned int ulBoardId; + + /* Board type. */ + unsigned int ulBoardType; +#endif +} tOCTPCIDRV_USER_PROCESS_CONTEXT, *tPOCTPCIDRV_USER_PROCESS_CONTEXT; + + +typedef struct wanec_config_ { + int max_channels; + int memory_chip_size; + UINT32 debug_data_mode; + PUINT8 imageData; + UINT32 imageSize; +} wanec_config_t; + +typedef struct wanec_param_ { + char key[MAX_PARAM_LEN]; + char value[MAX_VALUE_LEN]; + UINT32 value1; +} wanec_param_t; + +typedef struct wanec_chip_stats_ { + int reset; + tOCT6100_CHIP_STATS f_ChipStats; + tOCT6100_CHIP_IMAGE_INFO *f_ChipImageInfo; +} wanec_chip_stats_t; + +typedef struct wanec_chan_stats_ { + int reset; + tOCT6100_CHANNEL_STATS f_ChannelStats; +} wanec_chan_stats_t; + +#define MAX_MONITOR_DATA_LEN 1024 +typedef struct wanec_chan_monitor_ { + UINT32 remain_len; + UINT32 data_len; + UINT32 max_len; + UINT8 data[MAX_MONITOR_DATA_LEN+1]; +} wanec_chan_monitor_t; + +typedef struct wanec_tone_config_ { + UINT8 tone[WAN_MAX_TONE_LEN]; + PUINT8 data; + UINT32 size; + UINT32 buffer_index; /* value return by ec */ +} wanec_tone_config_t; + +typedef struct wanec_dtmf_config { + u_int8_t port; /* SOUT or ROUT */ + u_int8_t type; /* PRESENT or STOP */ +} wanec_dtmf_config_t; + +#define MAX_EC_PLAYOUT_LEN 20 +typedef struct wanec_playout_ { + UINT32 index; + UINT32 duration; + BOOL repeat; + UINT32 repeat_count; + UINT32 buffer_length; + INT32 gaindb; + + CHAR str[MAX_EC_PLAYOUT_LEN]; + UINT32 delay; +} wanec_playout_t; + +typedef struct wan_ec_api_ { + char devname[WAN_DRVNAME_SZ+1]; +// char if_name[WAN_IFNAME_SZ+1]; + unsigned long cmd; + unsigned int type; + int err; + int verbose; + int state; + + int channel; + unsigned long channel_map; + + union { +#define u_info u_ec.info +#define u_config u_ec.config +#define u_chip_stats u_ec.chip_stats +#define u_chan_stats u_ec.chan_stats +#define u_chan_monitor u_ec.chan_monitor +#define u_tone_config u_ec.tone_config +#define u_dtmf_config u_ec.dtmf_config +#define u_playout u_ec.playout + struct info_ { + unsigned int max_channels; + } info; + wanec_config_t config; + wanec_chip_stats_t chip_stats; + wanec_chan_stats_t chan_stats; + wanec_chan_monitor_t chan_monitor; + wanec_tone_config_t tone_config; + wanec_dtmf_config_t dtmf_config; + wanec_playout_t playout; + } u_ec; + int param_no; + wanec_param_t param[2]; +} wan_ec_api_t; + + +#if defined(WAN_KERNEL) + +/* Critical bit map */ +#define WAN_EC_BIT_TIMER_RUNNING 1 +#define WAN_EC_BIT_TIMER_KILL 2 +#define WAN_EC_BIT_CRIT_CMD 3 +#define WAN_EC_BIT_EVENT_DTMF 4 + +#define WAN_EC_POLL_NONE 0x00 +#define WAN_EC_POLL_INTR 0x01 +#define WAN_EC_POLL_CHIPOPENPENDING 0x02 + +struct wan_ec_; +typedef struct wan_ec_dev_ { + char *name; + char devname[WAN_DRVNAME_SZ+1]; + char ecdev_name[WAN_DRVNAME_SZ+1]; + int ecdev_no; + sdla_t *card; + + u_int8_t fe_media; + u_int32_t fe_lineno; + u_int32_t fe_max_channels; + u_int32_t fe_tdmv_law; + u_int32_t channel; + int state; + + u_int32_t critical; + wan_timer_t timer; + u_int8_t poll_cmd; + + u_int32_t events; /* enable events map */ + + struct wan_ec_ *ec; + WAN_LIST_ENTRY(wan_ec_dev_) next; +} wan_ec_dev_t; + +typedef struct wan_ec_ { + char name[WAN_DRVNAME_SZ+1]; + int usage; + int chip_no; + int state; + int ec_channels_no; + int max_channels; /* max number of ec channels (security) */ + void *ec_dev; + int intcount; + u_int32_t critical; + + u_int32_t events; /* enable events map */ + + PUINT8 pImageData; + tOCT6100_CHIP_OPEN f_OpenChip; + + tOCTPCIDRV_USER_PROCESS_CONTEXT f_Context; + tPOCT6100_INSTANCE_API pChipInstance; + tOCT6100_INTERRUPT_FLAGS f_InterruptFlag; + UINT32 *pEchoChannelHndl; + PUINT32 pToneBufferIndexes; + UINT32 ulDebugChannelHndl; + INT DebugChannel; + UINT32 ulDebugDataMode; + + struct wan_ec_dev_ **pEcDevMap; + WAN_LIST_HEAD(wan_ec_dev_head_, wan_ec_dev_) ec_dev_head; + WAN_LIST_ENTRY(wan_ec_) next; +} wan_ec_t; + +#if 0 +typedef struct wanec_lip_reg +{ + unsigned long init; + + void* (*reg) (void*, int); + int (*unreg) (void*, void*); + + int (*ioctl) (void); + int (*isr) (void); + +}wanec_lip_reg_t; +#endif + +/* global interface functions */ +void *wan_ec_config (void *pcard, int max_channels); +int wan_ec_remove(void*, void *pcard); +int wan_ec_ioctl(void*, struct ifreq*, void *pcard); +int wan_ec_dev_ioctl(void*, void *pcard); + +u32 wan_ec_req_write(void*, u32 write_addr, u16 write_data); +u32 wan_ec_req_write_smear(void*, u32 addr, u16 data, u32 len); +u32 wan_ec_req_write_burst(void*, u32 addr, u16 *data, u32 len); +u32 wan_ec_req_read(void*, u32 addr, u16 *data); +u32 wan_ec_req_read_burst(void*, u32 addr, u16 *data, u32 len); + +#endif + +#endif /* __WANEC_LIP_H */ diff -Nur linux.org/include/linux/wanpipe_abstr.h linux-2.6.17/include/linux/wanpipe_abstr.h --- linux.org/include/linux/wanpipe_abstr.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/wanpipe_abstr.h 2006-08-30 10:07:15.000000000 +0000 @@ -0,0 +1,205 @@ +/***************************************************************************** +* wanpipe_abstr.c WANPIPE(tm) Kernel Abstraction Layer. +* +* Authors: Nenad Corbic +* Alex Feldman +* +* Copyright: (c) 2003 Sangoma Technologies Inc. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version +* 2 of the License, or (at your option) any later version. +* ============================================================================ +* Jan 07, 2003 Nenad Corbic Based on ADSL ATM SAR +*****************************************************************************/ + + +#ifndef _SDLA_ATM_IFACE_H +#define _SDLA_ATM_IFACE_H + +#include + +extern int wp_sar_register_device (void *card, + unsigned char *devname, + void **atm_device_ptr, + void *rx_data_list, + void *tx_data_list, + void *trace_info); + +extern void wp_sar_unregister_device(void *atm_device); + +extern int wp_sar_register_pvc(void *atm_device, + void **pAdapter_ptr, + void **tx_cells_skb, + void *chan, + void *devname, + void *dev, + wan_atm_conf_if_t *atm_cfg, + unsigned int mtu); + +extern void wp_sar_unregister_pvc(void *atm_device, void *pAdapter, void *tx_skb); +extern int wanpipe_sar_rx (void *atm_device, void *rx_cell_block); +extern int wanpipe_sar_tx (void *pAdapter, void* tx_skb, void **tx_cell_skb); + +extern int wanpipe_sar_poll(void *pAdapter, int timeout); + +extern int wanpipe_get_atm_state (void *pAdapter); +extern int wanpipe_set_atm_state (void *pAdapter, int state); + + +#endif diff -Nur linux.org/include/linux/wanpipe_cfg.h linux-2.6.17/include/linux/wanpipe_cfg.h --- linux.org/include/linux/wanpipe_cfg.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/wanpipe_cfg.h 2006-08-30 10:07:15.000000000 +0000 @@ -0,0 +1,1223 @@ +#ifndef _WANPIPE_CFG_H_ +#define _WANPIPE_CFG_H_ + + +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) +# include +# include +# include +# include +# include +#elif defined(__LINUX__) +# include +# include +# include +# include +# include +#else +# error "No OS Defined!" +#endif + +/* DSL interface types */ +#define WAN_INTERFACE 0 +#define LAN_INTERFACE 1 + +/* Miscellaneous */ +#define WAN_IFNAME_SZ 15 /* max length of the interface name */ +#define WAN_DRVNAME_SZ 15 /* max length of the link driver name */ +#define WAN_ADDRESS_SZ 31 /* max length of the WAN media address */ +#define USED_BY_FIELD 30 /* max length of the used by field */ + +#define WAN_AUTHNAMELEN 64 + +/* Defines for UDP PACKET TYPE */ +#define UDP_PTPIPE_TYPE 0x01 +#define UDP_FPIPE_TYPE 0x02 +#define UDP_CPIPE_TYPE 0x03 +#define UDP_DRVSTATS_TYPE 0x04 +#define UDP_INVALID_TYPE 0x05 + +#define UDPMGMT_UDP_PROTOCOL 0x11 + +/* Command return code */ +#define WAN_CMD_OK 0 /* normal firmware return code */ +#define WAN_CMD_TIMEOUT 0xFF /* firmware command timed out */ +/* FIXME: Remove these 2 defines (use WAN_x) */ +#define CMD_OK 0 /* normal firmware return code */ +#define CMD_TIMEOUT 0xFF /* firmware command timed out */ + +/* UDP Packet Management */ +#define UDP_PKT_FRM_STACK 0x00 +#define UDP_PKT_FRM_NETWORK 0x01 + +#define WAN_UDP_FAILED_CMD 0xCF +#define WAN_UDP_INVALID_CMD 0xCE +#define WAN_UDP_TIMEOUT_CMD 0xAA +#define WAN_UDP_INVALID_NET_CMD 0xCD + +/* Maximum interrupt test counter */ +#define MAX_INTR_TEST_COUNTER 100 +#define MAX_NEW_INTR_TEST_COUNTER 5 + +/* Critical Values for RACE conditions*/ +#define CRITICAL_IN_ISR 0xA1 +#define CRITICAL_INTR_HANDLED 0xB1 + +/* Card Types */ +#define WANOPT_S50X 1 +#define WANOPT_S51X 2 +#define WANOPT_ADSL 3 +#define WANOPT_AFT 4 +#define WANOPT_AFT104 5 +#define WANOPT_AFT300 6 +#define WANOPT_AFT_ANALOG 7 +#define WANOPT_AFT108 8 +#define WANOPT_AFT_X 9 + +/* + * Configuration options defines. + */ +/* general options */ +#define WANOPT_OFF 0 +#define WANOPT_ON 1 +#define WANOPT_NO 0 +#define WANOPT_YES 1 + +/* intercace options */ +#define WANOPT_RS232 0 +#define WANOPT_V35 1 + +/* data encoding options */ +#define WANOPT_NRZ 0 +#define WANOPT_NRZI 1 +#define WANOPT_FM0 2 +#define WANOPT_FM1 3 + +/* line idle option */ +#define WANOPT_IDLE_FLAG 0 +#define WANOPT_IDLE_MARK 1 + +/* link type options */ +#define WANOPT_POINTTOPOINT 0 /* RTS always active */ +#define WANOPT_MULTIDROP 1 /* RTS is active when transmitting */ + +/* clocking options */ +#define WANOPT_EXTERNAL 0 +#define WANOPT_INTERNAL 1 + +/* station options */ +#define WANOPT_DTE 0 +#define WANOPT_DCE 1 +#define WANOPT_CPE 0 +#define WANOPT_NODE 1 +#define WANOPT_SECONDARY 0 +#define WANOPT_PRIMARY 1 + +/* connection options */ +#define WANOPT_PERMANENT 0 /* DTR always active */ +#define WANOPT_SWITCHED 1 /* use DTR to setup link (dial-up) */ +#define WANOPT_ONDEMAND 2 /* activate DTR only before sending */ + +/* frame relay in-channel signalling */ +#define WANOPT_FR_AUTO_SIG 0 /* Automatically find singalling */ +#define WANOPT_FR_ANSI 1 /* ANSI T1.617 Annex D */ +#define WANOPT_FR_Q933 2 /* ITU Q.933A */ +#define WANOPT_FR_LMI 3 /* LMI */ +#define WANOPT_FR_NO_LMI 4 /* NO LMI */ + +#define WANOPT_FR_EEK_OFF 0 /* Frame Relay EEK Disabled */ +#define WANOPT_FR_EEK_REQUEST 1 /* Frame Relay EEK Request Mode */ +#define WANOPT_FR_EEK_REPLY 2 /* Frame Relay EEK Reply Mode */ + +/* PPP IP Mode Options */ +#define WANOPT_PPP_STATIC 0 +#define WANOPT_PPP_HOST 1 +#define WANOPT_PPP_PEER 2 + +/* ASY Mode Options */ +#define WANOPT_ONE 1 +#define WANOPT_TWO 2 +#define WANOPT_ONE_AND_HALF 3 + +#define WANOPT_NONE 0 +#define WANOPT_ODD 1 +#define WANOPT_EVEN 2 + +/* ATM sync options */ +#define WANOPT_AUTO 0 +#define WANOPT_MANUAL 1 + +#define WANOPT_DSP_HPAD 0 +#define WANOPT_DSP_TPAD 1 + + +/* SS7 options */ +#define WANOPT_SS7_FISU 0 +#define WANOPT_SS7_LSSU 1 + +#define WANOPT_SS7_MODE_128 0 +#define WANOPT_SS7_MODE_4096 1 + +#define WANOPT_SS7_FISU_128_SZ 3 +#define WANOPT_SS7_FISU_4096_SZ 6 + + +/* CHDLC Protocol Options */ +/* DF Commmented out for now. + +#define WANOPT_CHDLC_NO_DCD IGNORE_DCD_FOR_LINK_STAT +#define WANOPT_CHDLC_NO_CTS IGNORE_CTS_FOR_LINK_STAT +#define WANOPT_CHDLC_NO_KEEPALIVE IGNORE_KPALV_FOR_LINK_STAT +*/ + + + +/* SS7 options */ +#define WANOPT_SS7_ANSI 1 +#define WANOPT_SS7_ITU 2 +#define WANOPT_SS7_NTT 3 + + +/* Port options */ +#define WANOPT_PRI 0 +#define WANOPT_SEC 1 +/* read mode */ +#define WANOPT_INTR 0 +#define WANOPT_POLL 1 + + +#define WANOPT_TTY_SYNC 0 +#define WANOPT_TTY_ASYNC 1 + +/* RBS Signalling Options */ +#define WAN_RBS_SIG_A 0x01 +#define WAN_RBS_SIG_B 0x02 +#define WAN_RBS_SIG_C 0x04 +#define WAN_RBS_SIG_D 0x08 + +/* Front End Ref Clock Options */ + +#define WANOPT_FE_OSC_CLOCK 0x00 +#define WANOPT_FE_LINE_CLOCK 0x01 + + +enum wan_codec_format{ + WP_NONE, + WP_SLINEAR +}; + + +/* Interface Operation Modes */ +enum { + WANPIPE, + API, + BRIDGE, + BRIDGE_NODE, + SWITCH, + STACK, + ANNEXG, + TTY, + TDM_VOICE, + TDM_VOICE_DCHAN, + TDM_VOICE_API, + TDM_API +}; + +/* POS protocols */ +enum { + IBM4680, + NCR2127, + NCR2126, + NCR1255, + NCR7000, + ICL +}; +/* 'state' defines */ +enum wan_states +{ + WAN_UNCONFIGURED, /* link/channel is not configured */ + WAN_DISCONNECTED, /* link/channel is disconnected */ + WAN_CONNECTING, /* connection is in progress */ + WAN_CONNECTED, /* link/channel is operational */ + WAN_LIMIT, /* for verification only */ + WAN_DUALPORT, /* for Dual Port cards */ + WAN_DISCONNECTING, + WAN_FT1_READY /* FT1 Configurator Ready */ +}; + +enum { + WAN_LOCAL_IP, + WAN_POINTOPOINT_IP, + WAN_NETMASK_IP, + WAN_BROADCAST_IP +}; + + +/* Standard Mode */ +enum { + WANOPT_ADSL_T1_413 = 0, + WANOPT_ADSL_G_LITE = 1, + WANOPT_ADSL_G_DMT = 2, + WANOPT_ADSL_ALCATEL_1_4 = 3, + WANOPT_ADSL_MULTIMODE = 4, + WANOPT_ADSL_ADI = 5, + WANOPT_ADSL_ALCATEL = 6, + WANOPT_ADSL_T1_413_AUTO = 9 +}; + +/* Trellis Modes */ +#define WANOPT_ADSL_TRELLIS_DISABLE 0x0000 +#define WANOPT_ADSL_TRELLIS_ENABLE 0x8000 + +#define WANOPT_ADSL_TRELLIS_LITE_ONLY_DISABLE 0xF000 + +#define WANOPT_ADSL_0DB_CODING_GAIN 0x0000 +#define WANOPT_ADSL_1DB_CODING_GAIN 0x1000 +#define WANOPT_ADSL_2DB_CODING_GAIN 0x2000 +#define WANOPT_ADSL_3DB_CODING_GAIN 0x3000 +#define WANOPT_ADSL_4DB_CODING_GAIN 0x4000 +#define WANOPT_ADSL_5DB_CODING_GAIN 0x5000 +#define WANOPT_ADSL_6DB_CODING_GAIN 0x6000 +#define WANOPT_ADSL_7DB_CODING_GAIN 0x7000 +#define WANOPT_ADSL_AUTO_CODING_GAIN 0xFF00 + +#define WANOPT_ADSL_RX_BIN_ENABLE 0x01 +#define WANOPT_ADSL_RX_BIN_DISABLE 0x00 + + +#define WANOPT_ADSL_FRAMING_TYPE_0 0x0000 +#define WANOPT_ADSL_FRAMING_TYPE_1 0x0001 +#define WANOPT_ADSL_FRAMING_TYPE_2 0x0002 +#define WANOPT_ADSL_FRAMING_TYPE_3 0x0003 + +#define WANOPT_ADSL_EXPANDED_EXCHANGE 0x8000 +#define WANOPT_ADSL_SHORT_EXCHANGE 0x0000 + +#define WANOPT_ADSL_CLOCK_OSCILLATOR 0x00 +#define WANOPT_ADSL_CLOCK_CRYSTAL 0x04 + + +#define SDLA_DECODE_CARDTYPE(card_type) \ + (card_type == WANOPT_S50X) ? "S50X" : \ + (card_type == WANOPT_S51X) ? "S51X" : \ + (card_type == WANOPT_ADSL) ? "ADSL" : \ + (card_type == WANOPT_AFT) ? "A101/2" : \ + (card_type == WANOPT_AFT104 || \ + card_type == WANOPT_AFT108) ? "A104/4D/8" : \ + (card_type == WANOPT_AFT300) ? "A300" : \ + (card_type == WANOPT_AFT_ANALOG) ? "A200" : \ + "Unknown" + +#define COMPORT_DECODE(port) (port == WANOPT_PRI) ? "PRI" : "SEC" + +#define STATE_DECODE(state) \ + ((state == WAN_UNCONFIGURED) ? "Unconfigured" : \ + (state == WAN_DISCONNECTED) ? "Disconnected" : \ + (state == WAN_CONNECTING) ? "Connecting" : \ + (state == WAN_CONNECTED) ? "Connected": \ + (state == WAN_LIMIT) ? "Limit": \ + (state == WAN_DUALPORT) ? "DualPort": \ + (state == WAN_DISCONNECTING) ? "Disconnecting": \ + (state == WAN_FT1_READY) ? "FT1 Ready": "Invalid") + +#define CFG_DECODE(value) (value) ? "YES" : "NO" + +#define CLK_DECODE(clocking) (clocking) ? "INT" : "EXT" + +#define INT_DECODE(interface) \ + (interface == WANOPT_RS232) ? "RS232" : "V35" + +#define SIGNALLING_DECODE(sig) \ + (sig == WANOPT_FR_ANSI) ? "ANSI" : \ + (sig == WANOPT_FR_Q933) ? "Q333" : \ + (sig == WANOPT_FR_LMI) ? "LMI" : "NO" + +#define COMPORT_DECODE(port) (port == WANOPT_PRI) ? "PRI" : "SEC" + +#define IP_MODE_DECODE(ip_mode) \ + (ip_mode == WANOPT_PPP_STATIC) ? "STATIC" : \ + (ip_mode == WANOPT_PPP_PEER) ? "PEER" : "HOST" + +#define X25_STATION_DECODE(station) \ + (station == WANOPT_DTE) ? "DTE" : \ + (station == WANOPT_DCE) ? "DCE" : "DXE" + +#define FR_STATION_DECODE(station) \ + (station == WANOPT_CPE) ? "CPE" : "Node" + +typedef char devname_t[WAN_DRVNAME_SZ+1]; + +typedef enum { + RFC_MODE_BRIDGED_ETH_LLC = 0, + RFC_MODE_BRIDGED_ETH_VC = 1, + RFC_MODE_ROUTED_IP_LLC = 2, + RFC_MODE_ROUTED_IP_VC = 3, + RFC_MODE_RFC1577_ENCAP = 4, + RFC_MODE_PPP_LLC = 5, + RFC_MODE_PPP_VC = 6, + RFC_MODE_STACK_VC = 7 +} RFC_MODE; + +typedef struct wan_adsl_vcivpi +{ + unsigned short vci; + unsigned char vpi; +} wan_adsl_vcivpi_t; + + +typedef struct wan_adsl_conf +{ +#if 1 + unsigned char EncapMode; + unsigned short Vci; + unsigned short Vpi; +#else + unsigned char interface; + unsigned char Rfc1483Mode; + unsigned short Rfc1483Vci; + unsigned short Rfc1483Vpi; + unsigned char Rfc2364Mode; + unsigned short Rfc2364Vci; + unsigned short Rfc2364Vpi; +#endif + unsigned char Verbose; + unsigned short RxBufferCount; + unsigned short TxBufferCount; + + unsigned short Standard; + unsigned short Trellis; + unsigned short TxPowerAtten; + unsigned short CodingGain; + unsigned short MaxBitsPerBin; + unsigned short TxStartBin; + unsigned short TxEndBin; + unsigned short RxStartBin; + unsigned short RxEndBin; + unsigned short RxBinAdjust; + unsigned short FramingStruct; + unsigned short ExpandedExchange; + unsigned short ClockType; + unsigned short MaxDownRate; + + unsigned char atm_autocfg; + unsigned short vcivpi_num; + wan_adsl_vcivpi_t vcivpi_list[100]; + unsigned char tty_minor; + unsigned short mtu; + + unsigned char atm_watchdog; +}wan_adsl_conf_t; + + +typedef struct wan_atm_conf +{ + unsigned char atm_sync_mode; + unsigned short atm_sync_data; + unsigned char atm_sync_offset; + unsigned short atm_hunt_timer; + + unsigned char atm_cell_cfg; + unsigned char atm_cell_pt; + unsigned char atm_cell_clp; + unsigned char atm_cell_payload; +}wan_atm_conf_t; + + +typedef struct wan_atm_conf_if +{ + unsigned char encap_mode; + unsigned short vci; + unsigned short vpi; + + unsigned char atm_oam_loopback; + unsigned char atm_oam_loopback_intr; + unsigned char atm_oam_continuity; + unsigned char atm_oam_continuity_intr; + unsigned char atm_arp; + unsigned char atm_arp_intr; + + unsigned short mtu; + + unsigned char atm_sync_mode; + unsigned short atm_sync_data; + unsigned char atm_sync_offset; + unsigned short atm_hunt_timer; + + unsigned char atm_cell_cfg; + unsigned char atm_cell_pt; + unsigned char atm_cell_clp; + unsigned char atm_cell_payload; + +}wan_atm_conf_if_t; + + +typedef struct wan_bitstrm_conf{ + /* Bitstreaming options */ + unsigned short sync_options; + unsigned short rx_sync_char; + unsigned char monosync_tx_time_fill_char; + unsigned int max_length_tx_data_block; + unsigned int rx_complete_length; + unsigned int rx_complete_timer; + + unsigned long rbs_map; + +}wan_bitstrm_conf_t; + + +typedef struct wan_bitstrm_conf_if +{ + unsigned int max_tx_queue_size; + unsigned int max_tx_up_size; + unsigned char seven_bit_hdlc; +}wan_bitstrm_conf_if_t; + +/*---------------------------------------------------------------------------- + * X.25-specific link-level configuration. + */ +typedef struct wan_x25_conf +{ + unsigned int lo_pvc; /* lowest permanent circuit number */ + unsigned int hi_pvc; /* highest permanent circuit number */ + unsigned int lo_svc; /* lowest switched circuit number */ + unsigned int hi_svc; /* highest switched circuit number */ + unsigned int hdlc_window; /* HDLC window size (1..7) */ + unsigned int pkt_window; /* X.25 packet window size (1..7) */ + unsigned int t1; /* HDLC timer T1, sec (1..30) */ + unsigned int t2; /* HDLC timer T2, sec (0..29) */ + unsigned int t4; /* HDLC supervisory frame timer = T4 * T1 */ + unsigned int n2; /* HDLC retransmission limit (1..30) */ + unsigned int t10_t20; /* X.25 RESTART timeout, sec (1..255) */ + unsigned int t11_t21; /* X.25 CALL timeout, sec (1..255) */ + unsigned int t12_t22; /* X.25 RESET timeout, sec (1..255) */ + unsigned int t13_t23; /* X.25 CLEAR timeout, sec (1..255) */ + unsigned int t16_t26; /* X.25 INTERRUPT timeout, sec (1..255) */ + unsigned int t28; /* X.25 REGISTRATION timeout, sec (1..255) */ + unsigned int r10_r20; /* RESTART retransmission limit (0..250) */ + unsigned int r12_r22; /* RESET retransmission limit (0..250) */ + unsigned int r13_r23; /* CLEAR retransmission limit (0..250) */ + unsigned int ccitt_compat; /* compatibility mode: 1988/1984/1980 */ + unsigned int x25_conf_opt; /* User defined x25 config optoins */ + unsigned char LAPB_hdlc_only; /* Run in HDLC only mode */ + unsigned char logging; /* Control connection logging */ + unsigned char oob_on_modem; /* Whether to send modem + status to the user app */ + unsigned char local_station_address; /*Local Station address */ + unsigned short defPktSize; + unsigned short pktMTU; + unsigned char cmd_retry_timeout; /* Value is seconds */ + unsigned char station; +} wan_x25_conf_t; + +/*---------------------------------------------------------------------------- + * Frame relay specific link-level configuration. + */ +typedef struct wan_fr_conf +{ + unsigned int signalling; /* local in-channel signalling type */ + unsigned int t391; /* link integrity verification timer */ + unsigned int t392; /* polling verification timer */ + unsigned int n391; /* full status polling cycle counter */ + unsigned int n392; /* error threshold counter */ + unsigned int n393; /* monitored events counter */ + unsigned int dlci_num; /* number of DLCs (access node) */ + unsigned int dlci[100]; /* List of all DLCIs */ + unsigned char issue_fs_on_startup; + unsigned char station; /* Node or CPE */ + unsigned int eek_cfg; /* EEK Request Reply Mode */ + unsigned int eek_timer; /* EEK Request Reply Timer */ +} wan_fr_conf_t; + +/* used by wanpipemon to get DLCI status */ +#define DLCI_NAME_LEN 20 +typedef struct wan_lip_fr_dlci +{ + unsigned short dlci; + unsigned int dlci_type; + unsigned char dlci_state; + unsigned char name[20]; + unsigned int down; + unsigned char type; +}wan_fr_dlci_t; + +typedef struct wan_xilinx_conf +{ + unsigned short dma_per_ch; /* DMA buffers per logic channel */ + unsigned short mru; /* MRU of transparent channels */ + unsigned int rbs; /* Robbit signalling support */ + unsigned int data_mux_map; /* Data mux map */ + unsigned int tdmv_span_no; + unsigned int tdmv_dchan; /* hwHDLC: PRI SIG */ + unsigned int rx_crc_bytes; + unsigned int ec_clk_src; /* Octasic Clock Source Port */ +/* unsigned char tdmv_hwec;*/ /* Congiure HW EC */ +}wan_xilinx_conf_t; + + +typedef struct wan_xilinx_conf_if +{ + unsigned char station; /* Node or CPE */ + unsigned int signalling; /* local in-channel signalling type */ + unsigned char seven_bit_hdlc; + unsigned int mru; + unsigned int mtu; + unsigned char idle_flag; + unsigned char data_mux; + unsigned char ss7_enable; + unsigned char ss7_mode; + unsigned char ss7_lssu_size; + unsigned char tdmv_master_if; + unsigned char tdmv_hwec; /* Enable/Disable HW EC */ + unsigned char rbs_cas_idle; /* Initial RBS/CAS value */ + unsigned char dtmf_hw; /* Enable/Disable HW DTMF */ +/* unsigned char tdmv_hwec_map[50];*/ /* Enable/Disable HW EC */ +}wan_xilinx_conf_if_t; + + +typedef struct wan_ss7_conf +{ + unsigned int line_cfg_opt; + unsigned int modem_cfg_opt; + unsigned int modem_status_timer; + unsigned int api_options; + unsigned int protocol_options; + unsigned int protocol_specification; + unsigned int stats_history_options; + unsigned int max_length_msu_sif; + unsigned int max_unacked_tx_msus; + unsigned int link_inactivity_timer; + unsigned int t1_timer; + unsigned int t2_timer; + unsigned int t3_timer; + unsigned int t4_timer_emergency; + unsigned int t4_timer_normal; + unsigned int t5_timer; + unsigned int t6_timer; + unsigned int t7_timer; + unsigned int t8_timer; + unsigned int n1; + unsigned int n2; + unsigned int tin; + unsigned int tie; + unsigned int suerm_error_threshold; + unsigned int suerm_number_octets; + unsigned int suerm_number_sus; + unsigned int sie_interval_timer; + unsigned int sio_interval_timer; + unsigned int sios_interval_timer; + unsigned int fisu_interval_timer; +} wan_ss7_conf_t; + + +#define WANOPT_TWO_WAY_ALTERNATE 0 +#define WANOPT_TWO_WAY_SIMULTANEOUS 1 + +#define WANOPT_PRI_DISC_ON_NO_RESP 0 +#define WANOPT_PRI_SNRM_ON_NO_RESP 1 + +typedef struct wan_xdlc_conf { + + unsigned char station; + unsigned int address; + unsigned int max_I_field_length; + + unsigned int protocol_config; + unsigned int error_response_config; + unsigned int TWS_max_ack_count; + + unsigned int pri_slow_poll_timer; + unsigned int pri_normal_poll_timer; + unsigned int pri_frame_response_timer; + unsigned int sec_nrm_timer; + + unsigned int max_no_response_cnt; + unsigned int max_frame_retransmit_cnt; + unsigned int max_rnr_cnt; + + unsigned int window; + +}wan_xdlc_conf_t; + + +typedef struct wan_sdlc_conf { + + unsigned char station_configuration; + unsigned long baud_rate; + unsigned short max_I_field_length; + unsigned short general_operational_config_bits; + unsigned short protocol_config_bits; + unsigned short exception_condition_reporting_config; + unsigned short modem_config_bits; + unsigned short statistics_format; + unsigned short pri_station_slow_poll_interval; + unsigned short permitted_sec_station_response_TO; + unsigned short no_consec_sec_TOs_in_NRM_before_SNRM_issued; + unsigned short max_lgth_I_fld_pri_XID_frame; + unsigned short opening_flag_bit_delay_count; + unsigned short RTS_bit_delay_count; + unsigned short CTS_timeout_1000ths_sec; + unsigned char SDLA_configuration; + +}wan_sdlc_conf_t; + + +typedef struct wan_bscstrm_conf { + unsigned long baud_rate; /* the baud rate */ + unsigned long adapter_frequency; /* the adapter frequecy */ + unsigned short max_data_length; /* the maximum length of a BSC data block */ + unsigned short EBCDIC_encoding; /* EBCDIC/ASCII encoding */ + unsigned short Rx_block_type; /* the type of BSC block to be received */ + unsigned short no_consec_PADs_EOB; /* the number of consecutive PADs indicating the end of the block */ + unsigned short no_add_lead_Tx_SYN_chars; /* the number of additional leading transmit SYN characters */ + unsigned short no_bits_per_char; /* the number of bits per character */ + unsigned short parity; /* parity */ + unsigned short misc_config_options; /* miscellaneous configuration options */ + unsigned short statistics_options; /* statistic options */ + unsigned short modem_config_options; /* modem configuration options */ +}wan_bscstrm_conf_t; + + +/*---------------------------------------------------------------------------- + * PPP-specific link-level configuration. + */ +typedef struct wan_ppp_conf +{ + unsigned restart_tmr; /* restart timer */ + unsigned auth_rsrt_tmr; /* authentication timer */ + unsigned auth_wait_tmr; /* authentication timer */ + unsigned mdm_fail_tmr; /* modem failure timer */ + unsigned dtr_drop_tmr; /* DTR drop timer */ + unsigned connect_tmout; /* connection timeout */ + unsigned conf_retry; /* max. retry */ + unsigned term_retry; /* max. retry */ + unsigned fail_retry; /* max. retry */ + unsigned auth_retry; /* max. retry */ + unsigned auth_options; /* authentication opt. */ + unsigned ip_options; /* IP options */ + char authenticator; /* AUTHENTICATOR or not */ + char ip_mode; /* Static/Host/Peer */ +} wan_ppp_conf_t; + +/*---------------------------------------------------------------------------- + * CHDLC-specific link-level configuration. + */ +typedef struct wan_chdlc_conf +{ + unsigned char ignore_dcd; /* Protocol options: */ + unsigned char ignore_cts; /* Ignore these to determine */ + unsigned char ignore_keepalive; /* link status (Yes or No) */ + unsigned char hdlc_streaming; /* hdlc_streaming mode (Y/N) */ + unsigned char receive_only; /* no transmit buffering (Y/N) */ + unsigned keepalive_tx_tmr; /* transmit keepalive timer */ + unsigned keepalive_rx_tmr; /* receive keepalive timer */ + unsigned keepalive_err_margin; /* keepalive_error_tolerance */ + unsigned slarp_timer; /* SLARP request timer */ + unsigned char fast_isr; /* Fast interrupt option */ + unsigned int protocol_options; +} wan_chdlc_conf_t; + + + +#define X25_CALL_STR_SZ 512 +#define WAN_IF_LABEL_SZ 15 + +typedef struct lapb_parms_struct { + unsigned int t1; + unsigned int t1timer; + unsigned int t2; + unsigned int t2timer; + unsigned int n2; + unsigned int n2count; + unsigned int t3; + unsigned int t4; + unsigned int window; + unsigned int state; + unsigned int mode; + unsigned int mtu; + unsigned int station; + unsigned char label[WAN_IF_LABEL_SZ+1]; + unsigned char virtual_addr[WAN_ADDRESS_SZ+1]; + unsigned char real_addr[WAN_ADDRESS_SZ+1]; +}wan_lapb_if_conf_t; + +/* used by both PPP and CHDLC in LIP layer */ +typedef struct sppp_parms_struct { + + unsigned char dynamic_ip;/* Static/Host/Peer (the same as ip_mode) */ + unsigned int local_ip; + unsigned int remote_ip; + + unsigned int pp_auth_timer; + unsigned int sppp_keepalive_timer;/* if 0, ignore keepalive for link status */ + unsigned int pp_timer; + + unsigned char pap; + unsigned char chap; + unsigned char userid[WAN_AUTHNAMELEN]; + unsigned char passwd[WAN_AUTHNAMELEN]; +#define SYSTEM_NAME_LEN 31 + unsigned char sysname[SYSTEM_NAME_LEN]; + + unsigned int gateway; + unsigned char ppp_prot; + + /* CHDLC */ + unsigned int keepalive_err_margin; +}wan_sppp_if_conf_t; + + +typedef struct x25_parms_struct { + + unsigned short X25_API_options; + unsigned short X25_protocol_options; + unsigned short X25_response_options; + unsigned short X25_statistics_options; + unsigned short packet_window; + unsigned short default_packet_size; + unsigned short maximum_packet_size; + unsigned short lowest_PVC; + unsigned short highest_PVC; + unsigned short lowest_incoming_channel; + unsigned short highest_incoming_channel; + unsigned short lowest_two_way_channel; + unsigned short highest_two_way_channel; + unsigned short lowest_outgoing_channel; + unsigned short highest_outgoing_channel; + unsigned short genl_facilities_supported_1; + unsigned short genl_facilities_supported_2; + unsigned short CCITT_facilities_supported; + unsigned short non_X25_facilities_supported; + unsigned short CCITT_compatibility; + unsigned short T10_T20; + unsigned short T11_T21; + unsigned short T12_T22; + unsigned short T13_T23; + unsigned short T16_T26; + unsigned short T28; + unsigned short R10_R20; + unsigned short R12_R22; + unsigned short R13_R23; + unsigned char dte; + unsigned char mode; + + unsigned char call_string [X25_CALL_STR_SZ+1]; + + /* Accept Call Information */ + unsigned char accept_called [WAN_ADDRESS_SZ+1]; + unsigned char accept_calling[WAN_ADDRESS_SZ+1]; + unsigned char accept_facil [WAN_ADDRESS_SZ+1]; + unsigned char accept_udata [WAN_ADDRESS_SZ+1]; + + unsigned char label [WAN_IF_LABEL_SZ+1]; + + unsigned int call_backoff_timeout; + unsigned char call_logging; + + /* X25_SW X.25 switching */ + unsigned char virtual_addr[WAN_ADDRESS_SZ+1]; + unsigned char real_addr[WAN_ADDRESS_SZ+1]; + + unsigned char addr[WAN_ADDRESS_SZ+1]; /* PVC LCN number */ + +} wan_x25_if_conf_t; + +typedef struct dsp_parms { + + unsigned char pad_type; /* PAD type: HOST or TERM */ + unsigned int T1; /* Service Timeout perioud */ + unsigned int T2; /* PAD protocol timeout period */ + unsigned int T3; /* Timeout between two packets + * of the same M_DATA */ + unsigned char auto_ce; /* Automaticaly send Circuit Enabled + * with ACCEPT CALL packet */ + unsigned char auto_call_req; /* Automaticaly re-send CALL REQUEST + * if it was failed before (T1) */ + unsigned char auto_ack; /* Automaticaly send ACK for data */ + + unsigned short dsp_mtu; /* MTU size for DSP level */ + +}wan_dsp_if_conf_t; + + +#if 0 +/*---------------------------------------------------------------------------- + * T1/E1 configuration structures. + */ +typedef struct sdla_te_cfg { + unsigned char media; + unsigned char lcode; + unsigned char frame; + unsigned char lbo; + unsigned char te_clock; + unsigned long active_ch; + unsigned char high_impedance_mode; +} sdla_te_cfg_t; + +/* Performamce monitor counters */ +typedef struct pmc_pmon { + unsigned long pmon1; + unsigned long pmon2; + unsigned long pmon3; + unsigned long pmon4; +} pmc_pmon_t; +#endif + +/*---------------------------------------------------------------------------- + * WAN device configuration. Passed to ROUTER_SETUP IOCTL. + */ +typedef struct wandev_conf +{ + unsigned magic; /* magic number (for verification) */ + unsigned config_id; /* configuration structure identifier */ + /****** hardware configuration ******/ + unsigned ioport; /* adapter I/O port base */ + unsigned long maddr; /* dual-port memory address */ + unsigned msize; /* dual-port memory size */ + int irq; /* interrupt request level */ + int dma; /* DMA request level */ + char S514_CPU_no[1]; /* S514 PCI adapter CPU number ('A' or 'B') */ + unsigned PCI_slot_no; /* S514 PCI adapter slot number */ + char auto_pci_cfg; /* S515 PCI automatic slot detection */ + int comm_port; /* Communication Port (PRI=0, SEC=1) */ + unsigned bps; /* data transfer rate */ + unsigned mtu; /* maximum transmit unit size */ + unsigned udp_port; /* UDP port for management */ + unsigned char ttl; /* Time To Live for UDP security */ + unsigned char ft1; /* FT1 Configurator Option */ + char interface; /* RS-232/V.35, etc. */ + char clocking; /* external/internal */ + char line_coding; /* NRZ/NRZI/FM0/FM1, etc. */ + char connection; /* permanent/switched/on-demand */ + char read_mode; /* read mode: Polling or interrupt */ + char receive_only; /* disable tx buffers */ + char tty; /* Create a fake tty device */ + unsigned tty_major; /* Major number for wanpipe tty device */ + unsigned tty_minor; /* Minor number for wanpipe tty device */ + unsigned tty_mode; /* TTY operation mode SYNC or ASYNC */ + char backup; /* Backup Mode */ + unsigned hw_opt[4]; /* other hardware options */ + unsigned reserved[4]; + + /****** arbitrary data ***************/ + unsigned data_size; /* data buffer size */ + void* data; /* data buffer, e.g. firmware */ + + union{ /****** protocol-specific ************/ + + wan_x25_conf_t x25; /* X.25 configuration */ + wan_ppp_conf_t ppp; /* PPP configuration */ + wan_fr_conf_t fr; /* frame relay configuration */ + wan_chdlc_conf_t chdlc; /* Cisco HDLC configuration */ + wan_ss7_conf_t ss7; /* SS7 Configuration */ + wan_sdlc_conf_t sdlc; /* SDLC COnfiguration */ + wan_bscstrm_conf_t bscstrm; /* Bisync Streaming Configuration */ + wan_adsl_conf_t adsl; /* ADSL Configuration */ + wan_atm_conf_t atm; + wan_xilinx_conf_t aft; + wan_bitstrm_conf_t bitstrm; + wan_xdlc_conf_t xdlc; + } u; + + /* No new variables are allowed above */ + + char card_type; /* Supported Sangoma Card type */ + unsigned pci_bus_no; /* S514 PCI bus number */ + + sdla_fe_cfg_t fe_cfg; /* Front end configurations */ + + unsigned char line_idle; /* IDLE FLAG/ IDLE MARK */ + unsigned char ignore_front_end_status; + unsigned int max_trace_queue; + unsigned int max_rx_queue; + + +#if 0 + /* Bitstreaming options */ + unsigned int sync_options; + unsigned char rx_sync_char; + unsigned char monosync_tx_time_fill_char; + unsigned int max_length_tx_data_block; + unsigned int rx_complete_length; + unsigned int rx_complete_timer; + + unsigned int max_trace_queue; + unsigned int max_rx_queue; +#endif + +} wandev_conf_t; + +/* 'config_id' definitions */ +#define WANCONFIG_X25 101 /* X.25 link */ +#define WANCONFIG_FR 102 /* frame relay link */ +#define WANCONFIG_PPP 103 /* synchronous PPP link */ +#define WANCONFIG_CHDLC 104 /* Cisco HDLC Link */ +#define WANCONFIG_BSC 105 /* BiSync Streaming */ +#define WANCONFIG_HDLC 106 /* HDLC Support */ +#define WANCONFIG_MPPP 107 /* Multi Port PPP over RAW CHDLC */ +#define WANCONFIG_MPROT WANCONFIG_MPPP /* Multi Port Driver HDLC,PPP,CHDLC over RAW CHDLC */ +#define WANCONFIG_BITSTRM 108 /* Bit-Stream protocol */ +#define WANCONFIG_EDUKIT 109 /* Educational Kit support */ +#define WANCONFIG_SS7 110 /* SS7 Support */ +#define WANCONFIG_BSCSTRM 111 /* Bisync Streaming Nasdaq */ +#define WANCONFIG_MFR 112 /* Mulit-Port Frame Relay over RAW HDLC */ +#define WANCONFIG_ADSL 113 /* LLC Ethernet Support */ +#define WANCONFIG_SDLC 114 /* SDLC Support */ +#define WANCONFIG_ATM 115 /* ATM Supprot */ +#define WANCONFIG_POS 116 /* POS Support */ +#define WANCONFIG_AFT 117 /* AFT Original Hardware Support */ +#define WANCONFIG_DEBUG 118 /* Real Time Debugging */ +#define WANCONFIG_ADCCP 119 /* Special HDLC LAPB Driver */ +#define WANCONFIG_MLINK_PPP 120 /* Multi-Link PPP */ +#define WANCONFIG_GENERIC 121 /* WANPIPE Generic driver */ +#define WANCONFIG_AFT_TE3 122 /* AFT TE3 Hardware Support */ +#define WANCONFIG_MPCHDLC 123 /* Multi Port CHDLC */ +#define WANCONFIG_AFT_TE1_SS7 124 /* AFT TE1 SS7 Hardware Support */ +#define WANCONFIG_LAPB 125 /* LIP LAPB Protocol Support */ +#define WANCONFIG_XDLC 126 /* LIP XDLC Protocol Support */ +#define WANCONFIG_TTY 127 /* LIP TTY Support */ +#define WANCONFIG_AFT_TE1 128 /* AFT Quad Hardware Support */ +#define WANCONFIG_XMTP2 129 /* LIP XMTP2 Protocol Support */ +#define WANCONFIG_ASYHDLC 130 /* S514 ASY HDLC API Support */ +#define WANCONFIG_LIP_ATM 131 /* ATM in LIP layer */ +#define WANCONFIG_AFT_ANALOG 132 /* AFT Analog Driver */ +#define WANCONFIG_ZAP 133 /* Used in wanpipemon when working with Zaptel driver */ +#define WANCONFIG_LAPD 134 /* LIP LAPD Q921 Protocol Support */ + +/*FIXME: This should be taken out, I just +//used it so I don't break the apps that are +//using the WANCONFIG_ETH. Once those apps are +//changed, remove this definition +*/ +#define WANCONFIG_ETH WANCONFIG_ADSL + +#define SDLA_DECODE_PROTOCOL(protocol) \ + (protocol == WANCONFIG_X25) ? "X25" : \ + (protocol == WANCONFIG_FR) ? "Frame Relay" : \ + (protocol == WANCONFIG_PPP) ? "PPP" : \ + (protocol == WANCONFIG_CHDLC) ? "CHDLC" : \ + (protocol == WANCONFIG_BSC) ? "BiSync Streaming": \ + (protocol == WANCONFIG_HDLC) ? "HDLC Streaming": \ + (protocol == WANCONFIG_MPPP) ? "PPP": \ + (protocol == WANCONFIG_BITSTRM) ? "Bit Stream": \ + (protocol == WANCONFIG_EDUKIT) ? "WAN EduKit": \ + (protocol == WANCONFIG_SS7) ? "SS7": \ + (protocol == WANCONFIG_BSCSTRM) ? "Bisync Streaming Nasdaq": \ + (protocol == WANCONFIG_MFR) ? "Frame Relay": \ + (protocol == WANCONFIG_ADSL) ? "LLC Ethernet (ADSL)": \ + (protocol == WANCONFIG_SDLC) ? "SDLC": \ + (protocol == WANCONFIG_ATM) ? "ATM": \ + (protocol == WANCONFIG_LIP_ATM)? "LIP_ATM": \ + (protocol == WANCONFIG_POS) ? "Point-of-Sale": \ + (protocol == WANCONFIG_AFT) ? "AFT": \ + (protocol == WANCONFIG_AFT_TE3) ? "AFT TE3": \ + (protocol == WANCONFIG_DEBUG) ? "Real Time Debugging": \ + (protocol == WANCONFIG_ADCCP) ? "Special HDLC LAPB": \ + (protocol == WANCONFIG_MLINK_PPP) ? "Multi-Link PPP": \ + (protocol == WANCONFIG_GENERIC) ? "WANPIPE Generic driver": \ + (protocol == WANCONFIG_MPCHDLC) ? "CHDLC": \ + (protocol == WANCONFIG_ZAP) ? "ZAP": \ + (protocol == WANCONFIG_TTY) ? "TTY": "Unknown Protocol" + + +/*---------------------------------------------------------------------------- + * WAN interface (logical channel) configuration (for ROUTER_IFNEW IOCTL). + */ +typedef struct wanif_conf +{ + unsigned magic; /* magic number */ + unsigned config_id; /* configuration identifier */ + char name[WAN_IFNAME_SZ+1]; /* interface name, ASCIIZ */ + char addr[WAN_ADDRESS_SZ+1]; /* media address, ASCIIZ */ + char usedby[USED_BY_FIELD]; /* used by API or WANPIPE */ + unsigned idle_timeout; /* sec, before disconnecting */ + unsigned hold_timeout; /* sec, before re-connecting */ + unsigned cir; /* Committed Information Rate fwd,bwd*/ + unsigned bc; /* Committed Burst Size fwd, bwd */ + unsigned be; /* Excess Burst Size fwd, bwd */ +#ifdef ENABLE_IPV6 + unsigned char enable_IPv4; /* Enable or Disable IPv4 */ + unsigned char enable_IPv6; /* Enable or Disable IPv6 */ +#endif + unsigned char enable_IPX; /* Enable or Disable IPX */ + unsigned char inarp; /* Send Inverse ARP requests Y/N */ + unsigned inarp_interval; /* sec, between InARP requests */ + unsigned long network_number; /* Network Number for IPX */ + char mc; /* Multicast on or off */ + char local_addr[WAN_ADDRESS_SZ+1];/* local media address, ASCIIZ */ + unsigned char port; /* board port */ + unsigned char protocol; /* prococol used in this channel (TCPOX25 or X25) */ + char pap; /* PAP enabled or disabled */ + char chap; /* CHAP enabled or disabled */ +#ifdef ENABLE_IPV6 + unsigned char chap_userid[WAN_AUTHNAMELEN]; /* List of User Id */ + unsigned char chap_passwd[WAN_AUTHNAMELEN]; /* List of passwords */ + unsigned char pap_userid[WAN_AUTHNAMELEN]; /* List of User Id */ + unsigned char pap_passwd[WAN_AUTHNAMELEN]; /* List of passwords */ +#else + unsigned char userid[WAN_AUTHNAMELEN]; /* List of User Id */ + unsigned char passwd[WAN_AUTHNAMELEN]; /* List of passwords */ +#endif + unsigned char sysname[SYSTEM_NAME_LEN]; /* Name of the system */ + unsigned char ignore_dcd; /* Protocol options: */ + unsigned char ignore_cts; /* Ignore these to determine */ + unsigned char ignore_keepalive; /* link status (Yes or No) */ + unsigned char hdlc_streaming; /* Hdlc streaming mode (Y/N) */ + unsigned keepalive_tx_tmr; /* transmit keepalive timer */ + unsigned keepalive_rx_tmr; /* receive keepalive timer */ + unsigned keepalive_err_margin; /* keepalive_error_tolerance */ + unsigned slarp_timer; /* SLARP request timer */ + unsigned char ttl; /* Time To Live for UDP security */ + char interface; /* RS-232/V.35, etc. */ + char clocking; /* external/internal */ + unsigned bps; /* data transfer rate */ + unsigned mtu; /* maximum transmit unit size */ + unsigned char if_down; /* brind down interface when disconnected */ + unsigned char gateway; /* Is this interface a gateway */ + unsigned char true_if_encoding; /* Set the dev->type to true board protocol */ + + unsigned char asy_data_trans; /* async API options */ + unsigned char rts_hs_for_receive; /* async Protocol options */ + unsigned char xon_xoff_hs_for_receive; + unsigned char xon_xoff_hs_for_transmit; + unsigned char dcd_hs_for_transmit; + unsigned char cts_hs_for_transmit; + unsigned char async_mode; + unsigned tx_bits_per_char; + unsigned rx_bits_per_char; + unsigned stop_bits; + unsigned char parity; + unsigned break_timer; + unsigned inter_char_timer; + unsigned rx_complete_length; + unsigned xon_char; + unsigned xoff_char; + unsigned char receive_only; /* no transmit buffering (Y/N) */ + + /* x25 media source address, ASCIIZ */ + unsigned char x25_src_addr[WAN_ADDRESS_SZ+1]; + /* pattern match string in -d + * for accepting calls, ASCIIZ */ + unsigned char accept_dest_addr[WAN_ADDRESS_SZ+1]; + /* pattern match string in -s + * for accepting calls, ASCIIZ */ + unsigned char accept_src_addr[WAN_ADDRESS_SZ+1]; + /* pattern match string in -u + * for accepting calls, ASCIIZ */ + unsigned char accept_usr_data[WAN_ADDRESS_SZ+1]; + + unsigned char inarp_rx; /* Receive Inverse ARP requests Y/N */ + unsigned long active_ch; + unsigned int max_trace_queue; + unsigned char sw_dev_name[WAN_IFNAME_SZ+1]; + unsigned char auto_cfg; + + unsigned char call_logging; + unsigned char master[WAN_IFNAME_SZ+1]; + unsigned char station; + unsigned char label[WAN_IF_LABEL_SZ+1]; + + unsigned char tdmv_echo_off; /* TDMV echo disable */ + unsigned char tdmv_codec; /* TDMV codec */ + + unsigned char lip_prot; + union { + wan_atm_conf_if_t atm; /* per interface configuration */ + wan_x25_if_conf_t x25; + wan_lapb_if_conf_t lapb; + wan_dsp_if_conf_t dsp; + wan_fr_conf_t fr; + wan_bitstrm_conf_if_t bitstrm; + wan_xilinx_conf_if_t aft; + wan_xdlc_conf_t xdlc; + wan_sppp_if_conf_t ppp; + wan_chdlc_conf_t chdlc; + }u; + +} wanif_conf_t; + +#define ATM_CELL_SIZE 53 +/* +** TYPEDEF +*/ +typedef struct atm_stats { + unsigned int rx_valid; + unsigned int rx_empty; + unsigned int rx_invalid_atm_hdr; + unsigned int rx_invalid_prot_hdr; + unsigned int rx_atm_pdu_size; + unsigned int rx_chip; + unsigned int tx_valid; + unsigned int tx_chip; + unsigned int rx_congestion; + unsigned int rx_clp; +} atm_stats_t; + +enum { + ATM_CONNECTED, + ATM_DISCONNECTED, + ATM_AIS +}; + +typedef struct { + unsigned short fr_active; + unsigned short fr_inactive; + unsigned short lapb_active; + unsigned short lapb_inactive; + unsigned short x25_link_active; + unsigned short x25_link_inactive; + unsigned short x25_active; + unsigned short x25_inactive; + unsigned short dsp_active; + unsigned short dsp_inactive; +}wp_stack_stats_t; + +/* ALEX_DEBUG*/ +typedef struct wan_debug { + unsigned long magic; /* for verification */ + unsigned long len; + unsigned long num; + unsigned long max_len; + unsigned long offs; + int is_more; + char* data; +} wan_kernel_msg_t; + +typedef struct wanpipe_debug_msg_hdr_t { + int len; + unsigned long time; +} wanpipe_kernel_msg_hdr_t; + + +typedef struct wplip_prot_reg +{ + int (*prot_set_state) (void *, int, unsigned char *, int); + int (*chan_set_state) (void *, int, unsigned char *, int); + int (*tx_link_down) (void *, void *); + int (*tx_chan_down) (void *, void *); + int (*rx_up) (void *, void *, int type); + unsigned int (*get_ipv4_addr)(void *, int type); + int (*set_ipv4_addr)(void *, + unsigned int, + unsigned int, + unsigned int, + unsigned int); + int (*kick_task) (void *); +#if 0 + int (*set_hw_idle_frame) (void *, unsigned char *, int); +#endif + int mtu; +}wplip_prot_reg_t; + +enum { + WPLIP_RAW, + WPLIP_IP, + WPLIP_IPV6, + WPLIP_IPX, + WPLIP_FR_ARP, + WPLIP_PPP, + WPLIP_FR, + WPLIP_ETH, + WPLIP_LAPD +}; + +#endif diff -Nur linux.org/include/linux/wanpipe_codec.h linux-2.6.17/include/linux/wanpipe_codec.h --- linux.org/include/linux/wanpipe_codec.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/wanpipe_codec.h 2006-08-30 10:07:15.000000000 +0000 @@ -0,0 +1,64 @@ +/************************************************************************** + * wanpipe_codec.h WANPIPE(tm) Multiprotocol WAN Link Driver. + * TDM voice board configuration. + * + * Author: Nenad Corbic + * + * Copyright: (c) 1995-2005 Sangoma Technologies Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + ****************************************************************************** + */ +/* + ****************************************************************************** + INCLUDE FILES + ****************************************************************************** +*/ + +#ifndef __WANPIPE_CODEC_H_ +#define __WANPIPE_CODEC_H_ + + + +#if (defined __FreeBSD__) | (defined __OpenBSD__) +#include +#else +#include +#endif + + +#ifdef CONFIG_PRODUCT_WANPIPE_CODEC_SLINEAR_LAW + +extern int wanpipe_codec_law_init(void); + +extern int wanpipe_codec_convert_s_2_alaw(u16 *data, + int len, + u8 *buf, + u8 user); + +extern int wanpipe_codec_convert_s_2_ulaw(u16 *data, + int len, + u8 *buf, + u8 user); + +extern int wanpipe_codec_convert_alaw_2_s(u8 *data, + int len, + u16 *buf, + u32 *power_ptr, + u8 user); + +extern int wanpipe_codec_convert_ulaw_2_s(u8 *data, + int len, + u16 *buf, + u32 *power_ptr, + u8 user); + +extern int wanpipe_codec_get_mtu_law_2_s(u32 mtu); +extern int wanpipe_codec_get_mtu_s_2_law(u32 mtu); +#endif + + +#endif diff -Nur linux.org/include/linux/wanpipe_codec_iface.h linux-2.6.17/include/linux/wanpipe_codec_iface.h --- linux.org/include/linux/wanpipe_codec_iface.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/wanpipe_codec_iface.h 2006-08-30 10:07:15.000000000 +0000 @@ -0,0 +1,89 @@ +/************************************************************************** + * wanpipe_codec_iface.c + * WANPIPE(tm) Multiprotocol WAN Link Driver. + * TDM voice board configuration. + * + * Author: Nenad Corbic + * + * Copyright: (c) 1995-2005 Sangoma Technologies Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + ****************************************************************************** + */ +/* + ****************************************************************************** + INCLUDE FILES + ****************************************************************************** +*/ + + +#ifndef __WANPIPE_CODEC_IFACE_ +#define __WANPIPE_CODEC_IFACE_ + +#define WP_TDM_HW_CODING_MAX 4 +#define WP_TDM_CODEC_MAX 10 + +enum wan_codec_source_format{ + WP_MULAW, + WP_ALAW +}; + +#if 0 +enum wan_codec_format{ + WP_NONE, + WP_SLINEAR +}; +#endif + +#ifdef WAN_KERNEL + +typedef struct { + int init; + int (*encode)(u8 *data, + int len, + u16 *buf, + u32 *power_ptr, u8 user); + + int (*decode)(u16 *data, + int len, + u8 *buf, u8 user); +}wanpipe_codec_ops_t; + + + +static __inline int wanpipe_codec_calc_new_mtu(u32 codec, u32 mtu) +{ + if (codec >= WP_TDM_CODEC_MAX){ + DEBUG_EVENT("%s:%d Critical: Invalid Codec \n", + __FUNCTION__,__LINE__); + return mtu; + } + + switch (codec){ + + case WP_SLINEAR: + mtu*=2; + break; + + default: + /* If no codec is specified + * there is no MTU multiple */ + break; + } + + return mtu; +} + + +extern int wanpipe_codec_init(void); +extern int wanpipe_codec_free(void); + +extern wanpipe_codec_ops_t *WANPIPE_CODEC_OPS[WP_TDM_HW_CODING_MAX][WP_TDM_CODEC_MAX]; + +#endif + +#endif + diff -Nur linux.org/include/linux/wanpipe_common.h linux-2.6.17/include/linux/wanpipe_common.h --- linux.org/include/linux/wanpipe_common.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/wanpipe_common.h 2006-08-30 10:07:15.000000000 +0000 @@ -0,0 +1,2302 @@ +/* + * Copyright (c) 2002 + * Alex Feldman . All rights reserved. + * + * $Id$ + */ + +/**************************************************************************** + * wanpipe_common.h WANPIPE(tm) Multiprotocol WAN Link Driver. + * + * Author: Alex Feldman + * + * ========================================================================== + * July 17, 2002 Alex Feldman Initial Version + **************************************************************************** + */ + +#ifndef __WANPIPE_COMMON_H +# define __WANPIPE_COMMON_H + +#ifdef __LINUX__ +# include +#else +# include +#endif + +#ifdef WAN_DEBUG_MEM +extern atomic_t wan_debug_mem; +#endif + +/**************************************************************************** +** D E F I N E S +****************************************************************************/ +#ifndef NIPQUAD +# define NIPQUAD(addr) \ + ((unsigned char *)&addr)[0], \ + ((unsigned char *)&addr)[1], \ + ((unsigned char *)&addr)[2], \ + ((unsigned char *)&addr)[3] +#endif + +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) + +# define WAN_LIST_HEAD(name, type) LIST_HEAD(name, type) +# define WAN_LIST_HEAD_INITIALIZER(head) LIST_HEAD_INITIALIZER(head) +# define WAN_LIST_ENTRY(type) LIST_ENTRY(type) +# define WAN_LIST_EMPTY(head) LIST_EMPTY(head) +# define WAN_LIST_FIRST(head) LIST_FIRST(head) +# define WAN_LIST_FOREACH(var, head, field) LIST_FOREACH(var, head, field) +# define WAN_LIST_INIT(head) LIST_INIT(head) +# define WAN_LIST_INSERT_AFTER(listelm, elm, field) LIST_INSERT_AFTER(listelm, elm, field) +/*# define WAN_LIST_INSERT_BEFORE(listelm, elm, field) LIST_INSERT_BEFORE(listelm, elm, field)*/ +# define WAN_LIST_INSERT_HEAD(head, elm, field) LIST_INSERT_HEAD(head, elm, field) +# define WAN_LIST_NEXT(elm, field) LIST_NEXT(elm, field) +# define WAN_LIST_REMOVE(elm, field) LIST_REMOVE(elm, field) + +#elif defined(__SOLARIS__) + +/* ********* S O L A R I S *****************/ + +# define WAN_LIST_HEAD(name, type) struct name { struct type * lh_first; } +# define WAN_LIST_HEAD_INITIALIZER(head) { NULL } +# define WAN_LIST_ENTRY(type) struct { struct type *le_next; struct type **le_prev; } +# define WAN_LIST_FIRST(head) ((head)->lh_first) +# define WAN_LIST_END(head) NULL +# define WAN_LIST_EMPTY(head) (WAN_LIST_FIRST(head) == WAN_LIST_END(head)) +# define WAN_LIST_NEXT(elm, field) ((elm)->field.le_next) +# define WAN_LIST_FOREACH(var, head, field) for((var) = WAN_LIST_FIRST(head); \ + (var); \ + (var) = WAN_LIST_NEXT(var, field)) +# define WAN_LIST_INIT(head) do { WAN_LIST_FIRST(head) = NULL;}\ + while(0) + +#define WAN_LIST_INSERT_HEAD(head, elm, field) do { \ + if ((WAN_LIST_NEXT((elm), field) = WAN_LIST_FIRST((head))) != NULL) \ + WAN_LIST_FIRST((head))->field.le_prev = &WAN_LIST_NEXT((elm), field);\ + WAN_LIST_FIRST((head)) = (elm); \ + (elm)->field.le_prev = &WAN_LIST_FIRST((head)); \ +} while (0) +#define WAN_LIST_INSERT_AFTER(listelm, elm, field) do { \ + if ((WAN_LIST_NEXT((elm), field) = WAN_LIST_NEXT((listelm), field)) != NULL)\ + WAN_LIST_NEXT((listelm), field)->field.le_prev = \ + &WAN_LIST_NEXT((elm), field); \ + WAN_LIST_NEXT((listelm), field) = (elm); \ + (elm)->field.le_prev = &WAN_LIST_NEXT((listelm), field); \ +} while (0) +#define WAN_LIST_REMOVE(elm, field) do { \ + if (WAN_LIST_NEXT((elm), field) != NULL) \ + WAN_LIST_NEXT((elm), field)->field.le_prev = \ + (elm)->field.le_prev; \ + *(elm)->field.le_prev = WAN_LIST_NEXT((elm), field); \ +} while (0) + + +#elif defined(__LINUX__) +/* ********* L I N U X *****************/ + +# define WAN_LIST_HEAD(name, type) struct name { struct type * lh_first; } +# define WAN_LIST_HEAD_INITIALIZER(head) { NULL } +# define WAN_LIST_ENTRY(type) struct { struct type *le_next; struct type **le_prev; } +# define WAN_LIST_FIRST(head) ((head)->lh_first) +# define WAN_LIST_END(head) NULL +# define WAN_LIST_EMPTY(head) (WAN_LIST_FIRST(head) == WAN_LIST_END(head)) +# define WAN_LIST_NEXT(elm, field) ((elm)->field.le_next) +# define WAN_LIST_FOREACH(var, head, field) for((var) = WAN_LIST_FIRST(head); \ + (var); \ + (var) = WAN_LIST_NEXT(var, field)) +# define WAN_LIST_INIT(head) do { WAN_LIST_FIRST(head) = NULL;}\ + while(0) + +#define WAN_LIST_INSERT_HEAD(head, elm, field) do { \ + if ((WAN_LIST_NEXT((elm), field) = WAN_LIST_FIRST((head))) != NULL) \ + WAN_LIST_FIRST((head))->field.le_prev = &WAN_LIST_NEXT((elm), field);\ + WAN_LIST_FIRST((head)) = (elm); \ + (elm)->field.le_prev = &WAN_LIST_FIRST((head)); \ +} while (0) +#define WAN_LIST_INSERT_AFTER(listelm, elm, field) do { \ + if ((WAN_LIST_NEXT((elm), field) = WAN_LIST_NEXT((listelm), field)) != NULL)\ + WAN_LIST_NEXT((listelm), field)->field.le_prev = \ + &WAN_LIST_NEXT((elm), field); \ + WAN_LIST_NEXT((listelm), field) = (elm); \ + (elm)->field.le_prev = &WAN_LIST_NEXT((listelm), field); \ +} while (0) +#define WAN_LIST_REMOVE(elm, field) do { \ + if (WAN_LIST_NEXT((elm), field) != NULL) \ + WAN_LIST_NEXT((elm), field)->field.le_prev = \ + (elm)->field.le_prev; \ + *(elm)->field.le_prev = WAN_LIST_NEXT((elm), field); \ +} while (0) + +#else +# error "WAN_LISTx macros not supported yet!" +#endif + +#if defined(WAN_KERNEL) + +#if defined(__FreeBSD__) +# define WAN_TAILQ_FIRST(ifp) TAILQ_FIRST(&ifp->if_addrhead) +# define WAN_TAILQ_NEXT(ifa) TAILQ_NEXT(ifa, ifa_link) +#elif defined (__OpenBSD__) +# define WAN_TAILQ_FIRST(ifp) TAILQ_FIRST(&ifp->if_addrlist) +# define WAN_TAILQ_NEXT(ifa) TAILQ_NEXT(ifa, ifa_list) +#elif defined (__NetBSD__) +# define WAN_TAILQ_FIRST(ifp) TAILQ_FIRST(&ifp->if_addrlist) +# define WAN_TAILQ_NEXT(ifa) TAILQ_NEXT(ifa, ifa_list) +#elif defined(__LINUX__) +#elif defined(__SOLARIS__) +#elif defined(__WINDOWS__) +#else +# error "WAN_TAILQ_x macros doesn't supported yet!" +#endif + +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) +# if defined(__FreeBSD__) +# define WAN_PKTATTR_DECL(pktattr) +# else +# define WAN_PKTATTR_DECL(pktattr) struct altq_pktattr pktattr +# endif +# define WAN_IFQ_SET_READY IFQ_SET_READY +# define WAN_IFQ_IS_EMPTY IFQ_IS_EMPTY +# define WAN_IFQ_INC_LEN IFQ_INC_LEN +# define WAN_IFQ_DEC_LEN IFQ_DEC_LEN +# define WAN_IFQ_INC_DROPS IFQ_INC_DROPS +# define WAN_IFQ_SET_MAXLEN IFQ_SET_MAXLEN +# define WAN_IFQ_PURGE IFQ_PURGE +# if (__FreeBSD_version > 503000) +# define WAN_IFQ_ENQUEUE(ifq, m, pattr, err) IFQ_ENQUEUE((ifq),(m),(err)) +# else +# define WAN_IFQ_ENQUEUE IFQ_ENQUEUE +# endif +# define WAN_IFQ_DEQUEUE IFQ_DEQUEUE +# define WAN_IFQ_POLL IFQ_POLL +# define WAN_IFQ_CLASSIFY IFQ_CLASSIFY +# define WAN_IFQ_INIT IFQ_INIT +# define WAN_IFQ_LEN IFQ_LEN +#elif defined(__LINUX__) +# define WAN_IFQ_INIT(ifq, max_pkt) skb_queue_head_init((ifq)) +# define WAN_IFQ_PURGE(ifq) skb_queue_purge((ifq)) +# define WAN_IFQ_ENQUEUE(ifq, skb, arg, err) skb_queue_tail((ifq), (skb)) +# define WAN_IFQ_LEN(ifq) skb_queue_len((ifq)) +#elif defined(__WINDOWS__) +#else +# error "Undefined IFQ_x macros!" +#endif + +#if defined(__FreeBSD__) +# if (__FreeBSD_version < 410000) +# define WAN_TASKLET_INIT(task, priority, func, arg) \ + (task)->running = 0; \ + (task)->task_func = func; (task)->data = arg +# define WAN_TASKLET_SCHEDULE(task) \ + if (!wan_test_bit(0, &(task)->running)){ \ + wan_set_bit(0, &(task)->running); \ + (task)->task_func((task)->data, 0); \ + } +# define __WAN_TASKLET_SCHEDULE(task) WAN_TASKLET_SCHEDULE(task) + +# define WAN_TASKLET_RUNNING(task) \ + wan_test_bit(0, &(task)->running) + +# define WAN_TASKLET_END(task) wan_clear_bit(0, &(task)->running) +# define WAN_TASKLET_RUNNING(task) \ + wan_test_bit(0, &(task)->running) + +# define WAN_TASKLET_KILL(task) +# else +# define WAN_TASKLET_INIT(task, priority, func, arg) \ + (task)->running = 0; \ + TASK_INIT(&(task)->task_id, priority, func, (void*)arg) +# define WAN_TASKLET_SCHEDULE(task) \ + if (!wan_test_bit(0, &(task)->running)){ \ + wan_set_bit(0, &(task)->running); \ + taskqueue_enqueue(taskqueue_swi, &(task)->task_id); \ + } +# define __WAN_TASKLET_SCHEDULE(task) WAN_TASKLET_SCHEDULE(task) + +# define WAN_TASKLET_RUNNING(task) \ + wan_test_bit(0, &(task)->running) + +/* taskqueue_run(taskqueue_swi); \*/ +# define WAN_TASKLET_END(task) wan_clear_bit(0, &(task)->running) +# define WAN_TASKLET_KILL(task) +# endif +#elif defined(__OpenBSD__) || defined(__NetBSD__) +# define WAN_TASKLET_INIT(task, priority, func, arg) \ + (task)->running = 0; \ + (task)->task_func = func; (task)->data = arg +# define WAN_TASKLET_SCHEDULE(task) \ + if (!wan_test_bit(0, &(task)->running)){ \ + wan_set_bit(0, &(task)->running); \ + (task)->task_func((task)->data, 0); \ + } + +# define __WAN_TASKLET_SCHEDULE(task) WAN_TASKLET_SCHEDULE(task) + +# define WAN_TASKLET_RUNNING(task) \ + wan_test_bit(0, &(task)->running) +# define WAN_TASKLET_END(task) wan_clear_bit(0, &(task)->running) +# define WAN_TASKLET_KILL(task) + + +#elif defined(__LINUX__) + +# define WAN_TASKLET_INIT(task, priority, func, arg) \ + (task)->running = 0; \ + tasklet_init(&(task)->task_id,func,(unsigned long)arg) + +# define WAN_TASKLET_SCHEDULE(task) \ + wan_set_bit(0, &(task)->running); \ + tasklet_schedule(&(task)->task_id); + +#if 0 +# define WAN_WP_TASKLET_SCHEDULE_PER_CPU(task,cpu) \ + wan_set_bit(0, &(task)->running); \ + wp_tasklet_hi_schedule_per_cpu(&(task)->task_id,cpu); +#endif + +# define WAN_TASKLET_RUNNING(task) \ + wan_test_bit(0, &(task)->running) + +# define WAN_TASKLET_END(task) wan_clear_bit(0, &(task)->running) +# define WAN_TASKLET_KILL(task) tasklet_kill(&(task)->task_id) + + +#elif defined(__WINDOWS__) +#else +# error "Undefined WAN_TASKLET_x macro!" +#endif + +#if defined(__FreeBSD__) +# if (__FreeBSD_version < 410000) +# define WAN_TASKQ_INIT(task, priority, func, arg) \ + (task)->tfunc = func; task->data = arg +# else +# define WAN_TASKQ_INIT(task, priority, func, arg) \ + TASK_INIT(&task->tqueue, priority, func, arg) +# endif +#elif defined(__OpenBSD__) +# define WAN_TASKQ_INIT(task, priority, func, arg) \ + (task)->tfunc = func; task->data = arg +#elif defined(__NetBSD__) +# define WAN_TASKQ_INIT(task, priority, func, arg) \ + (task)->tfunc = func; task->data = arg +#elif defined(__LINUX__) +# define WAN_TASKQ_INIT(task, priority, func, arg) \ + INIT_WORK((&task->tqueue),func,arg) +#elif defined(__WINDOWS__) +#else +# error "Undefined WAN_TASKQ_INIT macro!" +#endif + +#if defined(__FreeBSD__) && (__FreeBSD_version >= 410000) +# define WAN_IS_TASKQ_SCHEDULE +# define WAN_TASKQ_SCHEDULE(task) \ + taskqueue_enqueue(taskqueue_swi, &task->tqueue);\ + taskqueue_run(taskqueue_swi) +#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) +# define WAN_TASKQ_SCHEDULE(task) \ + task->tfunc(task->data, 0) +#elif defined(__LINUX__) +# define WAN_IS_TASKQ_SCHEDULE +# define WAN_TASKQ_SCHEDULE(task) \ + wan_schedule_task(&task->tqueue) +#elif defined(__WINDOWS__) +#else +# error "Undefined WAN_TASKQ_SCHEDULE macro!" +#endif + +#if defined(__LINUX__) +# define WAN_COPY_FROM_USER(k,u,l) copy_from_user(k,u,l) +# define WAN_COPY_TO_USER(u,k,l) copy_to_user(u,k,l) +#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) +# define WAN_COPY_FROM_USER(k,u,l) copyin(u,k,l) +# define WAN_COPY_TO_USER(u,k,l) copyout(k,u,l) +#elif defined(__WINDOWS__) +#else +# error "Undefined WAN_COPY_FROM_USER/WAN_COPY_TO_USER macros!" +#endif + +#if defined(__LINUX__) +# if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,43)) +# define WAN_NETIF_WAKE_QUEUE(dev) do { \ + clear_bit(0, &dev->tbusy); \ + mark_bh(NET_BH); \ + } while(0) +# define WAN_NETIF_START_QUEUE(dev) do { \ + dev->tbusy = 0; \ + dev->interrupt = 0; \ + dev->start = 1; \ + } while(0); +# define WAN_NETIF_STOP_QUEUE(dev) set_bit(0, &dev->tbusy) +# define WAN_NETIF_RUNNING(dev) dev->start +# define WAN_NETDEVICE_START(dev) dev->start = 1 +# define WAN_NETDEVICE_STOP(dev) dev->start = 0 +# define WAN_NETIF_QUEUE_STOPPED(dev) test_bit(0,&dev->tbusy) +# define WAN_NETIF_CARRIER_OFF(dev) +# define WAN_NETIF_CARRIER_ON(dev) +# define WAN_NETIF_CARRIER_OK(dev) 1 +# else +#if 0 +# define WAN_NETIF_WAKE_QUEUE(dev) do{ \ + if (((wanpipe_common_t *)dev->priv)->usedby == TDM_VOICE){ \ + DEBUG_EVENT("%s: TDM VOICE not waking but starting!!!!\n",dev->name); \ + netif_start_queue(dev); \ + }else{ \ + netif_wake_queue(dev); \ + } \ + }while(0) +#endif +# define WAN_NETIF_WAKE_QUEUE(dev) netif_wake_queue(dev); +# define WAN_NETIF_START_QUEUE(dev) netif_start_queue(dev) +# define WAN_NETIF_STOP_QUEUE(dev) netif_stop_queue(dev) +# define WAN_NETIF_RUNNING(dev) netif_running(dev) +# define WAN_NETDEVICE_START(dev) +# define WAN_NETDEVICE_STOP(dev) +# define WAN_NETIF_QUEUE_STOPPED(dev) netif_queue_stopped(dev) +# define WAN_NETIF_CARRIER_OFF(dev) netif_carrier_off(dev) +# define WAN_NETIF_CARRIER_ON(dev) netif_carrier_on(dev) +# define WAN_NETIF_CARRIER_OK(dev) netif_carrier_ok(dev) +# endif +# define WAN_NETIF_UP(dev) ((dev)->flags&IFF_UP) +# define WAN_NET_RATELIMIT net_ratelimit + +#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) +# define WAN_NETIF_QUEUE_STOPPED(dev) (dev)->if_flags & IFF_DRV_OACTIVE +# define WAN_NETIF_WAKE_QUEUE(dev) (dev)->if_flags &= ~IFF_DRV_OACTIVE +#if 0 +# define WAN_NETIF_STOP_QUEUE(dev) +# define WAN_NETIF_START_QUEUE(dev) +#endif +# define WAN_NETIF_STOP_QUEUE(dev) (dev)->if_flags |= IFF_DRV_OACTIVE +# define WAN_NETIF_START_QUEUE(dev) (dev)->if_flags &= ~IFF_DRV_OACTIVE +# define WAN_NETIF_RUNNING(dev) 1 +# define WAN_NETIF_UP(dev) ((dev)->if_flags&IFF_UP) +# define WAN_NETDEVICE_STOP(dev) +# define WAN_NETDEVICE_START(dev) +# define NET_ADMIN_CHECK() +# define WAN_NET_RATELIMIT() 1 +# define MOD_INC_USE_COUNT +# define MOD_DEC_USE_COUNT + +# define WAN_NETIF_CARRIER_OFF(dev) +# define WAN_NETIF_CARRIER_ON(dev) +# define WAN_NETIF_CARRIER_OK(dev) 1 + +#elif defined(__WINDOWS__) +#else +# error "Undefined WAN_NETIF_x macros!" +#endif + +#if defined(__LINUX__) +# define WAN_BPF_REPORT(dev,m) +#elif defined(__FreeBSD__) +# if (__FreeBSD_version > 500000) +# define WAN_BPF_REPORT(dev,m) bpf_mtap((dev)->if_bpf, (m)) +# else +# define WAN_BPF_REPORT(dev,m) bpf_mtap((dev), (m)) +# endif +#elif defined(__OpenBSD__) || defined(__NetBSD__) +# define WAN_BPF_REPORT(dev,m) bpf_mtap((dev)->if_bpf, (m)); +#elif defined(__WINDOWS__) +#else +# error "Undefined WAN_BPF_REPORT macro!" +#endif + + +#if defined (__LINUX__) +# define WAN_DEV_PUT(dev) wan_atomic_dec(&(dev)->refcnt) +# define WAN_DEV_HOLD(dev) wan_atomic_inc(&(dev)->refcnt) +# define __WAN_PUT(str) wan_atomic_dec(&(str)->refcnt) +# define WAN_PUT(str) if (atomic_dec_and_test(&(str)->refcnt)){ \ + wan_kfree(str); \ + } +# define WAN_HOLD(str) wan_atomic_inc(&(str)->refcnt) +#elif defined(__FreeBSD__) +# define WAN_DEV_PUT(dev) +# define WAN_DEV_HOLD(dev) +# define __WAN_PUT(str) wan_atomic_dec(&(str)->refcnt) +# define WAN_PUT(str) wan_atomic_dec(&str->refcnt); \ + if (str->refcnt){ \ + WAN_FREE(str); \ + } +# define WAN_HOLD(str) wan_atomic_inc(&(str)->refcnt) +#elif defined(__NetBSD__) || defined(__OpenBSD__) +# define WAN_DEV_PUT(dev) +# define WAN_DEV_HOLD(dev) +# define __WAN_PUT(str) str->refcnt-- +# define WAN_PUT(str) str->refcnt--; \ + if (str->refcnt){ \ + WAN_FREE(str); \ + } +# define WAN_HOLD(str) str->refcnt++ +#elif defined(__WINDOWS__) +#else +# warning "Undefined WAN_HOLD/WAN_PUT macro!" +#endif + +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) +# ifdef ENABLE_SPPP +# define WAN_SPPP_ENABLED 1 +# define WAN_SPPP_ATTACH(ifp) sppp_attach(ifp) +# define WAN_SPPP_DETACH(ifp) sppp_detach(ifp) +# define WAN_SPPP_FLUSH(ifp) sppp_flush(ifp) +# define WAN_SPPP_PICK(ifp) sppp_pick(ifp) +# define WAN_SPPP_DEQUEUE(ifp) sppp_dequeue(ifp) +# define WAN_SPPP_ISEMPTY(ifp) sppp_isempty(ifp) +# define WAN_SPPP_INPUT(ifp,skb) sppp_input(ifp,skb) +# define WAN_SPPP_IOCTL(ifp,cmd,data) sppp_ioctl(ifp,cmd,data); +# else +# define WAN_SPPP_ENABLED 0 +# define WAN_SPPP_ATTACH(ifp) +# define WAN_SPPP_DETACH(ifp) +# define WAN_SPPP_FLUSH(ifp) +# define WAN_SPPP_PICK(ifp) NULL +# define WAN_SPPP_DEQUEUE(ifp) NULL +# define WAN_SPPP_ISEMPTY(ifp) 0 +# define WAN_SPPP_INPUT(ifp,skb) +# define WAN_SPPP_IOCTL(ifp,cmd,data) -EOPNOTSUPP +# endif +#elif defined(__LINUX__) +# define WAN_SPPP_ENABLED 1 +# define WAN_SPPP_IOCTL(ifp,cmd,data) -EOPNOTSUPP +#elif defined(__WINDOWS__) +#else +# error "Undefined WAN_SPPP_x macros!" +#endif + +#define WAN_MAX_TRACE_TIMEOUT (5*HZ) + +#if 0 +/* + * Variable argument list macro definitions + */ +#ifndef _VALIST +#define _VALIST +typedef char *va_list; +#endif /* _VALIST */ +#define _WAN_VA_SIZE(type) (((sizeof(type) + sizeof(long) - 1) / sizeof(long)) * sizeof(long)) + +#define WAN_VA_START(ap, A) ((ap) = (va_list) &(A) + _WAN_VA_SIZE(A)) +#define WAN_VA_ARG(ap, T) (*(T *)((ap) += _WAN_VA_SIZE(T),(ap) - _WAN_VA_SIZE (T))) +#define WAN_VA_END(ap) (void) 0 +#endif + + +/**************************************************************************** +** T Y P E D E F S +****************************************************************************/ +# if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) +/* + * Ethernet statistics collection data + */ +struct net_device_stats +{ + unsigned long rx_packets; /* total packets received */ + unsigned long tx_packets; /* total packets transmited */ + unsigned long rx_bytes; /* total bytes received */ + unsigned long tx_bytes; /* total bytes transmited */ + unsigned long rx_errors; /* bad packet received */ + unsigned long tx_errors; /* packet transmit problems */ + unsigned long rx_dropped; /* no space in buffers */ + unsigned long tx_dropped; /* no space available */ + unsigned long multicast; /* multicast packet received */ + unsigned long collisions; + + /* detailed rx_errors */ + unsigned long rx_length_errors; + unsigned long rx_over_errors; /* receiver ring off buff overflow */ + unsigned long rx_crc_errors; /* recv'd pkt with crc error */ + unsigned long rx_frame_errors; /* recv'd frame alignment error */ + unsigned long rx_fifo_errors; /* recv'r fifo overrun */ + unsigned long rx_missed_errors; /* receiver missed packet */ + + /* detailed tx_errors */ + unsigned long tx_aborted_errors; + unsigned long tx_carrier_errors; + unsigned long tx_fifo_errors; + unsigned long tx_heartbeat_errors; + unsigned long tx_window_errors; + + /* for cslip etc */ + unsigned long rx_compressed; + unsigned long tx_compressed; +}; +#endif + +/**************************************************************************** +** F U N C T I O N P R O T O T Y P E S +****************************************************************************/ +unsigned int wan_dec2uint (unsigned char* str, int len); +char* wanpipe_get_state_string (void*); +void wanpipe_set_state (void*, int); +char wanpipe_get_state (void*); +void wanpipe_card_lock_irq (void *,unsigned long *); +void wanpipe_card_unlock_irq (void *,unsigned long *); +void wanpipe_set_baud(void*card,unsigned int baud); +unsigned long wan_get_ip_addr (void*, int); +int wan_udp_pkt_type (void*, caddr_t); +int wan_reply_udp (void*, unsigned char*, unsigned int); +unsigned short wan_calc_checksum(char *data, int len); +void wanpipe_debug_timer_init(void*); +void wan_trace_info_init(wan_trace_t *trace, int max_trace_queue); +int wan_trace_purge (wan_trace_t *trace); +int wan_trace_enqueue(wan_trace_t *trace, void *skb_ptr); +int wan_tracing_enabled(wan_trace_t *trace_info); +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) +void wanpipe_debugging (void* data, int pending); +#else +void wanpipe_debugging (unsigned long data); +#endif + +/**************************************************************************** +** I N L I N E F U N C T I O N S +****************************************************************************/ +/******************* WANPIPE MALLOC/FREE FUNCTION ******************/ +/* +** wan_malloc - +*/ +static __inline void* wan_malloc(int size) +{ + void* ptr = NULL; +#if defined(__LINUX__) + ptr = kmalloc(size, GFP_ATOMIC); + if (ptr){ + DEBUG_ADD_MEM(size); + } +#elif defined(__SOLARIS__) + ptr=kmem_alloc(size,KM_NOSLEEP); +#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) + ptr = malloc(size, M_DEVBUF, M_NOWAIT); +#elif defined(__WINDOWS__) + ptr = ExAllocatePool(NonPagedPool, size); +#else +# error "wan_malloc() function is not supported yet!" +#endif + if (ptr){ + memset(ptr, 0, size); + DEBUG_ADD_MEM(size); + } + return ptr; +} + +/* +** wan_free - +*/ +static __inline void wan_free(void* ptr) +{ + if (!ptr){ + DEBUG_EVENT("wan_free: NULL PTR !!!!!\n"); + return; + } + +#if defined(__LINUX__) + kfree(ptr); +#elif defined(__SOLARIS__) + kmem_free(ptr,sizeof(*ptr)); + DEBUG_EVENT("%s: Feeing Size %i\n",__FUNCTION__,sizeof(*ptr)); +#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) + return free(ptr, M_DEVBUF); +#elif defined(__WINDOWS__) + ExFreePool(ptr); +#else +# error "wan_free() function is not supported yet!" +#endif +} + +static __inline void* wan_vmalloc(int size) +{ + void* ptr = NULL; +#if defined(__LINUX__) + ptr = vmalloc(size); + if (ptr){ + DEBUG_ADD_MEM(size); + } +#elif defined(__FreeBSD__) + ptr = (caddr_t)kmem_alloc(kernel_map, size + sizeof(vm_size_t)); + if (ptr){ + vm_size_t *ptr1 = (vm_size_t*)ptr; + bzero(ptr, size); + *ptr1 = size + sizeof(vm_size_t); + ptr = ptr1++; + } +#elif defined(__OpenBSD__) || defined(__NetBSD__) + ptr = (caddr_t)uvm_km_alloc(kernel_map, size + sizeof(vsize_t)); + if (ptr){ + vsize_t *ptr1 = (vsize_t*)ptr; + bzero(ptr, size); + *ptr1 = size + sizeof(vsize_t); + ptr = ptr1++; + } +#elif defined(__SOLARIS__) +#elif defined(__WINDOWS__) +#else +# error "wan_vmalloc() function is not supported yet!" +#endif + if (ptr){ + memset(ptr, 0, size); + DEBUG_ADD_MEM(size); + } + return ptr; +} + +/* +** wan_vfree - +*/ +static __inline void wan_vfree(void* ptr) +{ + if (!ptr){ + DEBUG_EVENT("wan_vfree: NULL PTR !!!!!\n"); + return; + } +#if defined(__LINUX__) + vfree(ptr); +#elif defined(__FreeBSD__) + { + vm_size_t *ptr1 = (vm_size_t*)ptr; + ptr1 --; + kmem_free(kernel_map, (vm_offset_t)ptr1, (vm_size_t)*ptr1); + } +#elif defined(__OpenBSD__) || defined(__NetBSD__) + { + vsize_t *ptr1 = (vsize_t*)ptr; + ptr1 --; + uvm_km_free(kernel_map, (vaddr_t)ptr1, (vsize_t)*ptr1); + } +#elif defined(__SOLARIS__) +#elif defined(__WINDOWS__) +#else +# error "wan_free() function is not supported yet!" +#endif + return; +} + + +/******************* WANPIPE VIRT<->BUS SPACE FUNCTION ******************/ +/* +** wan_virt2bus +*/ +static __inline unsigned long wan_virt2bus(unsigned long* ptr) +{ +#if defined(__LINUX__) + return virt_to_bus(ptr); +#elif defined(__FreeBSD__) + return vtophys((vm_offset_t)ptr); +#elif defined(__OpenBSD__) || defined(__NetBSD__) + return vtophys((vaddr_t)ptr); +#elif defined(__WINDOWS__) +#else +# error "wan_virt2bus() function is not supported yet!" +#endif +} + +/* +** wan_bus2virt +*/ +static __inline unsigned long* wan_bus2virt(unsigned long virt_addr) +{ +#if defined(__LINUX__) + return bus_to_virt(virt_addr); +#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) + return (unsigned long*)virt_addr; +#elif defined(__WINDOWS__) +#else +# error "wan_bus2virt() function is not supported yet!" +#endif +} + + +/******************* WANPIPE DMA FUNCTION ******************/ + +/* +** wan_dma_alloc +*/ +static __inline int +wan_dma_alloc(void* hw, wan_dma_descr_t* dma_descr) +{ + int err = 0; +#if defined(__FreeBSD__) + err = bus_dma_tag_create(/*parent*/NULL, + /*alignemnt*/1, + /*boundary*/0, + /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, + /*highaddr*/BUS_SPACE_MAXADDR, + /*filter*/NULL, /*filterarg*/NULL, + /*maxsize*/dma_descr->max_length, +# if (__FreeBSD_version >= 502000) + /*nsegments*/1, +# else + /*nsegments*/BUS_SPACE_UNRESTRICTED, +# endif + /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT, + /*flags*/0, +# if (__FreeBSD_version >= 502000) + /*lockfunc*/NULL, /*lockfuncarg*/NULL, +# endif + &dma_descr->dmat); + if (err){ + DEBUG_EVENT("Failed create DMA tag (size=%ld)!\n", + dma_descr->max_length); + dma_descr->max_length = 0; + return err; + } + err = bus_dmamem_alloc(dma_descr->dmat, + (void**)&dma_descr->vAddr, + BUS_DMA_NOWAIT, + &dma_descr->dmamap); + if (err){ + DEBUG_EVENT("Failed allocate DMA (size=%ld)!\n", + dma_descr->max_length); + bus_dma_tag_destroy(dma_descr->dmat); + dma_descr->max_length = 0; + return err; + } +#elif defined(__OpenBSD__) || defined(__NetBSD__) + err = bus_dmamem_alloc(dma_descr->dmat, /* dma tag */ + dma_descr->max_length, /* size */ + PAGE_SIZE, /* alignment */ + 0, /* boundary */ + &dma_descr->dmaseg, /* serments */ + 1, /* num of segments */ + &dma_descr->rsegs, /* R num of segments */ + BUS_DMA_NOWAIT); + if (err){ + DEBUG_EVENT("Failed allocate DMA segment (size=%ld)!\n", + dma_descr->max_length); + dma_descr->max_length = 0; + return err; + } + err = bus_dmamem_map(dma_descr->dmat, /* dma tag */ + &dma_descr->dmaseg, /* segments */ + dma_descr->rsegs, /* return num of segments */ + dma_descr->max_length, /* size */ + (caddr_t*)&dma_descr->vAddr, /* kernel virtual address */ + BUS_DMA_NOWAIT); + if (err){ + DEBUG_EVENT("Failed map DMA segment (size=%ld)!\n", + dma_descr->max_length); + dma_descr->max_length = 0; + bus_dmamem_free(dma_descr->dmat, &dma_descr->dmaseg, dma_descr->rsegs); + return err; + } +#elif defined(__LINUX__) + dma_descr->vAddr = pci_alloc_consistent(NULL, + dma_descr->max_length, + (dma_addr_t *)&dma_descr->pAddr); + if (dma_descr->vAddr == NULL){ + err = -ENOMEM; + } +#elif defined(__WINDOWS__) + return -EINVAL; +#else +# error "wan_dma_alloc() function is not supported yet!" +#endif + return err; +} + +/* +** wan_dma_free +*/ +static __inline int +wan_dma_free(void* hw, wan_dma_descr_t* dma_descr) +{ +#if defined(__FreeBSD__) + bus_dmamem_free(dma_descr->dmat, dma_descr->vAddr, dma_descr->dmamap); + return bus_dma_tag_destroy(dma_descr->dmat); +#elif defined(__OpenBSD__) || defined(__NetBSD__) + bus_dmamem_unmap(dma_descr->dmat, (caddr_t)dma_descr->vAddr, dma_descr->max_length); + bus_dmamem_free(dma_descr->dmat, &dma_descr->dmaseg, dma_descr->rsegs); +#elif defined(__LINUX__) + + DEBUG_TEST("Freeing Pages 0x%p len=%li order=%i\n", + dma_descr->vAddr, + dma_descr->max_length, + get_order(dma_descr->max_length)); + + pci_free_consistent(NULL, dma_descr->max_length,dma_descr->vAddr,dma_descr->pAddr); + dma_descr->vAddr = NULL; + dma_descr->pAddr = 0; +#elif defined(__WINDOWS__) + return -EINVAL; +#else +# error "wan_dma_free() function is not supported yet!" +#endif + return 0; +} + +static __inline unsigned long* wan_dma_get_vaddr(void* card, wan_dma_descr_t* dma) +{ + return dma->vAddr; +} + +static __inline unsigned long wan_dma_get_paddr(void* card, wan_dma_descr_t* dma) +{ + return wan_virt2bus(dma->vAddr); +} + + + + + +/********************** WANPIPE TIMER FUNCTION **************************/ + + +static __inline int wan_getcurrenttime(unsigned long *sec, unsigned long *usec) +{ +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) + struct timeval tv; + microtime(&tv); + if (sec) *sec = tv.tv_sec; + if (usec) *usec = tv.tv_usec; + return 0; +#elif defined(__WINDOWS__) + LARGE_INTEGER tv; + NdisGetCurrentSystemTime(&tv); + if (sec) *sec = (unsigned long)tv.QuadPart; + return 0; +#elif defined(__LINUX__) + struct timeval tv; + do_gettimeofday(&tv); + if (sec) *sec = tv.tv_sec; + if (usec) *usec = tv.tv_usec; + return 0; +#else +# error "wan_getcurrenttime() function is not supported yet!" +#endif +} + +/* +** wan_init_timer +*/ +static __inline void +wan_init_timer(wan_timer_t* wan_timer, wan_timer_func_t timer_func, wan_timer_arg_t arg) +{ +#if defined(__LINUX__) + init_timer(&wan_timer->timer_info); + wan_timer->timer_info.function = timer_func; + wan_timer->timer_info.data = arg; +#elif defined(__FreeBSD__) + /* FIXME_ADSL_TIMER */ + callout_handle_init(&wan_timer->timer_info); + wan_timer->timer_func = timer_func; + wan_timer->timer_arg = arg; +#elif defined(__OpenBSD__) + timeout_set(&wan_timer->timer_info, timer_func, (void*)arg); + wan_timer->timer_func = timer_func; + wan_timer->timer_arg = arg; +#elif defined(__NetBSD__) + callout_init(&wan_timer->timer_info); + wan_timer->timer_func = timer_func; + wan_timer->timer_arg = arg; +#elif defined(__WINDOWS__) +#else +# error "wan_init_timer() function is not supported yet!" +#endif /* linux */ +} + +/* +** wan_del_timer +*/ +static __inline void +wan_del_timer(wan_timer_t* wan_timer) +{ +#if defined(__LINUX__) + if (!wan_timer->timer_info.function){ + if (WAN_NET_RATELIMIT()){ + DEBUG_EVENT("%s:%d Warning: WAN Timer del error: func=%p\n", + __FUNCTION__,__LINE__, + wan_timer->timer_info.function); + } + return; + } + del_timer(&wan_timer->timer_info); +#elif defined(__FreeBSD__) + untimeout(wan_timer->timer_func, + (void*)wan_timer->timer_arg, + wan_timer->timer_info); + callout_handle_init(&wan_timer->timer_info); +#elif defined(__OpenBSD__) + timeout_del(&wan_timer->timer_info); +#elif defined(__NetBSD__) + callout_stop(&wan_timer->timer_info); +#else +# error "wan_del_timer() function is not supported yet!" +#endif /* linux */ +} + +/* +** wan_add_timer +*/ +static __inline void +wan_add_timer(wan_timer_t* wan_timer, unsigned long delay) +{ +#if defined(__LINUX__) + if (timer_pending(&wan_timer->timer_info) || + !wan_timer->timer_info.function){ + if (WAN_NET_RATELIMIT()){ + DEBUG_EVENT("%s:%d Warning: WAN Timer add error: pending or func=%p\n", + __FUNCTION__,__LINE__, + wan_timer->timer_info.function); + } + return; + } + wan_timer->timer_info.expires = SYSTEM_TICKS + delay; + add_timer(&wan_timer->timer_info); +#elif defined(__FreeBSD__) + wan_timer->timer_info = + timeout(wan_timer->timer_func, + (void*)wan_timer->timer_arg, + delay); + WAN_ASSERT1(wan_timer->timer_info.callout == NULL); +#elif defined(__OpenBSD__) + timeout_add(&wan_timer->timer_info, delay); +#elif defined(__NetBSD__) + wan_timer->timer_info.c_time = delay; + callout_reset(&wan_timer->timer_info, + delay, + wan_timer->timer_func, + wan_timer->timer_arg); +#else +# error "wan_add_timer() function is not supported yet!" +#endif /* linux */ +} + +/********************** WANPIPE KERNEL BUFFER **************************/ +/* +** wan_skb_data() - +** Returns pointer to data. +*/ +static __inline unsigned char* wan_skb_data(void* skb) +{ +#if defined(__LINUX__) + return ((struct sk_buff*)skb)->data; +#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) + return mtod((struct mbuf*)skb, caddr_t); +#elif defined(__SOLARIS__) + return ((netskb_t*)mp)->b_rptr; +#else +# error "wan_skb_data() function is not supported yet!" +#endif +} + +/* +** wan_skb_tail() - +** Returns pointer to data. +*/ +static __inline unsigned char* wan_skb_tail(void* skb) +{ +#if defined(__LINUX__) + return ((struct sk_buff*)skb)->tail; +#elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) + return mtod((struct mbuf*)skb, caddr_t) + ((struct mbuf*)skb)->m_len; +#elif defined(__SOLARIS__) + return ((netskb_t*)mp)->b_wptr; +#else +# error "wan_skb_tail() function is not supported yet!" +#endif +} + +/* +** wan_skb_append() - +** Returns pointer to data. +*/ +static __inline void wan_skb_append(void* skbprev, void *skb, void *list) +{ +#if defined(__LINUX__) +# if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)) + skb_append(skbprev,skb); +# else + skb_append(skbprev,skb,list); +# endif +#elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) + m_cat (skbprev, skb); +#else +# error "wan_skb_append() function is not supported yet!" +#endif +} + + + +/* +** wan_skb_len() - +** Returns current kernel buffer length. +*/ +static __inline int wan_skb_len(void* skb) +{ +#if defined(__LINUX__) + return ((struct sk_buff*)skb)->len; +#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) + return ((struct mbuf*)skb)->m_len; +#elif defined(__SOLARIS__) + mblk_t* tmp = skb; + int len = 0; + while(tmp) { + len += (tmp->b_wptr - tmp->b_rptr); + tmp = tmp->b_cont; + } + return len; +#else +# error "wan_skb_len() function is not supported yet!" +#endif +} + +/* +** wan_skb_free() - +** Free kernel memory buffer. +*/ +static __inline void wan_skb_free(void* skb) +{ +#if defined(__LINUX__) +#if defined(WAN_DEBUG_MEM) + DEBUG_SUB_MEM(((struct sk_buff*)skb)->truesize); +#endif + dev_kfree_skb_any(skb); +#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) + m_freem(skb); +#elif defined(__SOLARIS__) + freemsg(skb); +#else +# error "wan_skb_free() function is not supported yet!" +#endif +} + +/* +** wan_skb_set_mark() - +** Set mark for skb. +*/ +static __inline void wan_skb_set_mark(void* pskb) +{ +#if defined(__LINUX__) + return; +#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) + ((netskb_t*)pskb)->m_flags |= WAN_MFLAG_PRV; +#endif + return; +} + +/* +** wan_skb_clear_mark() - +** Clear mark from skb. +*/ +static __inline void wan_skb_clear_mark(void* pskb) +{ +#if defined(__LINUX__) + return; +#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) + ((netskb_t*)pskb)->m_flags &= ~WAN_MFLAG_PRV; +#endif + return; +} + +/* +** wan_skb_mark() - +** Return 1 if mark is set, otherwise 0. +*/ +static __inline int wan_skb_mark(void* pskb) +{ +#if defined(__LINUX__) + return 0; +#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) + return (((netskb_t*)pskb)->m_flags & WAN_MFLAG_PRV); +#endif + return 0; +} + +/* +** wan_skb_alloc() - +** Allocate kernel buffer with len. +*/ +static __inline void* wan_skb_alloc(unsigned int len) +{ +#if defined(__LINUX__) +#if defined(WAN_DEBUG_MEM) + struct sk_buff *skb=dev_alloc_skb(len); + if (skb){ + DEBUG_ADD_MEM(skb->truesize); + } + return (void*)skb; +#else + return (void*)dev_alloc_skb(len); +#endif +#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) + struct mbuf *new = NULL; + + if (len){ + MGETHDR(new, M_DONTWAIT, MT_DATA); + }else{ + MGET(new, M_DONTWAIT, MT_DATA); + } + if (new){ + if (new->m_flags & M_PKTHDR){ + new->m_pkthdr.len = 0; + } + new->m_len = 0; + MCLGET(new, M_DONTWAIT); + if ((new->m_flags & M_EXT) == 0){ + wan_skb_free(new); + return NULL; + } + /* Always reserve extra 16 bytes (as Linux) + ** for the header */ + new->m_data += 16; + wan_skb_set_mark(new); + return (void*)new; + } + return NULL; +#elif defined (__SOLARIS__) + mblk_t *mp=allocb(ROUNDUP(len+16, IOC_LINESIZE), BPRI_MED); + if (mp){ + caddr_t ptr= (caddr_t) ROUNDUP((long)mp->b_rptr, 1); + mp->b_rptr=(uchar_t *)ptr+16; + } + return mp; +#else +# error "wan_skb_alloc() function is not supported yet!" +#endif +} + +/* +** wan_skb_set_dev() - +** Set device point. +*/ +static __inline void wan_skb_set_dev(void* pskb, void* dev) +{ +#if defined(__LINUX__) + struct sk_buff *skb = (struct sk_buff*)pskb; + if (skb){ + skb->dev = dev; + } +#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) + netskb_t* m = (netskb_t*)pskb; + if (m){ + m->m_pkthdr.rcvif = dev; + } +#else +# error "wan_skb_set_dev() function is not supported yet!" +#endif +} + +static __inline void wan_skb_set_protocol(void* pskb, unsigned int protocol) +{ +#if defined(__LINUX__) + struct sk_buff *skb = (struct sk_buff*)pskb; + if (skb){ + skb->protocol = htons(protocol); + } +#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) + struct mbuf *mbuf = (struct mbuf*)pskb; + if (protocol == ETH_P_IPX){ + mbuf->m_flags |= M_PROTO1; + } +#else + +# warning "wan_skb_set_protocol() function is not supported yet!" +#endif +} + +static __inline void wan_skb_set_raw(void* pskb) +{ +#if defined(__LINUX__) + struct sk_buff *skb = (struct sk_buff*)pskb; + if (skb){ + skb->mac.raw = skb->data; + skb->nh.raw = skb->data; + } +#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) +#else +# warning "wan_skb_set_raw() function is not supported yet!" +#endif +} + + + +/* +** wan_skb_set_csum() - +** Set checksum. +*/ +static __inline void wan_skb_set_csum(void* skb, unsigned int csum) +{ +#if defined(__LINUX__) + struct sk_buff *sk = (struct sk_buff*)skb; + if (sk){ + sk->csum = csum; + } +#elif defined(__OpenBSD__) + netskb_t* m = (netskb_t*)skb; + if (m){ +# if defined(OpenBSD3_8) || defined(OpenBSD3_9) + m->m_pkthdr.csum_flags = csum; +# else + m->m_pkthdr.csum = csum; +# endif + } +#elif defined(__NetBSD__) || defined(__FreeBSD__) + netskb_t* m = (netskb_t*)skb; + if (m){ + m->m_pkthdr.csum_data = csum; + } +#else +# error "wan_skb_set_csum() function is not supported yet!" +#endif +} + +/* +** wan_skb_csum() - +** Return checksum value. +*/ +static __inline unsigned int wan_skb_csum(void* skb) +{ +#if defined(__LINUX__) + struct sk_buff *sk = (struct sk_buff*)skb; + return (sk) ? sk->csum : 0; +#elif defined(__NetBSD__) || defined(__FreeBSD__) + netskb_t* m = (netskb_t*)skb; + return (m) ? m->m_pkthdr.csum_data : 0; +#elif defined(__OpenBSD__) + netskb_t* m = (netskb_t*)skb; +# if defined(OpenBSD3_8) || defined(OpenBSD3_9) + return (m) ? m->m_pkthdr.csum_flags : 0; +# else + return (m) ? m->m_pkthdr.csum : 0; +# endif +#else +# error "wan_skb_set_dev() function is not supported yet!" +#endif +} + +/* +** wan_skb_check() - +** Check if packet consists from one skb block. +*/ +static __inline int wan_skb_check(void* skb) +{ +#if defined(__LINUX__) + return 0; +#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) + netskb_t* m = (netskb_t*)skb; + if (m->m_pkthdr.len != m->m_len){ + return 1; + } + return 0; +#else +# error "wan_skb_check() function is not supported yet!" +#endif +} + +/* +** wan_skb_reserve() - +** Reserve extra bytes before data +*/ +static __inline void wan_skb_reserve(void* skb, unsigned int len) +{ +#if defined(__LINUX__) + skb_reserve(skb, len); +#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) + struct mbuf *m = (struct mbuf*)skb; + + m->m_data += len; +#else +# error "wan_skb_free() function is not supported yet!" +#endif +} + +/* +** wan_skb_copyback() - +** Copy data from a buffer back into the indicated mbuf chain, +** starting "off" bytes from the beginning, extending the mbuf +** chain if necessary. +*/ +static __inline void wan_skb_copyback(void* skb, int off, int len, caddr_t cp) +{ +#if defined(__LINUX__) + struct sk_buff* sk = (struct sk_buff*)skb; + unsigned char* data = NULL; + if (off == wan_skb_len(skb)){ + if (sk->tail + len > sk->end){ + DEBUG_EVENT("wan_skb_copyback: Internal Error (off=%d,len=%d,skb_len=%d)!\n", + off, len, wan_skb_len(skb)); + return; + }else{ + data = skb_put(skb, len); + memcpy(data, cp, len); + } + }else{ + if (off + len > wan_skb_len(skb)){ + data = skb_put(skb, len); + memcpy(data + off, cp, len); + skb_trim(skb, off + len); + } + } +#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) + struct mbuf* m = (struct mbuf*)skb; + caddr_t data = mtod(m, caddr_t); + + bcopy(cp, &data[off], len); + m->m_len = off + len; + m->m_pkthdr.len = off + len; +#else +# error "wan_skb_copyback() function is not supported yet!" +#endif +} + +/* +** wan_skb_copyback_user() - +** Copy data from a buffer back into the indicated mbuf chain, +** starting "off" bytes from the beginning, extending the mbuf +** chain if necessary. +** Data being copied is coming from user space, thus we must +** use a special function to copy it into kernel space. +*/ +static __inline int wan_skb_copyback_user(void* skb, int off, int len, caddr_t cp) +{ +#if defined(__LINUX__) + struct sk_buff* sk = (struct sk_buff*)skb; + unsigned char* data = NULL; + if (off == wan_skb_len(skb)){ + if (sk->tail + len > sk->end){ + DEBUG_EVENT("wan_skb_copyback_user: Internal Error (off=%d,len=%d,skb_len=%d)!\n", + off, len, wan_skb_len(skb)); + return -EINVAL; + }else{ + data = skb_put(skb, len); + if (WAN_COPY_FROM_USER(data, cp, len)){ + DEBUG_EVENT("wan_skb_copyback_user: Internal Error (off=%d,len=%d,skb_len=%d)!\n", + off, len, wan_skb_len(skb)); + return -EFAULT; + } + } + }else{ + if (off + len > wan_skb_len(skb)){ + data = skb_put(skb, len); + if (WAN_COPY_FROM_USER(data+off, cp, len)){ + DEBUG_EVENT("wan_skb_copyback_user: Internal Error (off=%d,len=%d,skb_len=%d)!\n", + off, len, wan_skb_len(skb)); + return -EFAULT; + } + skb_trim(skb, off + len); + } + } + return 0; +#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) + struct mbuf* m = (struct mbuf*)skb; + caddr_t data = mtod(m, caddr_t); + + WAN_COPY_FROM_USER(cp, &data[off], len); + m->m_len = off + len; + m->m_pkthdr.len = off + len; +#else +# error "wan_skb_copyback_user() function is not supported yet!" +#endif + return 0; +} + + +/* +** wan_skb_copyback() - +** Copy data from an mbuf chain starting "off" bytes from the beginning, +** continuing for "len" bytes, into the indicated buffer. +*/ +static __inline void wan_skb_copydata(void* skb, int off, int len, caddr_t cp) +{ +#if defined(__LINUX__) + if (off + len > wan_skb_len(skb)){ + DEBUG_EVENT("wan_skb_copydata: Internal error (off=%d, len=%d, skb_len=%d)!\n", + off, len, wan_skb_len(skb)); + return; + } + memcpy(cp, wan_skb_data(skb), len); +#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) + caddr_t data = mtod((struct mbuf*)skb, caddr_t); + + bcopy(cp, &data[off], len); +#elif defined(__SOLARIS__) + mblk_t* tmp = (mblk_t*)skb; + unsigned char* ptr = NULL; + unsigned i = 0, num = 0; + while(tmp != NULL) { + ptr = tmp->b_rptr; + num = tmp->b_wptr - tmp->b_rptr; + bcopy(ptr, &cp[i], num); + i += num; + tmp = tmp->b_cont; + } +#else +# error "wan_skb_copydata() function is not supported yet!" +#endif +} + +/* +** wan_skb_copy() +*/ +static __inline void * wan_skb_copy(void *skb) +{ +#if defined(__LINUX__) + return skb_copy(skb,GFP_ATOMIC); +#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) + return m_copym(skb, 0, wan_skb_len(skb), M_DONTWAIT); +#else +# error "wan_skb_copy() function is not supported yet" +#endif + +} + +/* +** wan_skb_clone() +*/ +static __inline void * wan_skb_clone(void *skb) +{ +#if defined(__LINUX__) + return skb_clone(skb,GFP_ATOMIC); +#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) + return m_copym(skb, 0, wan_skb_len(skb), M_DONTWAIT); +#else +# error "wan_skb_clone() function is not supported yet" +#endif + +} + + + + + +/* +** wan_skb2buffer() - +** Correct skb block. +*/ +static __inline int wan_skb2buffer(void** skb) +{ +#if defined(__LINUX__) + return 0; +#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) + netskb_t *m = (netskb_t*)(*skb); + netskb_t *new = NULL; + + new = wan_skb_alloc(0); + if (new){ + struct mbuf *tmp = m; + char *buffer = new->m_data; + + for( ; tmp; tmp = tmp->m_next) { + bcopy(mtod(tmp, caddr_t), buffer, tmp->m_len); + buffer += tmp->m_len; + new->m_len += tmp->m_len; + } + wan_skb_free(m); + *skb = new; + return 0; + } + return -EINVAL; +#else +# error "wan_skb_correct() function is not supported yet!" +#endif +} + +/* +** wan_skb_pull() - +** +*/ +static __inline unsigned char* wan_skb_pull(void* skb, int len) +{ +#if defined(__LINUX__) + return skb_pull((struct sk_buff*)skb, len); +#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) + m_adj(skb, len); +#if 0 + struct mbuf* m = (struct mbuf*)skb; + m->m_data += len; + m->m_pkthdr.len -= len; + m->m_len = m->m_pkthdr.len; +#endif + return wan_skb_data(skb); +#else +# error "wan_skb_pull() function is not supported yet!" +#endif +} + +/* +** wan_skb_put() - +** +*/ +static __inline unsigned char* wan_skb_put(void* skb, int len) +{ +#if defined(__LINUX__) + return skb_put((struct sk_buff*)skb, len); +#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) + struct mbuf* m = (struct mbuf*)skb; + int org_len = wan_skb_len(skb); + unsigned char* data = wan_skb_data(skb); + + m->m_len = org_len + len; + m->m_pkthdr.len = org_len + len; +/*Alex Sep27,2004 last tail but not data pointer return wan_skb_data(skb);*/ + return data + org_len; +#elif defined(__SOLARIS__) + mblk_t mp=(mblk_t*)skb; + unsigned char *wptr=mp->b_wptr; + mp->b_wptr += len; + return mp->b_wptr; +#else +# error "wan_skb_put() function is not supported yet!" +#endif +} + +/* +** wan_skb_push() - +** +*/ +static __inline unsigned char* wan_skb_push(void* skb, int len) +{ +#if defined(__LINUX__) + return skb_push((struct sk_buff*)skb, len); +#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) + struct mbuf *m = (struct mbuf*)skb; + int org_len = wan_skb_len(skb); + + if (m->m_flags & M_EXT){ + if ((m->m_data - len) < m->m_ext.ext_buf){ + DEBUG_EVENT("Can't push %d bytes!\n", len); + return wan_skb_data(skb); + } + }else{ + if ((m->m_data - len) < m->m_pktdat){ + DEBUG_EVENT("Can't push %d bytes!\n", len); + return wan_skb_data(skb); + } + } + m->m_data -= len; + m->m_len = org_len + len; + m->m_pkthdr.len = org_len + len; + return wan_skb_data(skb); +#else +# error "wan_skb_push() function is not supported yet!" +#endif +} + + + + +/* +** wan_skb_tailroom() - Tail room +** +** +*/ +static __inline int wan_skb_tailroom(void* skb) +{ +#if defined(__LINUX__) + return skb_tailroom(skb); +#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) + struct mbuf* m = (struct mbuf*)skb; + + if (m->m_flags & M_EXT){ + return (MCLBYTES - m->m_len); + } + return (MHLEN - m->m_len); +#else +# error "wan_skb_tailroom() function is not supported yet!" +#endif +} + +/* +** wan_skb_tailroom() - Head room +** +** +*/ +static __inline int wan_skb_headroom(void* skb) +{ +#if defined(__LINUX__) + return skb_headroom(skb); +#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) + struct mbuf* m = (struct mbuf*)skb; + + if (m->m_flags & M_EXT){ + return (m->m_data - m->m_ext.ext_buf); + } + return (m->m_data - m->m_pktdat); +#else +# error "wan_skb_headroom() function is not supported yet!" +#endif +} + + + +/* +** wan_skb_trim() - Trim from tail +** +** +*/ +static __inline void wan_skb_trim(void* skb, unsigned int len) +{ +#if defined(__LINUX__) + skb_trim(skb, len); +#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) + struct mbuf* m = (struct mbuf*)skb; +#if 0 + /* Trim only moves tail to head+len (Oct13) */ + if (len == 0){ + m->m_data = m->m_ext.ext_buf; + } +#endif + m->m_pkthdr.len = len; + m->m_len = m->m_pkthdr.len; +#else +# error "wan_skb_trim() function is not supported yet!" +#endif +} + +/* +** wan_skb_init() - Setup skb data ptr +** +** +*/ +static __inline void wan_skb_init(void* pskb, unsigned int len) +{ +#if defined(__LINUX__) + struct sk_buff* skb = (struct sk_buff*)pskb; + skb->data = skb->head + len; +#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) + struct mbuf* m = (struct mbuf*)pskb; + m->m_data = m->m_ext.ext_buf + len; +#else +# error "wan_skb_init() function is not supported yet!" +#endif +} + +static __inline int wan_skb_print(void* skb) +{ +#if defined(__LINUX__) + int len = wan_skb_len(skb); + unsigned char *data = wan_skb_data(skb); + int i; + + DEBUG_EVENT("DBG Packet %d bytes: ",len); + for(i=0;im_pkthdr.len, i; + unsigned char *data = wan_skb_data(skb); + + if (m->m_type & M_PKTHDR) + DEBUG_EVENT("M_PKTHDR flag set (%d)!\n", + m->m_pkthdr.len); + if (m->m_type & M_EXT) + DEBUG_EVENT("M_EXT flag set (%d)!\n", + m->m_pkthdr.len); + DEBUG_EVENT("Packet %d bytes: ", len); + for(i=0;i= '0') && (ifname[len] <= '9')){ + if (!base){ + int i=0; + base = 1; + for(i=0;i= 502000) + if_initname(dev, ifname, IF_DUNIT_NONE); +# else + dev->if_unit = ifunit; + if (dev->if_name == NULL){ + dev->if_name = wan_malloc(prefix_len+1); + if (dev->if_name == NULL){ + return -ENOMEM; + } + } + memcpy(dev->if_name, ifname, prefix_len); + dev->if_name[prefix_len] = '\0'; +# endif + WAN_IFQ_SET_MAXLEN(&dev->if_snd, ifqmaxlen); +#elif defined(__OpenBSD__) || defined(__NetBSD__) + if (strlen(ifname) >= IFNAMSIZ){ + return -ENOMEM; + } + bcopy(ifname, dev->if_xname, strlen(ifname)); + WAN_IFQ_SET_MAXLEN(&dev->if_snd, IFQ_MAXLEN); +#elif defined(__LINUX__) +# if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,43)) + dev->name = ifname; +# else + strcpy(dev->name, ifname); +# endif +#else +# error "wan_netif_init() function is not supported yet!" +#endif + return 0; +} + +static __inline int wan_netif_del(netdevice_t* dev) +{ + WAN_ASSERT(dev == NULL); +#if defined(__FreeBSD__) + dev->if_init = NULL; +# if (__FreeBSD_version >= 502000) + dev->if_dname = NULL; +# elif (__FreeBSD_version > 400000) + /* Free interface name (only for FreeBSD-4.0) */ + free(dev->if_name, M_DEVBUF); +# endif +#elif defined(__OpenBSD__) || defined(__NetBSD__) + /* Do nothing */ +#elif defined(__LINUX__) + /* Do nothing */ +#else +# error "wan_netif_del() function is not supported yet!" +#endif + return 0; +} + + +#if defined(__LINUX__) +static __inline void wan_netif_fake_init(netdevice_t *d) +{ + return; +} +#endif + +static __inline void* +wan_netif_alloc(unsigned char *devname, int ifType, int *err) +{ +#if defined(__LINUX__) +# if defined(LINUX_2_6) +# if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,4)) + return __dev_alloc(devname, err); +# else + return alloc_netdev(0,devname,wan_netif_fake_init); +# endif +# elif defined(LINUX_2_4) + netdevice_t *dev=wan_malloc(sizeof(netdevice_t)); + *err=0; + + if (!dev){ + *err=-ENOMEM; + } + memset(dev, 0, sizeof(netdevice_t)); + + strncpy(dev->name,devname,30); + return dev; +# else + netdevice_t *dev=wan_malloc(sizeof(netdevice_t)); + *err=0; + + if (!dev){ + *err=-ENOMEM; + } + memset(dev, 0, sizeof(netdevice_t)); + + dev->name=wan_malloc(35); + if (!dev->name){ + wan_free(dev); + dev=NULL; + *err=-ENOMEM; + return NULL; + } + strncpy(dev->name,devname,30); + return dev; +# endif +#elif defined(__FreeBSD__) && (__FreeBSD_version > 600000) + struct ifnet* ifp; + ifp = IFALLOC(ifType); + /*ifp = wan_malloc(sizeof(struct ifnet));*/ + if (ifp == NULL){ + *err = -ENOMEM; + return NULL; + } + if (devname){ + *err = wan_netif_init(ifp, devname); + if (*err){ + wan_netif_del(ifp); + return NULL; + } + } + return ifp; +#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) + struct ifnet* ifp; + switch(ifType){ + case WAN_IFT_PPP: + ifp = (struct ifnet*)wan_malloc(sizeof(struct sppp)); + if (ifp) bzero((struct sppp*)ifp, sizeof(struct sppp)); + break; + case WAN_IFT_ETHER: + ifp = (struct ifnet*)wan_malloc(sizeof(wan_ethercom_t)); + if (ifp) bzero(WAN_IFP2AC(ifp), sizeof(wan_ethercom_t)); + break; + case WAN_IFT_OTHER: + default: + ifp = wan_malloc(sizeof(struct ifnet)); + if (ifp) bzero(ifp, sizeof(struct ifnet)); + break; + } + /*ifp = IFALLOC(ifType);*/ + /*ifp = wan_malloc(sizeof(struct ifnet));*/ + if (ifp == NULL){ + *err = -ENOMEM; + return NULL; + } + if (devname){ + *err = wan_netif_init(ifp, devname); + if (*err){ + wan_netif_del(ifp); + return NULL; + } + } + return ifp; +#else +# error "wan_netif_alloc() unsupported" +#endif + +} + +static __inline void wan_netif_free(netdevice_t *dev) +{ + +#if defined(__LINUX__) +# if defined(LINUX_2_6) + free_netdev(dev); +# elif defined(LINUX_2_4) + wan_free(dev); +# else + if (dev->name){ + wan_free(dev->name); + dev->name=NULL; + } + wan_free(dev); +# endif +#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) + wan_netif_del(dev); + IFFREE(dev); /*wan_free(dev);*/ +#else +#error "wan_netif_free() not supported!" +#endif + +} + + +static __inline char* wan_netif_name(netdevice_t* dev) +{ + static char ifname[IFNAMSIZ+1]; + WAN_ASSERT2(dev == NULL, NULL); +#if defined(__LINUX__) + strcpy(ifname, dev->name); +#elif defined(__FreeBSD__) +# if (__FreeBSD_version >= 502000) + strcpy(ifname, dev->if_xname); +# else + sprintf(ifname, "%s%d", dev->if_name, dev->if_unit); +# endif +#elif defined(__OpenBSD__) || defined(__NetBSD__) + sprintf(ifname, "%s", dev->if_xname); +#else +# error "wan_get_ifname() function is not supported yet!" +#endif + return ifname; +} + +static __inline void* wan_netif_priv(netdevice_t* dev) +{ + WAN_ASSERT2(dev == NULL, NULL); +#if defined(__LINUX__) + return dev->priv; +#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) + return dev->if_softc; +#else +# error "wan_netif_priv() function is not supported yet!" +#endif +} + +static __inline int wan_netif_up(netdevice_t* dev) +{ + WAN_ASSERT2(dev == NULL, -EINVAL); +#if defined(__LINUX__) + return WAN_NETIF_UP(dev); +#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) + return WAN_NETIF_UP(dev); +#else +# error "wan_netif_up() function is not supported yet!" +#endif +} + + +static __inline void wan_netif_set_priv(netdevice_t* dev, void* priv) +{ + WAN_ASSERT1(dev == NULL); +#if defined(__LINUX__) + dev->priv = priv; +#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) + dev->if_softc = priv; +#else +# error "wan_netif_priv() function is not supported yet!" +#endif + return; +} + +static __inline short wan_netif_flags(netdevice_t* dev) +{ + WAN_ASSERT(dev == NULL); +#if defined(__LINUX__) + return dev->flags; +#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) + return dev->if_flags; +#else +# error "wan_netif_flags() function is not supported yet!" +#endif +} + +static __inline int wan_netif_mcount(netdevice_t* dev) +{ +#if defined(__LINUX__) + return dev->mc_count; +#elif defined(__FreeBSD__) + return dev->if_amcount; +#elif defined(__OpenBSD__) || defined(__NetBSD__) + return 0; +#else +# error "wan_netif_mcount() function is not supported yet!" +#endif +} + +static __inline int wan_netif_set_ticks(netdevice_t* dev, unsigned long ticks) +{ +#if defined(__LINUX__) + dev->trans_start = ticks; +#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) +#else +# error "wan_netif_set_ticks() function is not supported yet!" +#endif + return 0; +} + +static __inline int wan_netif_set_mtu(netdevice_t* dev, unsigned long mtu) +{ +#if defined(__LINUX__) +#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) + dev->if_mtu = mtu; +#else +# error "wan_netif_set_mtu() function is not supported yet!" +#endif + return 0; +} + + +static __inline void wan_bpf_report(netdevice_t* dev, void* pkt, int flag) +{ + +#if defined(__LINUX__) + /* Do nothing */ +#elif defined(__FreeBSD__) + if (dev->if_bpf != NULL){ /* BF-0002 */ + WAN_BPF_REPORT(dev, pkt); + } +#elif defined(__OpenBSD__) || defined(__NetBSD__) + if (dev->if_bpf != NULL){ /* BF-0002 */ + if (flag){ + struct mbuf m0; + u_int32_t af = AF_INET; + m0.m_next = pkt; + m0.m_len = 4; + m0.m_data = (char*)⁡ + WAN_BPF_REPORT(dev, &m0); + }else{ + WAN_BPF_REPORT(dev, pkt); + } + } +#else +# error "wan_bpf_report() function is not supported yet!" +#endif +} + + + + + +static __inline void wan_spin_lock_init(void *lock) +{ +#if defined(__LINUX__) + spin_lock_init(((spinlock_t*)lock)); +#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) + /*(*(wan_smp_flag_t*)flag) = 0;*/ +#else +# warning "wan_spin_lock_init() function is not supported yet!" +#endif +} + +static __inline int wan_spin_is_locked(void *lock) +{ +#if defined(__LINUX__) + return spin_is_locked((spinlock_t*)lock); +#elif defined(__NetBSD__) || defined(__OpenBSD__) + return 0;/*((*(wan_smp_flag_t*)flag) & imask[IPL_NET]);*/ +#elif defined(__FreeBSD__) +# if (__FreeBSD_version > 500000) + return 0; +# else + return 0;/*((*(wan_smp_flag_t*)flag) & net_imask);*/ +# endif +#else +# warning "wan_spin_is_lock() function is not supported yet!" +#endif +} + +static __inline void wan_spin_lock_irq(void *lock, wan_smp_flag_t *flag) +{ +#if defined(__LINUX__) + spin_lock_irqsave(((spinlock_t*)lock),*flag); +#elif defined(__FreeBSD__) + /* Feb 10, 2005 Change splnet to splimp + ** (i think it was cause to system crash) */ + *flag = splimp(); +#elif defined(__OpenBSD__) + *flag = splnet(); +#elif defined(__NetBSD__) +# if (__NetBSD_Version__ >= 106000200) + *flag = splvm(); +# else + *flag = splimp(); +# endif +#else +# warning "wan_spin_lock_irq() function is not supported yet!" +#endif +} +static __inline void wan_spin_unlock_irq(void *lock, wan_smp_flag_t *flag) +{ +#if defined(__LINUX__) + spin_unlock_irqrestore(((spinlock_t*)lock),*flag); +#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) + splx(*flag); +#else +# warning "wan_spin_unlock_irq() function is not supported yet!" +#endif +} + +static __inline void wan_spin_lock(void *lock) +{ +#if defined(__LINUX__) + spin_lock(((spinlock_t*)lock)); +#elif defined(__FreeBSD__) + /* Feb 10, 2005 Change splnet to splimp + ** (i think it was cause to system crash) */ + *((wan_spinlock_t*)lock) = splimp(); +#elif defined(__OpenBSD__) + *((wan_spinlock_t*)lock) = splnet(); +#elif defined(__NetBSD__) +# if (__NetBSD_Version__ >= 106000200) + *((wan_spinlock_t*)lock) = splvm(); +# else + *((wan_spinlock_t*)lock) = splimp(); +# endif +#else +# warning "wan_spin_lock() function is not supported yet!" +#endif +} +static __inline void wan_spin_unlock(void *lock) +{ +#if defined(__LINUX__) + spin_unlock(((spinlock_t*)lock)); +#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) + splx(*(wan_spinlock_t*)lock); +#else +# warning "wan_spin_unlock() function is not supported yet!" +#endif +} + + + +#if 0 +static __inline void wan_read_rw_lock(void *lock) +{ +#if defined(__LINUX__) + read_lock(((rwlock_t*)lock)); +#else +# warning "wan_read_rw_lock() function is not supported yet!" +#endif +} + +static __inline void wan_read_rw_unlock(void *lock) +{ +#if defined(__LINUX__) + read_unlock(((rwlock_t*)lock)); +#else +# warning "wan_read_rw_unlock() function is not supported yet!" +#endif +} + +static __inline void wan_write_rw_lock_irq(void *lock, unsigned long *flag) +{ +#if defined(__LINUX__) + write_lock_irqsave(((rwlock_t*)lock),flag); +#else +# warning "wan_read_rw_lock() function is not supported yet!" +#endif +} + +static __inline void wan_write_rw_unlock_irq(void *lock, unsigned long *flag) +{ +#if defined(__LINUX__) + write_unlock_irqrestore(((rwlock_t*)lock),flag); +#else +# warning "wan_read_rw_unlock() function is not supported yet!" +#endif +} +#endif + +#endif /* WAN_KERNEL */ +#endif /* __WANPIPE_COMMON_H */ diff -Nur linux.org/include/linux/wanpipe_debug.h linux-2.6.17/include/linux/wanpipe_debug.h --- linux.org/include/linux/wanpipe_debug.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/wanpipe_debug.h 2006-08-30 10:07:15.000000000 +0000 @@ -0,0 +1,629 @@ +/* + ************************************************************************ + * wanpipe_debug.h WANPIPE(tm) Global definition for Sangoma * + * Debugging messages * + * * + * Author: Alex Feldman * + *======================================================================* + * May 10 2002 Alex Feldman Initial version * + * * + ************************************************************************ + */ + +#ifndef __WANPIPE_DEBUG_H +# define __WANPIPE_DEBUG_H + +#if defined(WAN_KERNEL) + +#define WAN_DEBUG_EVENT +#undef WAN_DEBUG_KERNEL +#undef WAN_DEBUG_MOD +#undef WAN_DEBUG_CFG +#undef WAN_DEBUG_INIT_VAR +#undef WAN_DEBUG_IOCTL +#undef WAN_DEBUG_CMD +#undef WAN_DEBUG_ISR +#undef WAN_DEBUG_RX +#undef WAN_DEBUG_RX_ERROR +#undef WAN_DEBUG_TX +#undef WAN_DEBUG_TX_ERROR +#undef WAN_DEBUG_TIMER +#undef WAN_DEBUG_UDP +#undef WAN_DEBUG_TE1 +#undef WAN_DEBUG_56K +#undef WAN_DEBUG_PROCFS +#undef WAN_DEBUG_TDM_VOICE +#undef WAN_DEBUG_TEST +#undef WAN_DEBUG_DBG +#undef WAN_DEBUG_DMA +#undef WAN_DEBUG_SNMP +#undef WAN_DEBUG_TE3 +#undef WAN_DEBUG_RM +#undef WAN_DEBUG_HWEC +#undef WAN_DEBUG_TDMAPI +#undef WAN_DEBUG_FE + +#undef WAN_DEBUG_MEM + +#if defined (__WINDOWS__) + +# define DEBUG_NONE if (0) DbgPrint +# define PRINT OutputLogString +# define DEBUG_PRINT DbgPrint +# define _DEBUG_PRINT DbgPrint + +# define DEBUG_KERNEL DEBUG_NONE +# define DEBUG_EVENT DEBUG_NONE +# define DEBUG_MOD DEBUG_NONE +# define DEBUG_CFG DEBUG_NONE +# define DEBUG_INIT DEBUG_NONE +# define DEBUG_IOCTL DEBUG_NONE +# define DEBUG_CMD DEBUG_NONE +# define DEBUG_ISR DEBUG_NONE +# define DEBUG_RX DEBUG_NONE +# define DEBUG_RX_ERR DEBUG_NONE +# define DEBUG_TX DEBUG_NONE +# define _DEBUG_TX DEBUG_NONE +# define DEBUG_TX_ERR DEBUG_NONE +# define DEBUG_TIMER DEBUG_NONE +# define DEBUG_UDP DEBUG_NONE +# define DEBUG_TE1 DEBUG_NONE +# define DEBUG_TE3 DEBUG_NONE +# define DEBUG_56K DEBUG_NONE +# define DEBUG_PROCFS DEBUG_NONE +# define DEBUG_TDMV DEBUG_NONE +# define DEBUG_TEST DEGUG_NONE +# define DEBUG_DBG DEGUG_NONE +# define DEBUG_DMA DEGUG_NONE +# define DEBUG_SNMP DEGUG_NONE +# define DEBUG_RM DEGUG_NONE +# define DEBUG_HWEC DEGUG_NONE +# define DEBUG_TDMAPI DEGUG_NONE + +# ifdef WAN_DEBUG_KERNEL +# undef DEBUG_KERNEL +# define DEBUG_KERNEL DEBUG_PRINT +# endif +# ifdef WAN_DEBUG_EVENT +# undef DEBUG_EVENT +# define DEBUG_EVENT PRINT +# endif +# ifdef WAN_DEBUG_MOD +# undef DEBUG_MOD +# define DEBUG_MOD DEBUG_PRINT +# endif +# ifdef WAN_DEBUG_CFG +# undef DEBUG_CFG +# define DEBUG_CFG DEBUG_PRINT +# endif +# ifdef WAN_DEBUG_INIT_VAR +# undef DEBUG_INIT +# define DEBUG_INIT DEBUG_PRINT +# endif +# ifdef WAN_DEBUG_IOCTL +# undef DEBUG_IOCTL +# define DEBUG_IOCTL DEBUG_PRINT +# endif +# ifdef WAN_DEBUG_CMD +# undef DEBUG_CMD +# define DEBUG_CMD DEBUG_PRINT +# endif +# ifdef WAN_DEBUG_ISR +# undef DEBUG_ISR +# define DEBUG_ISR DEBUG_PRINT +# endif +# ifdef WAN_DEBUG_RX +# undef DEBUG_RX +# define DEBUG_RX DEBUG_PRINT +# endif +# ifdef WAN_DEBUG_RX_ERROR +# undef DEBUG_RX_ERR +# define DEBUG_RX_ERR DEBUG_PRINT +# endif +# ifdef WAN_DEBUG_TX +# undef DEBUG_TX +# define DEBUG_TX DEBUG_PRINT +# undef _DEBUG_TX +# define _DEBUG_TX _DEBUG_PRINT +# endif +# ifdef WAN_DEBUG_TX_ERROR +# undef DEBUG_TX_ERR +# define DEBUG_TX_ERR DEBUG_PRINT +# endif +# ifdef WAN_DEBUG_TIMER +# undef DEBUG_TIMER +# define DEBUG_TIMER DEBUG_PRINT +# endif +# ifdef WAN_DEBUG_UDP +# undef DEBUG_UDP +# define DEBUG_UDP DEBUG_PRINT +# endif +# ifdef WAN_DEBUG_TE1 +# undef DEBUG_TE1 +# define DEBUG_TE1 DEBUG_PRINT +# endif +# ifdef WAN_DEBUG_TE3 +# undef DEBUG_TE3 +# define DEBUG_TE3 DEBUG_PRINT +# endif +# ifdef WAN_DEBUG_56K +# undef DEBUG_56K +# define DEBUG_56K DEBUG_PRINT +# endif +# ifdef WAN_DEBUG_PROCFS +# undef DEBUG_PROCFS +# define DEBUG_PROCFS DEBUG_PRINT +# endif +# ifdef WAN_DEBUG_TDM_VOICE +# undef DEBUG_TDMV +# define DEBUG_TDMV DEBUG_PRINT +# endif +# ifdef WAN_DEBUG_TEST +# undef DEBUG_TEST +# define DEBUG_TEST DEBUG_PRINT +# endif +# ifdef WAN_DEBUG_DBG +# undef DEBUG_DBG +# define DEBUG_DBG DEBUG_PRINT +# endif +# ifdef WAN_DEBUG_DMA +# undef DEBUG_DMA +# define DEBUG_DMA DEBUG_PRINT +# endif +# ifdef WAN_DEBUG_SNMP +# undef DEBUG_SNMP +# define DEBUG_SNMP DEBUG_PRINT +# endif +# ifdef WAN_DEBUG_RM +# undef DEBUG_RM +# define DEBUG_RM DEBUG_PRINT +# endif +# ifdef WAN_DEBUG_HWEC +# undef DEBUG_HWEC +# define DEBUG_HWEC DEBUG_PRINT +# endif +# ifdef WAN_DEBUG_TDMAPI +# undef DEBUG_TDMAPI +# define DEBUG_TDMAPI DEBUG_PRINT +# endif + + + +#else /* !__WINDOWS__*/ + +# define DEBUG_KERNEL(format,msg...) +# define DEBUG_EVENT(format,msg...) +# define DEBUG_MOD(format,msg...) +# define DEBUG_CFG(format,msg...) +# define DEBUG_INIT(format,msg...) +# define DEBUG_IOCTL(format,msg...) +# define DEBUG_CMD(format,msg...) +# define DEBUG_ISR(format,msg...) +# define DEBUG_RX(format,msg...) +# define DEBUG_RX_ERR(format,msg...) +# define DEBUG_TX(format,msg...) +# define _DEBUG_TX(format,msg...) +# define DEBUG_TX_ERR(format,msg...) +# define DEBUG_TIMER(format,msg...) +# define DEBUG_UDP(format,msg...) +# define DEBUG_TE1(format,msg...) +# define DEBUG_TE3(format,msg...) +# define DEBUG_56K(format,msg...) +# define DEBUG_PROCFS(format,msg...) +# define DEBUG_TDMV(format,msg...) +# define DEBUG_TEST(format,msg...) +# define DEBUG_DBG(format,msg...) +# define DEBUG_DMA(format,msg...) +# define DEBUG_SNMP(format,msg...) +# define DEBUG_ADD_MEM(a) +# define DEBUG_SUB_MEM(a) +# define DEBUG_RM(format,msg...) +# define DEBUG_HWEC(format,msg...) +# define DEBUG_TDMAPI(format,msg...) + +# if (defined __FreeBSD__) || (defined __OpenBSD__) || defined(__NetBSD__) + +# define DEBUG_PRINT(format,msg...) log(LOG_INFO, format, ##msg) +# define _DEBUG_PRINT(format,msg...) log(LOG_INFO, format, ##msg) + +# else /* !__FreeBSD__ && !__OpenBSD__ */ + +# define DEBUG_PRINT(format,msg...) printk(KERN_INFO format, ##msg) +# define _DEBUG_PRINT(format,msg...) printk(format,##msg) + +# endif /* __FreeBSD__ || __OpenBSD__ */ + +# ifdef WAN_DEBUG_KERNEL +# undef DEBUG_KERNEL +# define DEBUG_KERNEL(format,msg...) DEBUG_PRINT(format,##msg) +# endif +# ifdef WAN_DEBUG_EVENT +# undef DEBUG_EVENT +# define DEBUG_EVENT(format,msg...) DEBUG_PRINT(format,##msg) +# undef _DEBUG_EVENT +# define _DEBUG_EVENT(format,msg...) _DEBUG_PRINT(format,##msg) +# endif +# ifdef WAN_DEBUG_MOD +# undef DEBUG_MOD +# define DEBUG_MOD(format,msg...) DEBUG_PRINT(format,##msg) +# endif +# ifdef WAN_DEBUG_CFG +# undef DEBUG_CFG +# define DEBUG_CFG(format,msg...) DEBUG_PRINT(format,##msg) +# endif +# ifdef WAN_DEBUG_INIT_VAR +# undef DEBUG_INIT +# define DEBUG_INIT(format,msg...) DEBUG_PRINT(format,##msg) +# endif +# ifdef WAN_DEBUG_IOCTL +# undef DEBUG_IOCTL +# define DEBUG_IOCTL(format,msg...) DEBUG_PRINT(format,##msg) +# endif +# ifdef WAN_DEBUG_CMD +# undef DEBUG_CMD +# define DEBUG_CMD(format,msg...) DEBUG_PRINT(format,##msg) +# endif +# ifdef WAN_DEBUG_ISR +# undef DEBUG_ISR +# define DEBUG_ISR(format,msg...) DEBUG_PRINT(format,##msg) +# endif +# ifdef WAN_DEBUG_RX +# undef DEBUG_RX +# define DEBUG_RX(format,msg...) DEBUG_PRINT(format,##msg) +# endif +# ifdef WAN_DEBUG_RX_ERROR +# undef DEBUG_RX_ERR +# define DEBUG_RX_ERR(format,msg...) DEBUG_PRINT(format,##msg) +# endif +# ifdef WAN_DEBUG_TX +# undef DEBUG_TX +# define DEBUG_TX(format,msg...) DEBUG_PRINT(format,##msg) +# undef _DEBUG_TX +# define _DEBUG_TX(format,msg...) _DEBUG_PRINT(format,##msg) +# endif +# ifdef WAN_DEBUG_TX_ERROR +# undef DEBUG_TX_ERR +# define DEBUG_TX_ERR(format,msg...) DEBUG_PRINT(format,##msg) +# endif +# ifdef WAN_DEBUG_TIMER +# undef DEBUG_TIMER +# define DEBUG_TIMER(format,msg...) DEBUG_PRINT(format,##msg) +# endif +# ifdef WAN_DEBUG_UDP +# undef DEBUG_UDP +# define DEBUG_UDP(format,msg...) DEBUG_PRINT(format,##msg) +# endif +# ifdef WAN_DEBUG_TE1 +# undef DEBUG_TE1 +# define DEBUG_TE1(format,msg...) DEBUG_PRINT(format,##msg) +# endif +# ifdef WAN_DEBUG_TE3 +# undef DEBUG_TE3 +# define DEBUG_TE3(format,msg...) DEBUG_PRINT(format,##msg) +# endif +# ifdef WAN_DEBUG_56K +# undef DEBUG_56K +# define DEBUG_56K(format,msg...) DEBUG_PRINT(format,##msg) +# endif +# ifdef WAN_DEBUG_PROCFS +# undef DEBUG_PROCFS +# define DEBUG_PROCFS(format,msg...) DEBUG_PRINT(format,##msg) +# endif +# ifdef WAN_DEBUG_TDM_VOICE +# undef DEBUG_TDMV +# define DEBUG_TDMV(format,msg...) DEBUG_PRINT(format,##msg) +# endif +# ifdef WAN_DEBUG_TEST +# undef DEBUG_TEST +# define DEBUG_TEST(format,msg...) DEBUG_PRINT(format,##msg) +# endif +# ifdef WAN_DEBUG_DBG +# undef DEBUG_DBG +# define DEBUG_DBG(format,msg...) DEBUG_PRINT(format,##msg) +# endif +# ifdef WAN_DEBUG_MEM +# undef DEBUG_ADD_MEM +# define DEBUG_ADD_MEM(a) /*DEBUG_EVENT("%s:%d MEM ADDING %d\n",__FUNCTION__,__LINE__,a);*/(atomic_add(a,&wan_debug_mem)) +# undef DEBUG_SUB_MEM +# define DEBUG_SUB_MEM(a) /*DEBUG_EVENT("%s:%d MEM SUBSTR %d\n",__FUNCTION__,__LINE__,a);*/(atomic_sub(a,&wan_debug_mem)) +#endif +# ifdef WAN_DEBUG_DMA +# undef DEBUG_DMA +# define DEBUG_DMA(format,msg...) DEBUG_PRINT(format,##msg) +# endif +# ifdef WAN_DEBUG_SNMP +# undef DEBUG_SNMP +# define DEBUG_SNMP(format,msg...) DEBUG_PRINT(format,##msg) +# endif +# ifdef WAN_DEBUG_RM +# undef DEBUG_RM +# define DEBUG_RM(format,msg...) DEBUG_PRINT(format,##msg) +# endif +# ifdef WAN_DEBUG_HWEC +# undef DEBUG_HWEC +# define DEBUG_HWEC(format,msg...) DEBUG_PRINT(format,##msg) +# endif +# ifdef WAN_DEBUG_TDMAPI +# undef DEBUG_TDMAPI +# define DEBUG_TDMAPI(format,msg...) DEBUG_PRINT(format,##msg) +# endif + + +#endif /* __WINDOWS__ */ + +#define WAN_DEBUG_FLINE DEBUG_EVENT("[%s]: %s:%d\n", \ + __FILE__,__FUNCTION__,__LINE__); + +#define WAN_ASSERT(val) if (val){ \ + DEBUG_EVENT("************** ASSERT FAILED **************\n"); \ + DEBUG_EVENT("%s:%d - Critical error\n",__FILE__,__LINE__); \ + return -EINVAL; \ + } +#define WAN_ASSERT_EINVAL(val) WAN_ASSERT(val) + +#define WAN_ASSERT1(val) if (val){ \ + DEBUG_EVENT("************** ASSERT FAILED **************\n"); \ + DEBUG_EVENT("%s:%d - Critical error\n",__FILE__,__LINE__); \ + return; \ + } +#define WAN_ASSERT_VOID(val) WAN_ASSERT1(val) + +#define WAN_ASSERT2(val, ret) if (val){ \ + DEBUG_EVENT("************** ASSERT FAILED **************\n"); \ + DEBUG_EVENT("%s:%d - Critical error\n",__FILE__,__LINE__); \ + return ret; \ + } +#define WAN_ASSERT_RC(val,ret) WAN_ASSERT2(val, ret) + +#define WAN_MEM_ASSERT(str) {if (str){ \ + DEBUG_EVENT("%s: Error: No memory in %s:%d\n", \ + str,__FILE__,__LINE__); \ + }else{ \ + DEBUG_EVENT("wanpipe: Error: No memory in %s:%d\n", \ + __FILE__,__LINE__); \ + } \ + } + +#define WAN_OPP_FLAG_ASSERT(val,cmd) if (val){ \ + DEBUG_EVENT("%s:%d - Critical error: Opp Flag Set Cmd=0x%x!\n", \ + __FILE__,__LINE__,cmd); \ + } + + + +#define WAN_MEM_INIT(id) unsigned long mem_in_used_##id = 0x0l +#define WAN_MEM_INC(id,size) mem_in_used_##id += size +#define WAN_MEM_DEC(id,size) mem_in_used_##id -= size + +/* WANPIPE debugging states */ +#define WAN_DEBUGGING_NONE 0x00 +#define WAN_DEBUGGING_AGAIN 0x01 +#define WAN_DEBUGGING_START 0x02 +#define WAN_DEBUGGING_CONT 0x03 +#define WAN_DEBUGGING_PROTOCOL 0x04 +#define WAN_DEBUGGING_END 0x05 + +/* WANPIPE debugging delay */ +#define WAN_DEBUGGING_DELAY 60 + +/* WANPIPE debugging messages */ +#define WAN_DEBUG_NONE_MSG 0x00 +#define WAN_DEBUG_ALARM_MSG 0x01 +#define WAN_DEBUG_TE1_MSG 0x02 +#define WAN_DEBUG_TE3_MSG 0x02 +#define WAN_DEBUG_LINERROR_MSG 0x03 +#define WAN_DEBUG_CLK_MSG 0x04 +#define WAN_DEBUG_TX_MSG 0x05 +#define WAN_DEBUG_FR_CPE_MSG 0x06 +#define WAN_DEBUG_FR_NODE_MSG 0x07 +#define WAN_DEBUG_PPP_LCP_MSG 0x08 +#define WAN_DEBUG_PPP_NAK_MSG 0x09 +#define WAN_DEBUG_PPP_NEG_MSG 0x0A +#define WAN_DEBUG_CHDLC_KPLV_MSG 0x0B +#define WAN_DEBUG_CHDLC_UNKNWN_MSG 0x0C + + +#define WAN_DEBUG_INIT(card){ \ + wan_tasklet_t* debug_task = &card->debug_task; \ + WAN_TASKLET_INIT(debug_task, 0, &wanpipe_debugging, card);\ + wan_clear_bit(0, (unsigned long*)&card->debug_running); \ + wanpipe_debug_timer_init(card); \ + } +#define WAN_DEBUG_END(card){ \ + wan_del_timer(&card->debug_timer); \ + WAN_TASKLET_KILL(&card->debug_task); \ + } +#define WAN_DEBUG_STOP(card) wan_clear_bit(0, &card->debug_running) + +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__WINDOWS__) +# define WAN_DEBUG_START(card) \ + if (!wan_test_bit(0, &card->debug_running)){ \ + wan_set_bit(0, &card->debug_running); \ + wan_add_timer(&card->debug_timer, 5*HZ); \ + } + +# define WP_READ_LOCK(lock,flag) { DEBUG_TEST("%s:%d: RLock %u\n",__FILE__,__LINE__,(u32)lock);\ + flag = splimp(); } + +# define WP_READ_UNLOCK(lock,flag) { DEBUG_TEST("%s:%d: RULock %u\n",__FILE__,__LINE__,(u32)lock);\ + splx(flag);} + +# define WP_WRITE_LOCK(lock,flag) { DEBUG_TEST("%s:%d: WLock %u\n",__FILE__,__LINE__,(u32)lock); \ + flag = splimp(); } + +# define WP_WRITE_UNLOCK(lock,flag) { DEBUG_TEST("%s:%d: WULock %u\n",__FILE__,__LINE__,(u32)lock); \ + splx(flag); } + +#elif defined(__LINUX__) + +# define WAN_DEBUG_START(card) \ + if (!wan_test_and_set_bit(0, &card->debug_running)){\ + wan_add_timer(&card->debug_timer, 5*HZ); \ + } + +# define WAN_TIMEOUT(sec) { unsigned long timeout; \ + timeout=jiffies; \ + while ((jiffies-timeout)= 2){ \ + DEBUG_EVENT("%s:%u %s Jiffies=%lu\n", \ + __FUNCTION__,__LINE__,label,wptimeout); \ + }\ + \ + wptimeout=wptv2.tv_usec - wptv1.tv_usec; \ + if (wptimeout >= usec){ \ + DEBUG_EVENT("%s:%u %s:%s Usec=%lu\n", \ + __FUNCTION__,__LINE__,card->devname,label,wptimeout); \ + }\ + } + +#else + +#define WP_USEC_DEFINE() +#define WP_START_TIMING() +#define WP_STOP_TIMING_TEST(label,usec) + +#endif + + +static __inline void debug_print_skb_pkt(unsigned char *name, unsigned char *data, int len, int direction) +{ +#if defined(__LINUX__) && defined(__KERNEL__) + int i; + printk(KERN_INFO "%s: PKT Len(%i) Dir(%s)\n",name,len,direction?"RX":"TX"); + printk(KERN_INFO "%s: DATA: ",name); + for (i=0;i10)?10:res; + + if (i==sizeof(struct iphdr)+sizeof(struct udphdr)+ + sizeof(wan_mgmt_t)+sizeof(wan_cmd_t)+sizeof(wan_trace_info_t)+res){ + break; + } + + }else{ + + if (i==sizeof(struct iphdr)+sizeof(struct udphdr)+sizeof(wan_mgmt_t)+sizeof(wan_cmd_t)){ + DEBUG_EVENT("\n"); + DEBUG_EVENT("DATA PKT: "); + } + + res=len-(sizeof(struct iphdr)+sizeof(struct udphdr)+ + sizeof(wan_mgmt_t)+sizeof(wan_cmd_t)); + + res=(res>10)?10:res; + + if (i==sizeof(struct iphdr)+sizeof(struct udphdr)+ + sizeof(wan_mgmt_t)+sizeof(wan_cmd_t)+res){ + break; + } + } + + DEBUG_EVENT("%02X ",*(data+i)); + } + DEBUG_EVENT("\n"); +#endif +} + + + + + +typedef struct wanpipe_debug_hdr { + unsigned long magic; + unsigned long total_len; +} wanpipe_kernel_msg_info_t; + +#define WAN_DEBUG_SET_TRIGGER 0x01 +#define WAN_DEBUG_CLEAR_TRIGGER 0x02 + +#define WAN_DEBUG_READING 0x00 +#define WAN_DEBUG_FULL 0x01 +#define WAN_DEBUG_TRIGGER 0x02 + +extern void wan_debug_trigger(int); +extern void wan_debug_write(char*); +extern int wan_debug_read(void*, void*); + +/* NC Added to debug function calls */ +#if 0 +extern void wp_debug_func_init(void); +extern void wp_debug_func_add(unsigned char *func); +extern void wp_debug_func_print(void); +#endif + +#endif /* WAN_KERNEL */ +#endif /* __WANPIPE_DEBUG_H */ diff -Nur linux.org/include/linux/wanpipe_defines.h linux-2.6.17/include/linux/wanpipe_defines.h --- linux.org/include/linux/wanpipe_defines.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/wanpipe_defines.h 2006-08-30 10:07:15.000000000 +0000 @@ -0,0 +1,1147 @@ + +/* + ************************************************************************ + * wanpipe_defines.h * + * WANPIPE(tm) Global definition for Sangoma * + * Mailbox/API/UDP structures. * + * * + * Author: Alex Feldman * + *======================================================================* + * May 10 2002 Alex Feldman Initial version * + * * + ************************************************************************ + */ + +#ifndef __WANPIPE_DEFINES_H +# define __WANPIPE_DEFINES_H + +/************************************************ + * SET COMMON KERNEL DEFINE * + ************************************************/ +#if defined (__KERNEL__) || defined (KERNEL) || defined (_KERNEL) +# ifndef WAN_KERNEL +# define WAN_KERNEL +# endif +#endif + +#if defined(__LINUX__) +# include +# include +#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) +# include +# if defined(WAN_KERNEL) +# include +# endif +#endif + +/************************************************ + * GLOBAL SANGOMA PLATFORM DEFINITIONS * + ************************************************/ +#define WAN_LINUX_PLATFORM 0x01 +#define WAN_WIN98_PLATFORM 0x02 +#define WAN_WINNT_PLATFORM 0x03 +#define WAN_WIN2K_PLATFORM 0x04 +#define WAN_FREEBSD_PLATFORM 0x05 +#define WAN_OPENBSD_PLATFORM 0x06 +#define WAN_SOLARIS_PLATFORM 0x07 +#define WAN_SCO_PLATFORM 0x08 +#define WAN_NETBSD_PLATFORM 0x09 + +#if defined(__FreeBSD__) +# define WAN_PLATFORM_ID WAN_FREEBSD_PLATFORM +#elif defined(__OpenBSD__) +# define WAN_PLATFORM_ID WAN_OPENBSD_PLATFORM +#elif defined(__NetBSD__) +# define WAN_PLATFORM_ID WAN_NETBSD_PLATFORM +#elif defined(__LINUX__) +# define WAN_PLATFORM_ID WAN_LINUX_PLATFORM +#elif defined(__WINDOWS__) +# define WAN_PLATFORM_ID WAN_WIN2K_PLATFORM +#endif + +/************************************************ + * GLOBAL SANGOMA COMMAND RANGES * + ************************************************/ +#define WAN_PROTOCOL_CMD_START 0x01 +#define WAN_PROTOCOL_CMD_END 0x4F + +#define WAN_UDP_CMD_START 0x60 +#define WAN_GET_PROTOCOL (WAN_UDP_CMD_START+0) +#define WAN_GET_PLATFORM (WAN_UDP_CMD_START+1) +#define WAN_GET_MEDIA_TYPE (WAN_UDP_CMD_START+2) +#define WAN_GET_MASTER_DEV_NAME (WAN_UDP_CMD_START+3) +#define WAN_UDP_CMD_END 0x6F + +#define WAN_FE_CMD_START 0x90 +#define WAN_FE_CMD_END 0x9F + +#define WAN_INTERFACE_CMD_START 0xA0 +#define WAN_INTERFACE_CMD_END 0xAF + +#define WAN_FE_UDP_CMD_START 0xB0 +#define WAN_FE_UDP_CMD_END 0xBF + +/* +************************************************ +** GLOBAL SANGOMA DEFINITIONS +************************************************ +*/ +#define WAN_FALSE 0 +#define WAN_TRUE 1 + +#if defined(__FreeBSD__) +# undef WANPIPE_VERSION +# undef WANPIPE_VERSION_BETA +# undef WANPIPE_SUB_VERSION +# undef WANPIPE_LITE_VERSION +# define WANPIPE_VERSION WANPIPE_VERSION_FreeBSD +# define WANPIPE_VERSION_BETA WANPIPE_VERSION_BETA_FreeBSD +# define WANPIPE_SUB_VERSION WANPIPE_SUB_VERSION_FreeBSD +# define WANPIPE_LITE_VERSION WANPIPE_LITE_VERSION_FreeBSD +#elif defined(__OpenBSD__) +# undef WANPIPE_VERSION +# undef WANPIPE_VERSION_BETA +# undef WANPIPE_SUB_VERSION +# undef WANPIPE_LITE_VERSION +# define WANPIPE_VERSION WANPIPE_VERSION_OpenBSD +# define WANPIPE_VERSION_BETA WANPIPE_VERSION_BETA_OpenBSD +# define WANPIPE_SUB_VERSION WANPIPE_SUB_VERSION_OpenBSD +# define WANPIPE_LITE_VERSION WANPIPE_LITE_VERSION_OpenBSD +#elif defined(__NetBSD__) +# undef WANPIPE_VERSION +# undef WANPIPE_VERSION_BETA +# undef WANPIPE_SUB_VERSION +# undef WANPIPE_LITE_VERSION +# define WANPIPE_VERSION WANPIPE_VERSION_NetBSD +# define WANPIPE_VERSION_BETA WANPIPE_VERSION_BETA_NetBSD +# define WANPIPE_SUB_VERSION WANPIPE_SUB_VERSION_NetBSD +# define WANPIPE_LITE_VERSION WANPIPE_LITE_VERSION_NetBSD +#elif defined(__WINDOWS__) +# undef WANPIPE_VERSION +# undef WANPIPE_VERSION_BETA +# undef WANPIPE_SUB_VERSION +# define WANPIPE_VERSION WANPIPE_VERSION_Windows +# define WANPIPE_VERSION_BETA WANPIPE_VERSION_BETA_Windows +# define WANPIPE_SUB_VERSION WANPIPE_SUB_VERSION_Windows +#endif + +#define WANROUTER_MAJOR_VER 2 +#define WANROUTER_MINOR_VER 1 + +#define WANPIPE_MAJOR_VER 1 +#define WANPIPE_MINOR_VER 1 +/* +************************************************* +** GLOBAL SANGOMA TYPEDEF +************************************************* +*/ +#if defined(__LINUX__) +typedef struct iphdr iphdr_t; +typedef struct udphdr udphdr_t; +typedef struct tcphdr tcphdr_t; +# define w_ip_v version +# define w_ip_hl ihl +# define w_ip_tos tos +# define w_ip_len tot_len +# define w_ip_id id +# define w_ip_off frag_off +# define w_ip_ttl ttl +# define w_ip_p protocol +# define w_ip_sum check +# define w_ip_src saddr +# define w_ip_dst daddr +# define w_udp_sport source +# define w_udp_dport dest +# define w_udp_len len +# define w_udp_sum check +# define w_tcp_sport source +# define w_tcp_dport dest +# define w_tcp_seq seq +# define w_tcp_ack_seq ack_seq +#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) +typedef struct ip iphdr_t; +typedef struct udphdr udphdr_t; +typedef struct tcphdr tcphdr_t; +# define w_ip_v ip_v +# define w_ip_hl ip_hl +# define w_ip_tos ip_tos +# define w_ip_len ip_len +# define w_ip_id ip_id +# define w_ip_off ip_off +# define w_ip_ttl ip_ttl +# define w_ip_p ip_p +# define w_ip_sum ip_sum +# define w_ip_src ip_src.s_addr +# define w_ip_dst ip_dst.s_addr +# define w_udp_sport uh_sport +# define w_udp_dport uh_dport +# define w_udp_len uh_ulen +# define w_udp_sum uh_sum +# define w_tcp_sport th_sport +# define w_tcp_dport th_dport +# define w_tcp_seq th_seq +# define w_tcp_ack_seq th_ack +#elif defined(__WINDOWS__) +typedef void* iphdr_t; +typedef void* udphdr_t; +#else +# error "Unknown OS system!" +#endif + +/************************************************ +** GLOBAL SANGOMA MACROS +************************************************/ +#if defined(__LINUX__) +# define strlcpy(d,s,l) strcpy(d,s) +#elif defined(__FreeBSD__) +# define strlcpy(d,s,l) strcpy(d,s) +#endif + +/************************************************ + * GLOBAL DEFINITION FOR SANGOMA MAILBOX * + ************************************************/ +#define WAN_MAILBOX_SIZE 16 +#define WAN_MAX_DATA_SIZE 2032 +#define WAN_MAX_POS_DATA_SIZE 1030 + +#pragma pack(1) +typedef struct { + union { + struct { + unsigned char opp_flag; + unsigned char command; + unsigned short data_len; + unsigned char return_code; + union { + struct { + unsigned char PF_bit; /* the HDLC P/F bit */ + } hdlc; + struct { + unsigned short dlci; /* DLCI number */ + unsigned char attr; /* FECN, BECN, DE and C/R bits */ + unsigned short rxlost1; /* frames discarded at int. level */ + u_int32_t rxlost2; /* frames discarded at app. level */ + } fr; + struct { + unsigned char pf; /* P/F bit */ + unsigned short lcn; /* logical channel */ + unsigned char qdm; /* Q/D/M bits */ + unsigned char cause; /* cause field */ + unsigned char diagn; /* diagnostics */ + unsigned char pktType; /* packet type */ + } x25; + struct { + unsigned char misc_Tx_Rx_bits; /* miscellaneous transmit and receive bits */ + unsigned char Rx_error_bits; /* an indication of a block received with an error */ + unsigned short Rx_time_stamp; /* a millisecond receive time stamp */ + unsigned char port; /* comm port */ + } bscstrm; + struct { + unsigned char misc_tx_rx_bits; + unsigned short heading_length; + unsigned short notify; + unsigned char station; + unsigned char poll_address; + unsigned char select_address; + unsigned char device_address; + unsigned char notify_extended; + } bsc; + struct { + unsigned char sdlc_address; + unsigned char PF_bit; + unsigned short poll_interval; + unsigned char general_mailbox_byte; + } sdlc; + } wan_protocol; + } wan_p_cmd; + struct { + unsigned char opp_flag; + unsigned char pos_state; + unsigned char async_state; + } wan_pos_cmd; + unsigned char mbox[WAN_MAILBOX_SIZE]; + } wan_cmd_u; +#define wan_cmd_opp_flag wan_cmd_u.wan_p_cmd.opp_flag +#define wan_cmd_command wan_cmd_u.wan_p_cmd.command +#define wan_cmd_data_len wan_cmd_u.wan_p_cmd.data_len +#define wan_cmd_return_code wan_cmd_u.wan_p_cmd.return_code +#define wan_cmd_hdlc_PF_bit wan_cmd_u.wan_p_cmd.wan_protocol.hdlc.PF_bit +#define wan_cmd_fr_dlci wan_cmd_u.wan_p_cmd.wan_protocol.fr.dlci +#define wan_cmd_fr_attr wan_cmd_u.wan_p_cmd.wan_protocol.fr.attr +#define wan_cmd_fr_rxlost1 wan_cmd_u.wan_p_cmd.wan_protocol.fr.rxlost1 +#define wan_cmd_fr_rxlost2 wan_cmd_u.wan_p_cmd.wan_protocol.fr.rxlost2 +#define wan_cmd_x25_pf wan_cmd_u.wan_p_cmd.wan_protocol.x25.pf +#define wan_cmd_x25_lcn wan_cmd_u.wan_p_cmd.wan_protocol.x25.lcn +#define wan_cmd_x25_qdm wan_cmd_u.wan_p_cmd.wan_protocol.x25.qdm +#define wan_cmd_x25_cause wan_cmd_u.wan_p_cmd.wan_protocol.x25.cause +#define wan_cmd_x25_diagn wan_cmd_u.wan_p_cmd.wan_protocol.x25.diagn +#define wan_cmd_x25_pktType wan_cmd_u.wan_p_cmd.wan_protocol.x25.pktType +#define wan_cmd_bscstrm_misc_bits wan_cmd_u.wan_p_cmd.wan_protocol.bscstrm.misc_Tx_Rx_bits +#define wan_cmd_bscstrm_Rx_err_bits wan_cmd_u.wan_p_cmd.wan_protocol.bscstrm.Rx_error_bits +#define wan_cmd_bscstrm_Rx_time_stamp wan_cmd_u.wan_p_cmd.wan_protocol.bscstrm.Rx_time_stamp +#define wan_cmd_bscstrm_port wan_cmd_u.wan_p_cmd.wan_protocol.bscstrm.port +#define wan_cmd_bsc_misc_bits wan_cmd_u.wan_p_cmd.wan_protocol.bsc.misc_tx_rx_bits +#define wan_cmd_bsc_heading_len wan_cmd_u.wan_p_cmd.wan_protocol.bsc.heading_length +#define wan_cmd_bsc_notify wan_cmd_u.wan_p_cmd.wan_protocol.bsc.notify +#define wan_cmd_bsc_station wan_cmd_u.wan_p_cmd.wan_protocol.bsc.station +#define wan_cmd_bsc_poll_addr wan_cmd_u.wan_p_cmd.wan_protocol.bsc.poll_address +#define wan_cmd_bsc_select_addr wan_cmd_u.wan_p_cmd.wan_protocol.bsc.select_address +#define wan_cmd_bsc_device_addr wan_cmd_u.wan_p_cmd.wan_protocol.bsc.device_address +#define wan_cmd_bsc_notify_ext wan_cmd_u.wan_p_cmd.wan_protocol.bsc.notify_extended +#define wan_cmd_sdlc_address wan_cmd_u.wan_p_cmd.wan_protocol.sdlc.sdlc_address +#define wan_cmd_sdlc_pf wan_cmd_u.wan_p_cmd.wan_protocol.sdlc.PF_bit +#define wan_cmd_sdlc_poll_interval wan_cmd_u.wan_p_cmd.wan_protocol.sdlc.poll_interval +#define wan_cmd_sdlc_general_mb_byte wan_cmd_u.wan_p_cmd.wan_protocol.sdlc.general_mailbox_byte + +#define wan_cmd_pos_opp_flag wan_cmd_u.wan_pos_cmd.opp_flag +#define wan_cmd_pos_pos_state wan_cmd_u.wan_pos_cmd.pos_state +#define wan_cmd_pos_async_state wan_cmd_u.wan_pos_cmd.async_state +} wan_cmd_t; + + +typedef struct { + wan_cmd_t wan_cmd; + union { + struct { + unsigned char command; + unsigned short data_len; + unsigned char return_code; + unsigned char port_num; + unsigned char attr; + unsigned char reserved[10]; + unsigned char data[WAN_MAX_POS_DATA_SIZE]; + } pos_data; + unsigned char data[WAN_MAX_DATA_SIZE]; + } wan_u_data; +#define wan_opp_flag wan_cmd.wan_cmd_opp_flag +#define wan_command wan_cmd.wan_cmd_command +#define wan_data_len wan_cmd.wan_cmd_data_len +#define wan_return_code wan_cmd.wan_cmd_return_code +#define wan_hdlc_PF_bit wan_cmd.wan_cmd_hdlc_PF_bit +#define wan_fr_dlci wan_cmd.wan_cmd_fr_dlci +#define wan_fr_attr wan_cmd.wan_cmd_fr_attr +#define wan_fr_rxlost1 wan_cmd.wan_cmd_fr_rxlost1 +#define wan_fr_rxlost2 wan_cmd.wan_cmd_fr_rxlost2 +#define wan_x25_pf wan_cmd.wan_cmd_x25_pf +#define wan_x25_lcn wan_cmd.wan_cmd_x25_lcn +#define wan_x25_qdm wan_cmd.wan_cmd_x25_qdm +#define wan_x25_cause wan_cmd.wan_cmd_x25_cause +#define wan_x25_diagn wan_cmd.wan_cmd_x25_diagn +#define wan_x25_pktType wan_cmd.wan_cmd_x25_pktType +#define wan_bscstrm_misc_bits wan_cmd.wan_cmd_bscstrm_misc_bits +#define wan_bscstrm_Rx_err_bits wan_cmd.wan_cmd_bscstrm_Rx_error_bits +#define wan_bscstrm_Rx_time_stamp wan_cmd.wan_cmd_bscstrm_Rx_time_stamp +#define wan_bscstrm_port wan_cmd.wan_cmd_bscstrm_port +#define wan_bsc_misc_bits wan_cmd.wan_cmd_bsc_misc_bits +#define wan_bsc_heading_len wan_cmd.wan_cmd_bsc_heading_length +#define wan_bsc_notify wan_cmd.wan_cmd_bsc_notify +#define wan_bsc_station wan_cmd.wan_cmd_bsc_station +#define wan_bsc_poll_addr wan_cmd.wan_cmd_bsc_poll_address +#define wan_bsc_select_addr wan_cmd.wan_cmd_bsc_select_address +#define wan_bsc_device_addr wan_cmd.wan_cmd_bsc_device_address +#define wan_bsc_notify_ext wan_cmd.wan_cmd_bsc_notify_extended +#define wan_sdlc_address wan_cmd.wan_cmd_sdlc_address +#define wan_sdlc_pf wan_cmd.wan_cmd_sdlc_pf +#define wan_sdlc_poll_interval wan_cmd.wan_cmd_sdlc_poll_interval +#define wan_sdlc_general_mb_byte wan_cmd.wan_cmd_sdlc_general_mb_byte +#define wan_data wan_u_data.data + +#define wan_pos_opp_flag wan_cmd.wan_cmd_pos_opp_flag +#define wan_pos_pos_state wan_cmd.wan_cmd_pos_pos_state +#define wan_pos_async_state wan_cmd.wan_cmd_pos_async_state +#define wan_pos_command wan_u_data.pos_data.command +#define wan_pos_data_len wan_u_data.pos_data.data_len +#define wan_pos_return_code wan_u_data.pos_data.return_code +#define wan_pos_port_num wan_u_data.pos_data.port_num +#define wan_pos_attr wan_u_data.pos_data.attr +#define wan_pos_data wan_u_data.pos_data.data +} wan_mbox_t; + +#define WAN_MBOX_INIT(mbox) memset(mbox, 0, sizeof(wan_cmd_t)); + +/******************************************************** + * GLOBAL DEFINITION FOR SANGOMA API STRUCTURE * + *******************************************************/ +#define WAN_API_MAX_DATA 2048 +typedef struct{ + unsigned char pktType; + unsigned short length; + unsigned char result; + union { + struct { + unsigned char arg1; + unsigned short time_stamp; + } chdlc; + struct { + unsigned char attr; + unsigned short time_stamp; + } fr; + struct { + unsigned char qdm; + unsigned char cause; + unsigned char diagn; + unsigned short lcn; + } x25; + struct { + unsigned char station; + unsigned char PF_bit; + unsigned short poll_interval; + unsigned char general_mailbox_byte; + }sdlc; + struct { + unsigned char exception; + }xdlc; + } wan_protocol; +#define wan_apihdr_chdlc_error_flag wan_protocol.chdlc.arg1 +#define wan_apihdr_chdlc_attr wan_protocol.chdlc.arg1 +#define wan_apihdr_chdlc_time_stamp wan_protocol.chdlc.time_stamp +#define wan_apihdr_fr_attr wan_protocol.fr.attr +#define wan_apihdr_fr_time_stamp wan_protocol.fr.time_stamp +#define wan_apihdr_x25_qdm wan_protocol.x25.qdm +#define wan_apihdr_x25_cause wan_protocol.x25.cause +#define wan_apihdr_x25_diagn wan_protocol.x25.diagn +#define wan_apihdr_x25_lcn wan_protocol.x25.lcn + +#define wan_apihdr_sdlc_station wan_protocol.sdlc.station +#define wan_apihdr_sdlc_pf wan_protocol.sdlc.PF_bit +#define wan_apihdr_sdlc_poll_interval wan_protocol.sdlc.poll_interval +#define wan_apihdr_sdlc_general_mb_byte wan_protocol.sdlc.general_mailbox_byte + +#define wan_apihdr_xdlc_exception wan_protocol.xdlc.exception +} wan_api_hdr_t; + + +typedef struct{ + wan_api_hdr_t api_hdr; + unsigned char data[WAN_API_MAX_DATA]; +#define wan_api_pktType api_hdr.pktType +#define wan_api_length api_hdr.length +#define wan_api_result api_hdr.result +#define wan_api_chdlc_error_flag api_hdr.wan_apihdr_chdlc_error_flag +#define wan_api_chdlc_time_stamp api_hdr.wan_apihdr_chdlc_time_stamp +#define wan_api_chdlc_attr api_hdr.wan_apihdr_chdlc_attr +#define wan_api_chdlc_misc_Tx_bits api_hdr.wan_apihdr_chdlc_misc_Tx_bits +#define wan_api_fr_attr api_hdr.wan_apihdr_fr_attr +#define wan_api_fr_time_stamp api_hdr.wan_apihdr_fr_time_stamp +#define wan_api_x25_qdm api_hdr.wan_apihdr_x25_qdm +#define wan_api_x25_cause api_hdr.wan_apihdr_x25_cause +#define wan_api_x25_diagn api_hdr.wan_apihdr_x25_diagn +#define wan_api_x25_lcn api_hdr.wan_apihdr_x25_lcn +#define wan_api_sdlc_station api_hdr.wan_apihdr_sdlc_station +#define wan_api_sdlc_pf api_hdr.wan_apihdr_sdlc_pf +#define wan_api_sdlc_poll_interval api_hdr.wan_apihdr_sdlc_poll_interval +#define wan_api_sdlc_general_mb_byte api_hdr.wan_apihdr_sdlc_general_mb_byte +#define wan_api_xdlc_exception api_hdr.wan_apihdr_xdlc_exception +} wan_api_t; + + +typedef struct { + union { + struct { + unsigned char error_flag; + unsigned short time_stamp; + }chdlc,hdlc; + struct { + unsigned char exception; + unsigned char pf; + }lapb; + struct { + unsigned char state; + unsigned char address; + unsigned short exception; + }xdlc; + unsigned char reserved[16]; + }u; + +#define wan_hdr_xdlc_state u.xdlc.state +#define wan_hdr_xdlc_address u.xdlc.address +#define wan_hdr_xdlc_exception u.xdlc.exception +} wan_api_rx_hdr_t; + +typedef struct { + wan_api_rx_hdr_t api_rx_hdr; + unsigned char data[0]; +#define wan_rxapi_xdlc_state api_rx_hdr.wan_hdr_xdlc_state +#define wan_rxapi_xdlc_address api_rx_hdr.wan_hdr_xdlc_address +#define wan_rxapi_xdlc_exception api_rx_hdr.wan_hdr_xdlc_exception +} wan_api_rx_element_t; + +typedef struct { + union{ + struct { + unsigned char attr; + unsigned char misc_Tx_bits; + }chdlc,hdlc; + struct { + unsigned char pf; + }lapb; + struct { + unsigned char pf; + }xdlc; + unsigned char reserved[16]; + }u; +} wan_api_tx_hdr_t; + +typedef struct { + wan_api_tx_hdr_t api_tx_hdr; + unsigned char data[0]; +}wan_api_tx_element_t; + +#pragma pack() + +enum { + SIOC_WAN_READ_REG = 0x01, + SIOC_WAN_WRITE_REG, + SIOC_WAN_HWPROBE, + SIOC_WAN_ALL_HWPROBE, + SIOC_WAN_ALL_READ_REG, + SIOC_WAN_ALL_WRITE_REG, + SIOC_WAN_ALL_SET_PCI_BIOS, + SIOC_WAN_SET_PCI_BIOS, + SIOC_WAN_COREREV, + SIOC_WAN_GET_CFG, + SIOC_WAN_FE_READ_REG, + SIOC_WAN_FE_WRITE_REG, + SIOC_WAN_EC_REG +}; + +typedef struct wan_cmd_api_ +{ + unsigned int cmd; + unsigned short len; + unsigned char bar; + unsigned short offset; + unsigned char data[WAN_MAX_DATA_SIZE]; +} wan_cmd_api_t; + + +/******************************************************** + * GLOBAL DEFINITION FOR SANGOMA UDP STRUCTURE * + *******************************************************/ +#define GLOBAL_UDP_SIGNATURE "WANPIPE" +#define GLOBAL_UDP_SIGNATURE_LEN 7 +#define UDPMGMT_UDP_PROTOCOL 0x11 + +typedef struct { + unsigned char signature[8]; + unsigned char request_reply; + unsigned char id; + unsigned char reserved[6]; +} wan_mgmt_t; + + +/****** DEFINITION OF UDP HEADER AND STRUCTURE PER PROTOCOL ******/ +typedef struct { + unsigned char num_frames; + unsigned char ismoredata; +} wan_trace_info_t; + +typedef struct wan_udp_hdr{ + wan_mgmt_t wan_mgmt; + wan_cmd_t wan_cmd; + union { + struct { + wan_trace_info_t trace_info; + unsigned char data[WAN_MAX_DATA_SIZE]; + } chdlc, adsl, atm, ss7,bitstrm,aft; +#define xilinx aft + unsigned char data[WAN_MAX_DATA_SIZE]; + } wan_udphdr_u; +#define wan_udphdr_signature wan_mgmt.signature +#define wan_udphdr_request_reply wan_mgmt.request_reply +#define wan_udphdr_id wan_mgmt.id +#define wan_udphdr_opp_flag wan_cmd.wan_cmd_opp_flag +#define wan_udphdr_command wan_cmd.wan_cmd_command +#define wan_udphdr_data_len wan_cmd.wan_cmd_data_len +#define wan_udphdr_return_code wan_cmd.wan_cmd_return_code +#define wan_udphdr_hdlc_PF_bit wan_cmd.wan_cmd_hdlc_PF_bit +#define wan_udphdr_fr_dlci wan_cmd.wan_cmd_fr_dlci +#define wan_udphdr_fr_attr wan_cmd.wan_cmd_fr_attr +#define wan_udphdr_fr_rxlost1 wan_cmd.wan_cmd_fr_rxlost1 +#define wan_udphdr_fr_rxlost2 wan_cmd.wan_cmd_fr_rxlost2 +#define wan_udphdr_x25_pf wan_cmd.wan_cmd_x25_pf +#define wan_udphdr_x25_lcn wan_cmd.wan_cmd_x25_lcn +#define wan_udphdr_x25_qdm wan_cmd.wan_cmd_x25_qdm +#define wan_udphdr_x25_cause wan_cmd.wan_cmd_x25_cause +#define wan_udphdr_x25_diagn wan_cmd.wan_cmd_x25_diagn +#define wan_udphdr_x25_pktType wan_cmd.wan_cmd_x25_pktType +#define wan_udphdr_bscstrm_misc_bits wan_cmd.wan_cmd_bscstrm_misc_bits +#define wan_udphdr_bscstrm_Rx_err_bits wan_cmd.wan_cmd_bscstrm_Rx_err_bits +#define wan_udphdr_bscstrm_Rx_time_stamp wan_cmd.wan_cmd_bscstrm_Rx_time_stamp +#define wan_udphdr_bscstrm_port wan_cmd.wan_cmd_bscstrm_port +#define wan_udphdr_bsc_misc_bits wan_cmd.wan_cmd_bsc_misc_bit +#define wan_udphdr_bsc_misc_heading_len wan_cmd.wan_cmd_bsc_misc_heading_len +#define wan_udphdr_bsc_misc_notify wan_cmd.wan_cmd_bsc_misc_notify +#define wan_udphdr_bsc_misc_station wan_cmd.wan_cmd_bsc_misc_station +#define wan_udphdr_bsc_misc_poll_add wan_cmd.wan_cmd_bsc_misc_poll_addr +#define wan_udphdr_bsc_misc_select_addr wan_cmd.wan_cmd_bsc_misc_select_addr +#define wan_udphdr_bsc_misc_device_addr wan_cmd.wan_cmd_bsc_misc_device_addr +#define wan_udphdr_chdlc_num_frames wan_udphdr_u.chdlc.trace_info.num_frames +#define wan_udphdr_chdlc_ismoredata wan_udphdr_u.chdlc.trace_info.ismoredata +#define wan_udphdr_chdlc_data wan_udphdr_u.chdlc.data + +#define wan_udphdr_bitstrm_num_frames wan_udphdr_u.bitstrm.trace_info.num_frames +#define wan_udphdr_bitstrm_ismoredata wan_udphdr_u.bitstrm.trace_info.ismoredata +#define wan_udphdr_bitstrm_data wan_udphdr_u.bitstrm.data + +#define wan_udphdr_adsl_num_frames wan_udphdr_u.adsl.trace_info.num_frames +#define wan_udphdr_adsl_ismoredata wan_udphdr_u.adsl.trace_info.ismoredata +#define wan_udphdr_adsl_data wan_udphdr_u.adsl.data +#define wan_udphdr_atm_num_frames wan_udphdr_u.atm.trace_info.num_frames +#define wan_udphdr_atm_ismoredata wan_udphdr_u.atm.trace_info.ismoredata +#define wan_udphdr_atm_data wan_udphdr_u.atm.data +#define wan_udphdr_ss7_num_frames wan_udphdr_u.ss7.trace_info.num_frames +#define wan_udphdr_ss7_ismoredata wan_udphdr_u.ss7.trace_info.ismoredata +#define wan_udphdr_ss7_data wan_udphdr_u.ss7.data +#define wan_udphdr_aft_num_frames wan_udphdr_u.aft.trace_info.num_frames +#define wan_udphdr_aft_ismoredata wan_udphdr_u.aft.trace_info.ismoredata +#define wan_udphdr_aft_data wan_udphdr_u.aft.data +#define wan_udphdr_data wan_udphdr_u.data +} wan_udp_hdr_t; + + +#ifdef WAN_KERNEL + +#if defined(__LINUX__) +# include +#elif defined(__FreeBSD__) || defned(__OpenBSD__) +# include +#endif + +/* +****************************************************************** +** D E F I N E S +****************************************************************** +*/ +#define MAX_PACKET_SIZE 5000 +#if defined(__FreeBSD__) +/******************* F R E E B S D ******************************/ +# define WAN_MOD_LOAD MOD_LOAD +# define WAN_MOD_UNLOAD MOD_UNLOAD +# if (__FreeBSD_version > 503000) +# define WAN_MOD_SHUTDOWN MOD_SHUTDOWN +# define WAN_MOD_QUIESCE MOD_QUIESCE +# else +# define WAN_MOD_SHUTDOWN WAN_MOD_UNLOAD+1 +# define WAN_MOD_QUIESCE WAN_MOD_UNLOAD+2 +# endif +# define WP_DELAY DELAY +# define WP_SCHEDULE(arg,name) tsleep(&(arg),PPAUSE,(name),(arg)) +# define SYSTEM_TICKS ticks +# define HZ hz +# define RW_LOCK_UNLOCKED 0 +# define ETH_P_IP AF_INET +# define ETH_P_IPV6 AF_INET6 +# define ETH_P_IPX AF_IPX +# define WAN_IFT_OTHER IFT_OTHER +# define WAN_IFT_ETHER IFT_ETHER +# define WAN_IFT_PPP IFT_PPP +# define WAN_MFLAG_PRV M_PROTO1 +#elif defined(__OpenBSD__) +/******************* O P E N B S D ******************************/ +# define WAN_MOD_LOAD LKM_E_LOAD +# define WAN_MOD_UNLOAD LKM_E_UNLOAD +# define WP_DELAY DELAY +# define WP_SCHEDULE(arg,name) tsleep(&(arg),PPAUSE,(name),(arg)) +# define SYSTEM_TICKS ticks +# define HZ hz +# define RW_LOCK_UNLOCKED 0 +# define ETH_P_IP AF_INET +# define ETH_P_IPV6 AF_INET6 +# define ETH_P_IPX AF_IPX +# define WAN_IFT_OTHER IFT_OTHER +# define WAN_IFT_ETHER IFT_ETHER +# define WAN_IFT_PPP IFT_PPP +# define WAN_MFLAG_PRV M_PROTO1 +#elif defined(__NetBSD__) +/******************* N E T B S D ******************************/ +# define WAN_MOD_LOAD LKM_E_LOAD +# define WAN_MOD_UNLOAD LKM_E_UNLOAD +# define WP_DELAY DELAY +# define SYSTEM_TICKS tick +# define HZ hz +# define RW_LOCK_UNLOCKED 0 +# define WAN_IFT_OTHER IFT_OTHER +# define WAN_IFT_ETHER IFT_ETHER +# define WAN_IFT_PPP IFT_PPP +#elif defined(__LINUX__) +/*********************** L I N U X ******************************/ +# define ETHER_ADDR_LEN ETH_ALEN +# define WP_DELAY(usecs) udelay(usecs) +# define atomic_set_int(name, val) atomic_set(name, val) +# define SYSTEM_TICKS jiffies +# define WP_SCHEDULE(arg,name) schedule() +# define wan_atomic_read atomic_read +# define wan_atomic_set atomic_set +# define wan_atomic_inc atomic_inc +# define wan_atomic_dec atomic_dec +# define WAN_IFT_OTHER 0x00 +# define WAN_IFT_ETHER 0x00 +# define WAN_IFT_PPP 0x00 +#elif defined(__WINDOWS__) +/******************* W I N D O W S ******************************/ +# define EINVAL 22 +# define IFNAMESIZ 16 +#endif + +#if defined(__FreeBSD__) +# define WAN_MODULE_VERSION(module, version) \ + MODULE_VERSION(module, version) +# define WAN_MODULE_DEPEND(module, mdepend, vmin, vpref, vmax) \ + MODULE_DEPEND(module, mdepend, vmin, vpref, vmax) +# define WAN_MODULE_DEFINE(name,name_str,author,descr,lic,mod_init,mod_exit,devsw)\ + int load_##name (module_t mod, int cmd, void *arg); \ + int load_##name (module_t mod, int cmd, void *arg){ \ + switch(cmd){ \ + case WAN_MOD_LOAD: return mod_init((devsw)); \ + case WAN_MOD_UNLOAD: \ + case WAN_MOD_SHUTDOWN: return mod_exit((devsw));\ + case WAN_MOD_QUIESCE: return 0; \ + } \ + return -EINVAL; \ + } \ + DEV_MODULE(name, load_##name, NULL); +#elif defined(__OpenBSD__) +# define WAN_MODULE_VERSION(module, version) +# define WAN_MODULE_DEPEND(module, mdepend, vmin, vpref, vmax) +# define WAN_MODULE_DEFINE(name,name_str,author,descr,lic,mod_init,mod_exit,devsw)\ + int (name)(struct lkm_table* lkmtp, int cmd, int ver);\ + MOD_DEV(name_str, LM_DT_CHAR, -1, (devsw)); \ + int load_##name(struct lkm_table* lkm_tp, int cmd){ \ + switch(cmd){ \ + case WAN_MOD_LOAD: return mod_init(NULL); \ + case WAN_MOD_UNLOAD: return mod_exit(NULL); \ + } \ + return -EINVAL; \ + } \ + int (name)(struct lkm_table* lkmtp, int cmd, int ver){\ + DISPATCH(lkmtp,cmd,ver,load_##name,load_##name,lkm_nofunc);\ + } +#elif defined(__NetBSD__) +# define WAN_MODULE_VERSION(module, version) +# define WAN_MODULE_DEPEND(module, mdepend, vmin, vpref, vmax) +# if (__NetBSD_Version__ < 200000000) +# define WAN_MOD_DEV(name,devsw) MOD_DEV(name,LM_DT_CHAR,-1,(devsw)); +# else +# define WAN_MOD_DEV(name,devsw) MOD_DEV(name,name,NULL,-1,(devsw),-1); +# endif +# define WAN_MODULE_DEFINE(name,name_str,author,descr,lic,mod_init,mod_exit,devsw)\ + int (##name_lkmentry)(struct lkm_table* lkmtp, int cmd, int ver);\ + WAN_MOD_DEV(name_str, (devsw)); \ + int load_##name(struct lkm_table* lkm_tp, int cmd){ \ + switch(cmd){ \ + case WAN_MOD_LOAD: return mod_init(NULL); \ + case WAN_MOD_UNLOAD: return mod_exit(NULL); \ + } \ + return -EINVAL; \ + } \ + int (##name_lkmentry)(struct lkm_table* lkmtp, int cmd, int ver){\ + DISPATCH(lkmtp,cmd,ver,load_##name,load_##name,lkm_nofunc);\ + } +#elif defined(__LINUX__) +# define WAN_MODULE_VERSION(module, version) +# define WAN_MODULE_DEPEND(module, mdepend, vmin, vpref, vmax) +# define WAN_MODULE_DEFINE(name,name_str,author,descr,lic,mod_init,mod_exit,devsw)\ + MODULE_AUTHOR (author); \ + MODULE_DESCRIPTION (descr); \ + MODULE_LICENSE(lic); \ + int __init load_##name(void){return mod_init(NULL);} \ + void __exit unload_##name(void){mod_exit(NULL);} \ + module_init(load_##name); \ + module_exit(unload_##name); + +#elif defined(__SOLARIS__) +# define WAN_MODULE_VERSION(module, version) +# define WAN_MODULE_DEPEND(module, mdepend, vmin, vpref, vmax) +# define WAN_MODULE_DEFINE(name,name_str,author,descr,lic,mod_init,mod_exit,devsw)\ + int _init(void){\ + int err=mod_init(NULL); \ + if (err) return err; \ + err=mod_install(&modlinkage) \ + if (err) cmn_err(CE_CONT, "mod_install: failed\n"); \ + return err; \ + }\ + void _fini(void){ \ + int status \ + mod_exit(NULL); \ + if ((status = mod_remove(&modlinkage)) != 0) \ + cmn_err(CE_CONT, "mod_remove: failed\n"); \ + return status; \ + }\ + int _info(struct modinfo* modinfop) \ + { \ + dcmn_err((CE_CONT, "Get module info!\n")); \ + return (mod_info(&modlinkage, modinfop)); \ + } +#endif + +/* +****************************************************************** +** T Y P E D E F +****************************************************************** +*/ +#if !defined(offsetof) +# define offsetof(type, member) ((size_t)(&((type*)0)->member)) +#endif + +#if defined(__LINUX__) +typedef struct sk_buff netskb_t; +typedef struct sk_buff_head wan_skb_queue_t; +typedef struct ethhdr ethhdr_t; +typedef struct timer_list wan_timer_info_t; +typedef void (*wan_timer_func_t)(unsigned long); +typedef unsigned long wan_timer_arg_t; +typedef void wan_tasklet_func_t(unsigned long); +typedef void (*wan_taskq_func_t)(void *); +typedef void* virt_addr_t; +typedef unsigned long phys_addr_t; +typedef spinlock_t wan_spinlock_t; +typedef rwlock_t wan_rwlock_t; +typedef unsigned long wan_smp_flag_t; +typedef unsigned long wan_rwlock_flag_t; + +typedef void (*TASKQ_FUNC)(void *); +typedef struct tty_driver ttydriver_t; +typedef struct tty_struct ttystruct_t; +typedef struct termios termios_t; +# if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,10) +# define vsnprintf(a,b,c,d) vsprintf(a,c,d) +# endif +typedef void* wan_dma_tag_t; +typedef wait_queue_head_t wan_waitq_head_t; +#elif defined(__FreeBSD__) +typedef u_int8_t u8; +typedef u_int16_t u16; +typedef u_int32_t u32; +typedef u_int64_t u64; +typedef struct ifnet netdevice_t; +typedef struct mbuf netskb_t; +# ifdef ALTQ +typedef struct ifaltq wan_skb_queue_t; +# else +typedef struct ifqueue wan_skb_queue_t; +# endif +typedef struct ether_header ethhdr_t; +typedef struct callout_handle wan_timer_info_t; +typedef timeout_t* wan_timer_func_t; +typedef void* wan_timer_arg_t; +typedef task_fn_t wan_tasklet_func_t; +typedef task_fn_t* wan_taskq_func_t; +typedef caddr_t virt_addr_t; +typedef u_int32_t phys_addr_t; +typedef int atomic_t; +typedef dev_t ttydriver_t; +typedef struct tty ttystruct_t; +typedef struct termios termios_t; +typedef int (get_info_t)(char *, char **, off_t, int, int); +typedef int wan_spinlock_t; +typedef int wan_rwlock_t; +typedef int wan_smp_flag_t; +typedef int wan_rwlock_flag_t; +# if (__FreeBSD_version < 450000) +typedef struct proc wan_dev_thread_t; +# else +typedef d_thread_t wan_dev_thread_t; +# endif +typedef bus_dma_tag_t wan_dma_tag_t; +typedef int wan_waitq_head_t; +#elif defined(__OpenBSD__) +typedef u_int8_t u8; +typedef u_int16_t u16; +typedef u_int32_t u32; +typedef u_int64_t u64; +typedef struct ifnet netdevice_t; +typedef struct mbuf netskb_t; +# ifdef ALTQ +typedef struct ifaltq wan_skb_queue_t; +# else +typedef struct ifqueue wan_skb_queue_t; +# endif +typedef struct ether_header ethhdr_t; +typedef struct timeout wan_timer_info_t; +typedef void (*wan_timer_func_t)(void*); +typedef void* wan_timer_arg_t; +typedef void wan_tasklet_func_t(void*, int); +typedef void (*wan_taskq_func_t)(void*, int); +typedef caddr_t virt_addr_t; +typedef u_int32_t phys_addr_t; +typedef int atomic_t; +typedef dev_t ttydriver_t; +typedef struct tty ttystruct_t; +typedef struct termios termios_t; +typedef int (get_info_t)(char *, char **, off_t, int, int); +typedef bus_dma_tag_t wan_dma_tag_t; +typedef int wan_spinlock_t; +typedef int wan_smp_flag_t; +typedef int wan_rwlock_t; +typedef int wan_rwlock_flag_t; +#elif defined(__NetBSD__) +typedef u_int8_t u8; +typedef u_int16_t u16; +typedef u_int32_t u32; +typedef u_int64_t u64; +typedef struct ifnet netdevice_t; +typedef struct mbuf netskb_t; +# ifdef ALTQ +typedef struct ifaltq wan_skb_queue_t; +# else +typedef struct ifqueue wan_skb_queue_t; +# endif +typedef struct ether_header ethhdr_t; +typedef struct callout wan_timer_info_t; +typedef void (*wan_timer_func_t)(void*); +typedef void* wan_timer_arg_t; +typedef void wan_tasklet_func_t(void*, int); +typedef void (*wan_taskq_func_t)(void*, int); +typedef caddr_t virt_addr_t; +typedef u_int32_t phys_addr_t; +typedef int atomic_t; +typedef dev_t ttydriver_t; +typedef struct tty ttystruct_t; +typedef struct termios termios_t; +typedef int (get_info_t)(char *, char **, off_t, int, int); +typedef bus_dma_tag_t wan_dma_tag_t; +typedef int wan_spinlock_t; +typedef int wan_smp_flag_t; +typedef int wan_rwlock_t; +typedef int wan_rwlock_flag_t; +#elif defined(__SOLARIS__) +typedef mblk_t netskb_t; + + +#elif defined(__WINDOWS__) +typedef UCHAR u8; +typedef UINT u16; +typedef USHORT u32; +typedef ULONG u64; +typedef char* caddr_t; +# if defined(NDIS_MINIPORT_DRIVER) +typedef NDIS_MINIPORT_TIMER wan_timer_info_t; +# else +typedef KTIMER wan_timer_info_t; +# endif + +typedef void netdevice_t; +typedef void* wan_skb_queue_t; +typedef void (*wan_timer_func_t)(void*); +#endif + +/* + * Spin Locks + */ +#if 0 +typedef struct _wan_spinlock +{ +#if defined(__LINUX__) + spinlock_t slock; + unsigned long flags; +#elif defined(MAC_OS) + ULONG slock; +#elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) + int slock; +#endif /* OS */ +} wan_spinlock_t; +#endif + +/* + * Read Write Locks + */ +#if 0 +typedef struct _wan_rwlock +{ +#if defined(__LINUX__) + rwlock_t rwlock; +#elif defined(MAC_OS) + #error "wan_rwlock_t not defined" +#elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) + volatile unsigned int lock; +#else + #error "wan_rwlock_t not defined" +#endif /* OS */ +} wan_rwlock_t; +#endif + +/* +** FIXME: Redefined from sdla_adsl.c +** DMA structure +*/ +typedef struct _wan_dma_descr +{ + unsigned long* vAddr; + unsigned long pAddr; + unsigned long length; + unsigned long max_length; +#if defined(__FreeBSD__) + bus_dma_tag_t dmat; + bus_dmamap_t dmamap; +#elif defined(__OpenBSD__) + bus_dma_tag_t dmat; + bus_dma_segment_t dmaseg; + int rsegs; +#elif defined(__NetBSD__) + bus_dma_tag_t dmat; + bus_dma_segment_t dmaseg; + int rsegs; +#else /* other OS */ +#endif +} wan_dma_descr_t;/*, *PDMA_DESCRIPTION;*/ + +/* +** TASK structure +*/ +typedef struct _wan_tasklet +{ + unsigned long running; +#if defined(__FreeBSD__) && (__FreeBSD_version >= 410000) + struct task task_id; +#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) + wan_tasklet_func_t* task_func; + void* data; +#elif defined(__LINUX__) + struct tasklet_struct task_id; +#elif defined(__SOLARIS__) +#error "wan_tasklet: not defined in solaris" +#endif +} wan_tasklet_t; + + +typedef struct _wan_taskq +{ + unsigned char running; +#if defined(__FreeBSD__) && (__FreeBSD_version >= 410000) + struct task tqueue; +#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) + wan_taskq_func_t tfunc; + void* data; +#elif defined(__LINUX__) + struct tq_struct tqueue; +#elif defined(__SOLARIS__) +#error "_wan_taskq: not defined in solaris" +#endif +} wan_taskq_t; + +typedef struct wan_trace +{ + u_int32_t tracing_enabled; + wan_skb_queue_t trace_queue; + unsigned long trace_timeout;/* WARNING: has to be 'unsigned long' !!!*/ + unsigned int max_trace_queue; + unsigned char last_trace_direction; + u_int32_t missed_idle_rx_counter; +}wan_trace_t; + + + +/* +** TIMER structure +*/ +typedef struct _wan_timer +{ +#define NDIS_TIMER_TAG 0xBEEF0005 + unsigned long Tag; + wan_timer_func_t MiniportTimerFunction; + void * MiniportTimerContext; + void * MiniportAdapterHandle; + wan_timer_info_t timer_info; +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) + wan_timer_func_t timer_func; +#elif defined(__WINDOWS__) + KDPC TimerDpcObject; +#endif + void* timer_arg; +} wan_timer_t; + +#if !defined(LINUX_2_6) +/* Define this structure for BSDs and not Linux-2.6 */ +struct seq_file { + char* buf; /* pointer to buffer (buf)*/ + size_t size; /* total buffer len (len)*/ + size_t from; /* total buffer len (offs)*/ + size_t count; /* offset into buffer (cnt)*/ +# if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) + unsigned long index; /* iteration index*/ +# else + loff_t index; /* iteration index*/ +# endif + int stop_cnt;/* last stop offset*/ +}; +#endif + + + +/****** DEFINITION OF UDP HEADER AND STRUCTURE PER PROTOCOL *******/ +typedef struct wan_udp_pkt { + iphdr_t ip_hdr; + udphdr_t udp_hdr; + wan_udp_hdr_t wan_udp_hdr; +#define wan_ip ip_hdr +#define wan_ip_v ip_hdr.w_ip_v +#define wan_ip_tos ip_hdr.w_ip_tos +#define wan_ip_len ip_hdr.w_ip_len +#define wan_ip_id ip_hdr.w_ip_id +#define wan_ip_off ip_hdr.w_ip_off +#define wan_ip_ttl ip_hdr.w_ip_ttl +#define wan_ip_p ip_hdr.w_ip_p +#define wan_ip_sum ip_hdr.w_ip_sum +#define wan_ip_src ip_hdr.w_ip_src +#define wan_ip_dst ip_hdr.w_ip_dst +#define wan_udp_sport udp_hdr.w_udp_sport +#define wan_udp_dport udp_hdr.w_udp_dport +#define wan_udp_len udp_hdr.w_udp_len +#define wan_udp_sum udp_hdr.w_udp_sum +#define wan_udp_cmd wan_udp_hdr.wan_cmd +#define wan_udp_signature wan_udp_hdr.wan_udphdr_signature +#define wan_udp_request_reply wan_udp_hdr.wan_udphdr_request_reply +#define wan_udp_id wan_udp_hdr.wan_udphdr_id +#define wan_udp_opp_flag wan_udp_hdr.wan_udphdr_opp_flag +#define wan_udp_command wan_udp_hdr.wan_udphdr_command +#define wan_udp_data_len wan_udp_hdr.wan_udphdr_data_len +#define wan_udp_return_code wan_udp_hdr.wan_udphdr_return_code +#define wan_udp_hdlc_PF_bit wan_udp_hdr.wan_udphdr_hdlc_PF_bit +#define wan_udp_fr_dlci wan_udp_hdr.wan_udphdr_fr_dlci +#define wan_udp_fr_attr wan_udp_hdr.wan_udphdr_fr_attr +#define wan_udp_fr_rxlost1 wan_udp_hdr.wan_udphdr_fr_rxlost1 +#define wan_udp_fr_rxlost2 wan_udp_hdr.wan_udphdr_fr_rxlost2 +#define wan_udp_x25_pf wan_udp_hdr.wan_udphdr_x25_pf +#define wan_udp_x25_lcn wan_udp_hdr.wan_udphdr_x25_lcn +#define wan_udp_x25_qdm wan_udp_hdr.wan_udphdr_x25_qdm +#define wan_udp_x25_cause wan_udp_hdr.wan_udphdr_x25_cause +#define wan_udp_x25_diagn wan_udp_hdr.wan_udphdr_x25_diagn +#define wan_udp_x25_pktType wan_udp_hdr.wan_udphdr_x25_pktType +#define wan_udp_bscstrm_misc_bits wan_udp_hdr.wan_udphdr_bscstrm_misc_bits +#define wan_udp_bscstrm_Rx_err_bits wan_udp_hdr.wan_udphdr_bscstrm_Rx_err_bits +#define wan_udp_bscstrm_Rx_time_stam wan_udp_hdr.wan_udphdr_bscstrm_Rx_time_stamp +#define wan_udp_bscstrm_port wan_udp_hdr.wan_udphdr_bscstrm_port +#define wan_udp_bsc_misc_bits wan_udp_hdr.wan_udphdr_bsc_misc_bits +#define wan_udp_bsc_misc_heading_len wan_udp_hdr.wan_udphdr_bsc_misc_heading_len +#define wan_udp_bsc_misc_notify wan_udp_hdr.wan_udphdr_bsc_misc_notify +#define wan_udp_bsc_misc_station wan_udp_hdr.wan_udphdr_bsc_misc_station +#define wan_udp_bsc_misc_poll_add wan_udp_hdr.wan_udphdr_bsc_misc_poll_add +#define wan_udp_bsc_misc_select_addr wan_udp_hdr.wan_udphdr_bsc_misc_select_addr +#define wan_udp_bsc_misc_device_addr wan_udp_hdr.wan_udphdr_bsc_misc_device_addr +#define wan_udp_bsc_misc_notify_ext wan_udp_hdr.wan_udphdr_bsc_misc_notify_ext +#define wan_udp_chdlc_num_frames wan_udp_hdr.wan_udphdr_chdlc_num_frames +#define wan_udp_chdlc_ismoredata wan_udp_hdr.wan_udphdr_chdlc_ismoredata +#define wan_udp_chdlc_data wan_udp_hdr.wan_udphdr_chdlc_data + +#define wan_udp_bitstrm_num_frames wan_udp_hdr.wan_udphdr_bitstrm_num_frames +#define wan_udp_bitstrm_ismoredata wan_udp_hdr.wan_udphdr_bitstrm_ismoredata +#define wan_udp_bitstrm_data wan_udp_hdr.wan_udphdr_bitstrm_data + +#define wan_udp_adsl_num_frames wan_udp_hdr.wan_udphdr_adsl_num_frames +#define wan_udp_adsl_ismoredata wan_udp_hdr.wan_udphdr_adsl_ismoredata +#define wan_udp_adsl_data wan_udp_hdr.wan_udphdr_adsl_data +#define wan_udp_atm_num_frames wan_udp_hdr.wan_udphdr_atm_num_frames +#define wan_udp_atm_ismoredata wan_udp_hdr.wan_udphdr_atm_ismoredata +#define wan_udp_atm_data wan_udp_hdr.wan_udphdr_atm_data +#define wan_udp_ss7_num_frames wan_udp_hdr.wan_udphdr_ss7_num_frames +#define wan_udp_ss7_ismoredata wan_udp_hdr.wan_udphdr_ss7_ismoredata +#define wan_udp_ss7_data wan_udp_hdr.wan_udphdr_ss7_data +#define wan_udp_aft_num_frames wan_udp_hdr.wan_udphdr_aft_num_frames +#define wan_udp_aft_ismoredata wan_udp_hdr.wan_udphdr_aft_ismoredata +#define wan_udp_data wan_udp_hdr.wan_udphdr_data +} wan_udp_pkt_t; + +#endif /* KERNEL */ + +#endif /* __WANPIPE_DEFINES_H */ diff -Nur linux.org/include/linux/wanpipe_dsp_kernel.h linux-2.6.17/include/linux/wanpipe_dsp_kernel.h --- linux.org/include/linux/wanpipe_dsp_kernel.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/wanpipe_dsp_kernel.h 2006-08-30 10:07:15.000000000 +0000 @@ -0,0 +1,225 @@ +/* + * These are the public elements of the Linux DSP module. + */ + +#ifndef _WANPIPE_DSP_KERNEL_H +#define _WANPIPE_DSP_KERNEL_H + +/* + * ****************************************************************** + * INCLUDES * + * ****************************************************************** + */ +#include +#include +#include "wanpipe_x25_kernel.h" + +/* + * ****************************************************************** + * DEFINES/MACROS * + * ****************************************************************** + */ + +/* DSP Messages */ +#define DSP_CALL_REQ_HOST_MSG 0x56 +#define DSP_CALL_REQ_TERM_MSG 0x57 +#define DSP_INV_TO_CLEAR_MSG 0x01 +#define DSP_CMD_RES_UNDELIVERED_MSG 0x10 +#define DSP_CMD_RES_ABORTED_MSG 0x11 +#define DSP_STATUS_MSG 0x12 +#define DSP_ACK_MSG 0x14 +#define DSP_CIRCUIT_ENABLED_MSG 0x20 +#define DSP_CIRCUIT_RESET_MSG 0x21 +#define DSP_CIRCUIT_REQUEST_MSG 0x22 +#define DSP_CIRCUIT_DISCONNECT_MSG 0x24 + +#define DSP_DATA_MSG 0x40 +#define DSP_DATA_ACK_MSG 0x41 + + +#define DSP_FALSE 0 +#define DSP_TRUE 1 + +#define DSP_OK 0 + +/* 'dsp_result' values */ +#define DSP_LINK_DOWN 0x01 +#define DSP_LINK_READY 0x02 +#define DSP_LINK_RESET 0x03 + +/* Options for 'DSP_pad' */ +#define DSP_HPAD 0x00 +#define DSP_TPAD 0x01 + +#define DSP_MAX_DATA 1024 + +#define DSP_CALL_STR_SZ 512 + +#ifndef DSP_PROT +# define DSP_PROT 0x20 +#endif + +/* Control Byte */ +#define DSP_CR_INC_INF_FOR_SE 0x01 /* Further information for session + * establishment is contained in a + * CIRCUIT REQEUST message + */ +#define DSP_SND_MULT_USER_CR 0x02 /* Sends a Multiple User Circuit + * Request message. + */ +#define DSP_TT_SUPPORTS 0x04 /* Request is for a 3270 device that + * supports Transparent Text. + */ +#define DSP_REQ_FOR_ASCII_DEV 0x08 /* Request is for an ASCII device. + */ + +/* Connection Request Mode */ +#define DSP_CRM_TYPE1 0x01 /* Referred to as fixed class */ +#define DSP_CRM_TYPE2 0x02 /* Referred to as specific class */ +#define DSP_CRM_TYPE3 0x03 /* Referred to as non-specific class */ +#define DSP_CRM_TYPE4 0x04 /* Referred to as associated class */ + +/* + * ************* + * Reason Code * + * ************* + */ +/* Reason code for CIRCUIT_RESET */ +#define DSP_RC_RESET 0x00 +#define DSP_RC_DATA_ERROR 0x11 +/* Reason code for INVITATION_TO_CLEAR */ +#define DSP_RC_UNDEFINED 0x00 +#define DSP_RC_USER 0x01 +#define DSP_RC_INVALID_DQ_MSG 0x10 +#define DSP_RC_INVALID_STATE_TRANS 0x11 +#define DSP_RC_INVALID_DQ_FORMAT 0x12 +#define DSP_RC_INVALID_DATA_FORMAT 0x13 +#define DSP_RC_TIMEOUT 0x20 +#define DSP_RC_FACILITY_FAILURE 0x21 + +/* + * ****************************************************************** + * ENUM/TYPEDEF/STRCTURE * + * ****************************************************************** + */ +enum { + SIOC_DSP_PLACE_CALL = (SIOC_ANNEXG_PLACE_CALL), + SIOC_DSP_CLEAR_CALL = (SIOC_ANNEXG_CLEAR_CALL), + SIOC_DSP_API_RESERVED = (SIOC_WANPIPE_DEVPRIVATE), + + SIOC_DSP_GET_CALL_DATA, + SIOC_DSP_SET_CALL_DATA, + + SIOC_DSP_ACCEPT_CALL, + SIOC_DSP_RESET_CALL, + SIOC_DSP_DEBUG, + + SIOC_DSP_INVITATION_TO_CLEAR, + SIOC_DSP_CIRCUIT_ENABLED, + SIOC_DSP_CIRCUIT_RESET, + SIOC_DSP_CIRCUIT_DISCONNECT, + SIOC_DSP_CIRCUIT_REQUEST, + SIOC_DSP_STATUS, + SIOC_DSP_ACK, + SIOC_DSP_CMD_RES_UNDELIVERED, + SIOC_DSP_CMD_RES_ABORTED, + + SIOC_DSP_SEND_DATA, + SIOC_DSP_RECEIVE_DATA, + + SIOC_DSP_SET_PID, + SIOC_DSP_SET_LCN_LABEL +}; + + + +#pragma pack(1) +typedef struct { + unsigned char dsp_pkt_type; /* DSP packet type */ + unsigned char dsp_resp; /* 1 - sending response */ + unsigned char dsp_user_cn; /* user circuit number */ + unsigned short dsp_length; /* Data length */ + unsigned short dsp_lcn; + unsigned char dsp_result; + union { + unsigned char status; /* Status */ + unsigned char pad_type; /* PAD type */ +#if 0 + ALEX 10.4.2001 + ETX_ETB_ESC + unsigned char et_byte; /* ET byte (1-ETX,0-ETB)*/ +#endif + } dspapi_hdr_dspu1; + union { + struct { + unsigned char src_cu_addr; /* Src Ctrl Unit addr */ + unsigned char src_dev_addr; /* Source Device addr */ + unsigned char ctrl_byte; /* control byte */ + unsigned char dev_info; /* Device information */ + unsigned char crm_type; /* Con. Request mode */ + } dspapi_hdr_dsppc1; + unsigned char error_code; /* Sense byte */ + unsigned char reason_code; /* reason code */ + unsigned char transp; /* Transparent data */ + } dspapi_hdr_dspu2; + union { + struct { + unsigned char dst_cu_addr; /* Dst Ctrl Unit addr */ + unsigned char dst_dev_addr; /* Dst Device addr */ + }dspapi_hdr_dsppc2; + unsigned char sn; /* seq. num */ + unsigned char sense; /* Sense byte */ + }dspapi_hdr_dspu3; +}dspapi_hdr_t; + +#define dsp_status dspapi_hdr_dspu1.status +#define dsp_pad_type dspapi_hdr_dspu1.pad_type +#define dsp_et_byte dspapi_hdr_dspu1.et_byte + +#define dsp_src_cu_addr dspapi_hdr_dspu2.dspapi_hdr_dsppc1.src_cu_addr +#define dsp_src_dev_addr dspapi_hdr_dspu2.dspapi_hdr_dsppc1.src_dev_addr +#define dsp_ctrl_byte dspapi_hdr_dspu2.dspapi_hdr_dsppc1.ctrl_byte +#define dsp_dev_info dspapi_hdr_dspu2.dspapi_hdr_dsppc1.dev_info +#define dsp_crm_type dspapi_hdr_dspu2.dspapi_hdr_dsppc1.crm_type +#define dsp_error_code dspapi_hdr_dspu2.error_code +#define dsp_reason_code dspapi_hdr_dspu2.reason_code +#define dsp_data_transp dspapi_hdr_dspu2.transp + +#define dsp_dst_cu_addr dspapi_hdr_dspu3.dspapi_hdr_dsppc2.dst_cu_addr +#define dsp_dst_dev_addr dspapi_hdr_dspu3.dspapi_hdr_dsppc2.dst_dev_addr +#define dsp_sense dspapi_hdr_dspu3.sense +#define dsp_sn dspapi_hdr_dspu3.sn + +typedef struct { + dspapi_hdr_t hdr; + char data[DSP_MAX_DATA]; +}dspapi_t; + +#pragma pack() + + +#ifdef __KERNEL__ + +struct wanpipe_dsp_register_struct{ + unsigned char init; + int (*dsp_bind_api)(struct net_device *master_dev, void *sk_id); +}; + + +/* ---------------------------------------------------------------------------- + * Return codes from interface commands + * --------------------------------------------------------------------------*/ + + +extern int register_wanpipe_dsp_protocol(struct wanpipe_dsp_register_struct*); +extern void unregister_wanpipe_dsp_protocol(void); + +extern int register_x25_dsp_protocol(struct x25_dsp_register_struct*); +extern void unregister_x25_dsp_protocol(void); +extern struct net_device* x25_get_svc_dev(struct net_device* master_dev); +extern int x25_get_call_info(struct net_device* master_dev, unsigned short*, unsigned short*, unsigned short*); + +#endif /* __KERNEL__ */ + +#endif + diff -Nur linux.org/include/linux/wanpipe_ec_kernel.h linux-2.6.17/include/linux/wanpipe_ec_kernel.h --- linux.org/include/linux/wanpipe_ec_kernel.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/wanpipe_ec_kernel.h 2006-08-30 10:07:15.000000000 +0000 @@ -0,0 +1,38 @@ +/****************************************************************************** + * wanpipe_ec_kernel.h + * + * Author: Alex Feldman + * + * Copyright: (c) 1995-2001 Sangoma Technologies Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * ============================================================================ + ****************************************************************************** + */ + +#ifndef __WANPIPE_EC_KERNEL_H +# define __WANPIPE_EC_KERNEL_H + +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) +#elif defined(__LINUX__) +# include +#endif + +typedef struct wanec_iface_ +{ + unsigned long init; + + void* (*reg) (void*, int); + int (*unreg) (void*, void*); + + int (*ioctl) (void); + int (*isr) (void*, void*); + int (*poll) (void*, void*); + int (*event_ctrl) (void*, void*, wan_event_ctrl_t*); + +} wanec_iface_t; + +#endif /* __WANPIPE_EC_KERNEL_H */ diff -Nur linux.org/include/linux/wanpipe_edac_iface.h linux-2.6.17/include/linux/wanpipe_edac_iface.h --- linux.org/include/linux/wanpipe_edac_iface.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/wanpipe_edac_iface.h 2006-08-30 10:07:15.000000000 +0000 @@ -0,0 +1,88 @@ +#ifndef __WANPIPE_EDAC_IFACE_H +#define __WANPIPE_EDAC_IFACE_H + + +#define WAN_TDMV_RX 0 +#define WAN_TDMV_TX 1 + +typedef struct wan_tdmv_pwr{ + unsigned int sum; + unsigned int tap_depth; + unsigned int tap_debug_counter; +}wan_tdmv_pwr_t; + +typedef struct _sample_state_t{ + int state; + int forced_state; +}sample_state_t; +#define SAMPLE_STATE_HISTORY_LEN 3 + +typedef struct wan_tdmv_rxtx_pwr{ + wan_tdmv_pwr_t direction[2]; + /* of type ED_STATE */ + int sample_state[SAMPLE_STATE_HISTORY_LEN]; + //sample_state_t sample_state[SAMPLE_STATE_HISTORY_LEN]; + + unsigned int current_sample_number; + + /* of type ED_STATE */ + int current_state; + + /* see comment in ED code */ + int complete_samples_counter; + + /* debugging stuff */ + unsigned int total_samples_number; + /* current counters */ + unsigned int echo_present_samples_number; + unsigned int echo_absent_samples_number; + /* history counters */ + unsigned int echo_present_samples_number_history; + unsigned int echo_absent_samples_number_history; +}wan_tdmv_rxtx_pwr_t; + + +typedef enum { ECHO_PRESENT, ECHO_ABSENT, INDETERMINATE, DOUBLE_TALK, NOT_USED } ED_STATE; + +typedef enum { ECHO_DETECT_OFF, ECHO_DETECT_ON } ED_CONTROL_STATE; + +typedef struct _echo_detect_struct{ + /* Used for reporting Echo Presence/Absence on a Asterisk CLI request. */ + ED_STATE echo_state; + + /* Controls start/stop of ED algorithm. */ + ED_CONTROL_STATE echo_detection_state; + ED_CONTROL_STATE echo_detection_state_old; + + /* if 1 ED algorithm enabled for the channel */ + int ed_enabled; + + /* debugging stuff */ + int echo_absent_samples_number; + int echo_present_samples_number; + + unsigned int last_rx_power; + unsigned int last_tx_power; + +}echo_detect_struct_t; + +/* +#define TDMV_SAMPLE_STATE_DECODE(state) \ + ((state == ECHO_PRESENT) ? "ECHO_PRESENT" : \ + (state == ECHO_ABSENT) ? "ECHO_ABSENT" : \ + (state == INDETERMINATE) ? "INDETERMINATE" : "Invalid") +*/ +#define TDMV_SAMPLE_STATE_DECODE(state) \ + ((state == ECHO_PRESENT) ? "P" : \ + (state == ECHO_ABSENT) ? "A" : \ + (state == DOUBLE_TALK) ? "D" : \ + (state == INDETERMINATE) ? "I" : "Invalid") + +extern int wp_tdmv_calc_echo (wan_tdmv_rxtx_pwr_t *pwr_rxtx, + int is_mlaw, + int channo, + unsigned char* rxdata, unsigned char *txdata, + int len); +extern void init_ed_state(wan_tdmv_rxtx_pwr_t *pwr_rxtx, int echo_detect_chan); + +#endif diff -Nur linux.org/include/linux/wanpipe_events.h linux-2.6.17/include/linux/wanpipe_events.h --- linux.org/include/linux/wanpipe_events.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/wanpipe_events.h 2006-08-30 10:07:15.000000000 +0000 @@ -0,0 +1,83 @@ +/****************************************************************************** + * wanpipe_events.h + * + * Author: Alex Feldman + * + * Copyright: (c) 1995-2001 Sangoma Technologies Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * ============================================================================ + ****************************************************************************** + */ + +#ifndef __WANPIPE_EVENTS_H__ +# define __WANPIPE_EVENTS_H__ + +/* DTMF event tone type: present or stop */ +#define WAN_EC_TONE_PRESENT 0x01 +#define WAN_EC_TONE_STOP 0x02 +#define WAN_EC_DECODE_TONE_TYPE(type) \ + (type == WAN_EC_TONE_PRESENT) ? "Present" : \ + (type == WAN_EC_TONE_STOP) ? "Stop" : \ + "Unknown" + +/* channel port (sout, rout, sin, rin) */ +#define WAN_EC_CHANNEL_PORT_SOUT 0x01 +#define WAN_EC_CHANNEL_PORT_SIN 0x02 +#define WAN_EC_CHANNEL_PORT_ROUT 0x03 +#define WAN_EC_CHANNEL_PORT_RIN 0x04 + +#define WAN_EVENT_RXHOOK_OFF 0x01 +#define WAN_EVENT_RXHOOK_ON 0x02 + +#define WAN_EVENT_RING_PRESENT 0x01 +#define WAN_EVENT_RING_STOP 0x02 + +#if defined(WAN_KERNEL) + +/* Global Event defines */ +#define WAN_EVENT_ENABLE 0x80000000 +#define WAN_EVENT_DISABLE 0x00000000 +#define WAN_EVENT_MODE_DECODE(type) ((type) & WAN_EVENT_ENABLE) ? "Enable" : "Disable" + +#define WAN_EVENT_EC_DTMF 0x00000001 +#define WAN_EVENT_RM_POWER 0x00000002 +#define WAN_EVENT_RM_LC 0x00000004 +#define WAN_EVENT_RM_RT 0x00000008 +#define WAN_EVENT_RM_DTMF 0x00000010 +#define WAN_EVENT_TE_RBS 0x00000020 +#define WAN_EVENT_TYPE_DECODE(type) \ + ((type) & WAN_EVENT_EC_DTMF) ? "EC DTMF" : \ + ((type) & WAN_EVENT_RM_POWER) ? "RM POWER" : \ + ((type) & WAN_EVENT_RM_LC) ? "RM LC" : \ + ((type) & WAN_EVENT_RM_RT) ? "RM RT" : \ + ((type) & WAN_EVENT_RM_DTMF) ? "RM DTMF" : \ + ((type) & WAN_EVENT_TE_RBS) ? "TE RBS" : "Unknown" + +/* Event information */ +typedef struct wan_event_ { + unsigned long type; + int channel; /* A200-mod_no, T1/E1-fe chan */ + unsigned char digit; /* DTMF: digit */ + unsigned char dtmf_type; /* DTMF: PRESETN/STOP */ + unsigned char dtmf_port; /* DTMF: ROUT/SOUT */ + + unsigned char rxhook; /* LC: OFF-HOOK or ON-HOOK */ + +} wan_event_t; + +/* Event control */ +typedef struct wan_event_ctrl_ { + + int mod_no; /* A200-Remora */ + unsigned long type; + unsigned char ec_dtmf_port; /* EC DTMF: SOUT or ROUT */ + unsigned long ts_map; + +} wan_event_ctrl_t; +#endif /* WAN_KERNEL */ + +#endif /* __WANPIPE_EVENTS_H__ */ diff -Nur linux.org/include/linux/wanpipe_fr_iface.h linux-2.6.17/include/linux/wanpipe_fr_iface.h --- linux.org/include/linux/wanpipe_fr_iface.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/wanpipe_fr_iface.h 2006-08-30 10:07:15.000000000 +0000 @@ -0,0 +1,171 @@ +/*********************************************************** + * wanpipe_fr_iface.h Wanpipe Multi Protocol Interface + * + * + * + * + */ + +#ifndef _WANPIPE_FR_IFACE_H_ +#define _WANPIPE_FR_IFACE_H_ + +#ifdef WANLIP_DRIVER + +#if 0 +typedef struct wp_fr_reg +{ + int (*prot_set_state)(void* link_dev, int state, unsigned char *, int reason); + int (*chan_set_state)(void* chan_dev, int state, unsigned char *, int reason); + int (*tx_down) (void *, void *); + int (*rx_up) (void *, void *, int); + int mtu; +}wp_fr_reg_t; +#endif + +#define wplist_insert_dev(dev, list) do{\ + dev->next = list;\ + list = dev;\ + }while(0) + +#define wplist_remove_dev(dev,cur,prev,list)\ + do{\ + if ((cur=list) == dev){\ + list=cur->next;\ + break;\ + }else{\ + while (cur!=NULL && cur->next!=NULL){\ + prev=cur;\ + cur=cur->next;\ + if (cur==dev){\ + prev->next=cur->next;\ + break;\ + }\ + }\ + }\ + }while(0) + + + +extern void *wp_register_fr_prot(void *link_ptr, + char *devname, + void *cfg, + wplip_prot_reg_t *fr_reg); + +extern int wp_unregister_fr_prot(void *prot_ptr); + +extern void *wp_register_fr_chan(void *if_ptr, + void *prot_ptr, + char *devname, + void *cfg, + unsigned char type); + +extern int wp_unregister_fr_chan(void *chan_ptr); + +extern int wp_fr_open_chan (void *chan_ptr); +extern int wp_fr_close_chan(void *chan_ptr); +extern int wp_fr_ioctl (void *chan_ptr, int cmd, void *arg); + +extern int wp_fr_rx (void * prot_ptr, void *rx_pkt); +extern int wp_fr_timer (void *prot_ptr, unsigned int *period, unsigned int carrier_reliable); +extern int wp_fr_tx (void * chan_ptr, void *skb, int type); +extern int wp_fr_pipemon(void *chan, int cmd, int dlci, unsigned char* data, unsigned int *len); +extern int wp_fr_snmp(void* chan_ptr, void* data); + +#endif + + +/* 'command' field defines */ +#define FR_WRITE 0x01 +#define FR_READ 0x02 +#define FR_ISSUE_IS_FRAME 0x03 +#define FR_SET_CONFIG 0x10 +#define FR_READ_CONFIG 0x11 +#define FR_COMM_DISABLE 0x12 +#define FR_COMM_ENABLE 0x13 +#define FR_READ_STATUS 0x14 +#define FR_READ_STATISTICS 0x15 +#define FR_FLUSH_STATISTICS 0x16 +#define FR_LIST_ACTIVE_DLCI 0x17 +#define FR_FLUSH_DATA_BUFFERS 0x18 +#define FR_READ_ADD_DLC_STATS 0x19 +#define FR_ADD_DLCI 0x20 +#define FR_DELETE_DLCI 0x21 +#define FR_ACTIVATE_DLCI 0x22 +#define FR_DEACTIVATE_DLCI 0x22 +#define FR_READ_MODEM_STATUS 0x30 +#define FR_SET_MODEM_STATUS 0x31 +#define FR_READ_ERROR_STATS 0x32 +#define FR_FLUSH_ERROR_STATS 0x33 +#define FR_READ_DLCI_IB_MAPPING 0x34 +#define FR_READ_CODE_VERSION 0x40 +#define FR_SET_INTR_MODE 0x50 +#define FR_READ_INTR_MODE 0x51 +#define FR_SET_TRACE_CONFIG 0x60 +#define FR_FT1_STATUS_CTRL 0x80 +#define FR_SET_FT1_MODE 0x81 +#define FR_LIST_CONFIGURED_DLCIS 0x82 + + +#pragma pack(1) + +/*---------------------------------------------------------------------------- + * Global Statistics Block. + * This structure is returned by the FR_READ_STATISTICS command when + * dcli == 0. + */ +typedef struct fr_link_stat +{ + unsigned short rx_too_long ; /* 00h: */ + unsigned short rx_dropped ; /* 02h: */ + unsigned short rx_dropped2 ; /* 04h: */ + unsigned short rx_bad_dlci ; /* 06h: */ + unsigned short rx_bad_format ; /* 08h: */ + unsigned short retransmitted ; /* 0Ah: */ + unsigned short cpe_tx_FSE ; /* 0Ch: */ + unsigned short cpe_tx_LIV ; /* 0Eh: */ + unsigned short cpe_rx_FSR ; /* 10h: */ + unsigned short cpe_rx_LIV ; /* 12h: */ + unsigned short node_rx_FSE ; /* 14h: */ + unsigned short node_rx_LIV ; /* 16h: */ + unsigned short node_tx_FSR ; /* 18h: */ + unsigned short node_tx_LIV ; /* 1Ah: */ + unsigned short rx_ISF_err ; /* 1Ch: */ + unsigned short rx_unsolicited ; /* 1Eh: */ + unsigned short rx_SSN_err ; /* 20h: */ + unsigned short rx_RSN_err ; /* 22h: */ + unsigned short T391_timeouts ; /* 24h: */ + unsigned short T392_timeouts ; /* 26h: */ + unsigned short N392_reached ; /* 28h: */ + unsigned short cpe_SSN_RSN ; /* 2Ah: */ + unsigned short current_SSN ; /* 2Ch: */ + unsigned short current_RSN ; /* 2Eh: */ + unsigned short curreny_T391 ; /* 30h: */ + unsigned short current_T392 ; /* 32h: */ + unsigned short current_N392 ; /* 34h: */ + unsigned short current_N393 ; /* 36h: */ +} fr_link_stat_t; + +/*---------------------------------------------------------------------------- + * DLCI statistics. + * This structure is returned by the FR_READ_STATISTICS command when + * dlci != 0. + */ +typedef struct fr_dlci_stat +{ + unsigned int tx_frames ; /* 00h: */ + unsigned int tx_bytes ; /* 04h: */ + unsigned int rx_frames ; /* 08h: */ + unsigned int rx_bytes ; /* 0Ch: */ + unsigned int rx_dropped ; /* 10h: */ + unsigned int rx_inactive ; /* 14h: */ + unsigned int rx_exceed_CIR ; /* 18h: */ + unsigned int rx_DE_set ; /* 1Ch: */ + unsigned int tx_throughput ; /* 20h: */ + unsigned int tx_calc_timer ; /* 24h: */ + unsigned int rx_throughput ; /* 28h: */ + unsigned int rx_calc_timer ; /* 2Ch: */ +} fr_dlci_stat_t; + +#pragma pack() + +#endif diff -Nur linux.org/include/linux/wanpipe.h linux-2.6.17/include/linux/wanpipe.h --- linux.org/include/linux/wanpipe.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/wanpipe.h 2006-08-30 10:07:15.000000000 +0000 @@ -0,0 +1,988 @@ +/***************************************************************************** +* wanpipe.h WANPIPE(tm) Multiprotocol WAN Link Driver. +* User-level API definitions. +* +* Author: Nenad Corbic +* Alex Feldman +* Gideon Hack +* +* Copyright: (c) 1995-2000 Sangoma Technologies Inc. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version +* 2 of the License, or (at your option) any later version. +* ============================================================================ +* Nov 3, 2000 Nenad Corbic Added config_id to sdla_t structure. +* Used to determine the protocol running. +* Jul 13, 2000 Nenad Corbic Added SyncPPP Support +* Feb 24, 2000 Nenad Corbic Added support for x25api driver +* Oct 04, 1999 Nenad Corbic New CHDLC and FRAME RELAY code, SMP support +* Jun 02, 1999 Gideon Hack Added 'update_call_count' for Cisco HDLC +* support +* Jun 26, 1998 David Fong Added 'ip_mode' in sdla_t.u.p for dynamic IP +* routing mode configuration +* Jun 12, 1998 David Fong Added Cisco HDLC union member in sdla_t +* Dec 08, 1997 Jaspreet Singh Added 'authenticator' in union of 'sdla_t' +* Nov 26, 1997 Jaspreet Singh Added 'load_sharing' structure. Also added +* 'devs_struct','dev_to_devtint_next' to 'sdla_t' +* Nov 24, 1997 Jaspreet Singh Added 'irq_dis_if_send_count', +* 'irq_dis_poll_count' to 'sdla_t'. +* Nov 06, 1997 Jaspreet Singh Added a define called 'INTR_TEST_MODE' +* Oct 20, 1997 Jaspreet Singh Added 'buff_intr_mode_unbusy' and +* 'dlci_intr_mode_unbusy' to 'sdla_t' +* Oct 18, 1997 Jaspreet Singh Added structure to maintain global driver +* statistics. +* Jan 15, 1997 Gene Kozin Version 3.1.0 +* o added UDP management stuff +* Jan 02, 1997 Gene Kozin Version 3.0.0 +*****************************************************************************/ +#ifndef _WANPIPE_H +#define _WANPIPE_H + +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) +#include +#include +#include +# include +#elif defined(__LINUX__) || defined (__KERNEL__) +#include +#include +#include +# include +#else +# error "No OS Specified" +#endif + +/* Due to changes between 2.4.9 and 2.4.13, + * I decided to write my own min() and max() + * functions */ + +#define wp_min(x,y) \ + ({ unsigned int __x = (x); unsigned int __y = (y); __x < __y ? __x: __y; }) +#define wp_max(x,y) \ + ({ unsigned int __x = (x); unsigned int __y = (y); __x > __y ? __x: __y; }) + + +#if defined(__LINUX__) || defined (__KERNEL__) +# if defined(LINUX_2_4)||defined(LINUX_2_6) +# ifndef AF_WANPIPE +# define AF_WANPIPE 25 +# ifndef PF_WANPIPE +# define PF_WANPIPE AF_WANPIPE +# endif +# endif +# else +# ifndef AF_WANPIPE +# define AF_WANPIPE 24 +# ifndef PF_WANPIPE +# define PF_WANPIPE AF_WANPIPE +# endif +# endif +# endif +# define AF_ANNEXG_WANPIPE AF_WANPIPE +# define PF_ANNEXG_WANPIPE AF_ANNEXG_WANPIPE +#endif + +/* Defines */ + +#ifndef PACKED +#define PACKED __attribute__((packed)) +#endif + +#define WANPIPE_MAGIC 0x414C4453L /* signature: 'SDLA' reversed */ + +/* IOCTL numbers (up to 16) */ +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) +# define WANPIPE_DUMP _IOW(ROUTER_IOCTL, 16, wan_conf_t) +# define WANPIPE_EXEC _IOWR(ROUTER_IOCTL, 17, wan_conf_t) +#elif defined(__LINUX__) +# define WANPIPE_DUMP (ROUTER_USER+0) /* dump adapter's memory */ +# define WANPIPE_EXEC (ROUTER_USER+1) /* execute firmware command */ +#endif + +#if 0 +#define WAN_HWCALL(func, (x)) \ + if (card->hw_iface.##func){ \ + card->hw_iface.##func(x); \ + } +#endif + +#define TRACE_ALL 0x00 +#define TRACE_PROT 0x01 +#define TRACE_DATA 0x02 + +/* values for request/reply byte */ +#define UDPMGMT_REQUEST 0x01 +#define UDPMGMT_REPLY 0x02 +#define UDP_OFFSET 12 + +#define MAX_CMD_BUFF 10 +#define MAX_X25_LCN 255 /* Maximum number of x25 channels */ +#define MAX_LCN_NUM 4095 /* Maximum lcn number */ +#define MAX_FT1_RETRY 100 + +#define TX_TIMEOUT 5*HZ + + +/* General Critical Flags */ +enum { + SEND_CRIT, + PERI_CRIT, + RX_CRIT, + PRIV_CRIT +}; + +/* TE timer critical flags */ +/* #define LINELB_TIMER_RUNNING 0x04 - define in sdla_te1_pmc.h */ + +/* Bit maps for dynamic interface configuration + * DYN_OPT_ON : turns this option on/off + * DEV_DOWN : device was shutdown by the driver not + * by user + */ +#define DYN_OPT_ON 0x00 +#define DEV_DOWN 0x01 +#define WAN_DEV_READY 0x02 + +/* + * Data structures for IOCTL calls. + */ + +typedef struct sdla_dump /* WANPIPE_DUMP */ +{ + unsigned long magic; /* for verification */ + unsigned long offset; /* absolute adapter memory address */ + unsigned long length; /* block length */ + void* ptr; /* -> buffer */ +} sdla_dump_t; + +typedef struct sdla_exec /* WANPIPE_EXEC */ +{ + unsigned long magic; /* for verification */ + void* cmd; /* -> command structure */ + void* data; /* -> data buffer */ +} sdla_exec_t; + +typedef struct wan_procfs +{ + unsigned long magic; /* for verification */ + int cmd; + unsigned long max_len; + unsigned long offs; + int is_more; + void* data; +} wan_procfs_t; + +/* UDP management stuff */ +typedef struct wum_header +{ + unsigned char signature[8]; /* 00h: signature */ + unsigned char type; /* 08h: request/reply */ + unsigned char command; /* 09h: commnand */ + unsigned char reserved[6]; /* 0Ah: reserved */ +} wum_header_t; + +/************************************************************************* + Data Structure for global statistics +*************************************************************************/ + +typedef struct global_stats +{ + unsigned long isr_entry; + unsigned long isr_already_critical; + unsigned long isr_rx; + unsigned long isr_tx; + unsigned long isr_intr_test; + unsigned long isr_spurious; + unsigned long isr_enable_tx_int; + unsigned long rx_intr_corrupt_rx_bfr; + unsigned long rx_intr_on_orphaned_DLCI; + unsigned long rx_intr_dev_not_started; + unsigned long tx_intr_dev_not_started; + unsigned long poll_entry; + unsigned long poll_already_critical; + unsigned long poll_processed; + unsigned long poll_tbusy_bad_status; + unsigned long poll_host_disable_irq; + unsigned long poll_host_enable_irq; + +} global_stats_t; + +/************************************************************************* + Data Structure for if_send statistics +*************************************************************************/ +typedef struct if_send_stat{ + unsigned long if_send_entry; + unsigned long if_send_skb_null; + unsigned long if_send_broadcast; + unsigned long if_send_multicast; + unsigned long if_send_critical_ISR; + unsigned long if_send_critical_non_ISR; + unsigned long if_send_tbusy; + unsigned long if_send_tbusy_timeout; + unsigned long if_send_PIPE_request; + unsigned long if_send_wan_disconnected; + unsigned long if_send_dlci_disconnected; + unsigned long if_send_no_bfrs; + unsigned long if_send_adptr_bfrs_full; + unsigned long if_send_bfr_passed_to_adptr; + unsigned long if_send_protocol_error; + unsigned long if_send_bfr_not_passed_to_adptr; + unsigned long if_send_tx_int_enabled; + unsigned long if_send_consec_send_fail; +} if_send_stat_t; + +typedef struct rx_intr_stat{ + unsigned long rx_intr_no_socket; + unsigned long rx_intr_dev_not_started; + unsigned long rx_intr_PIPE_request; + unsigned long rx_intr_bfr_not_passed_to_stack; + unsigned long rx_intr_bfr_passed_to_stack; +} rx_intr_stat_t; + +typedef struct pipe_mgmt_stat{ + unsigned long UDP_PIPE_mgmt_kmalloc_err; + unsigned long UDP_PIPE_mgmt_direction_err; + unsigned long UDP_PIPE_mgmt_adptr_type_err; + unsigned long UDP_PIPE_mgmt_adptr_cmnd_OK; + unsigned long UDP_PIPE_mgmt_adptr_cmnd_timeout; + unsigned long UDP_PIPE_mgmt_adptr_send_passed; + unsigned long UDP_PIPE_mgmt_adptr_send_failed; + unsigned long UDP_PIPE_mgmt_not_passed_to_stack; + unsigned long UDP_PIPE_mgmt_passed_to_stack; + unsigned long UDP_PIPE_mgmt_no_socket; + unsigned long UDP_PIPE_mgmt_passed_to_adptr; +} pipe_mgmt_stat_t; + + +typedef struct { + struct sk_buff *skb; +} bh_data_t, cmd_data_t; + +#define MAX_LGTH_UDP_MGNT_PKT WAN_MAX_DATA_SIZE + + +/* This is used for interrupt testing */ +#define INTR_TEST_MODE 0x02 + +#define WUM_SIGNATURE_L 0x50495046 +#define WUM_SIGNATURE_H 0x444E3845 + +#define WUM_KILL 0x50 +#define WUM_EXEC 0x51 + + + +#if defined(WAN_KERNEL) +/****** Kernel Interface ****************************************************/ + +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) +# include /* WANPIPE Debugging messages */ +# include +# include +# include +# include +#elif defined(__LINUX__) +# include +# ifndef KERNEL_VERSION +# define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) +# endif +# include +# include /* SDLA firmware module definitions */ +# include /* SDLA support module API definitions */ + +# if defined(LINUX_2_6) +# include +# elif defined(LINUX_2_4) +# include +# endif + +# include +# if defined(LINUX_2_4) || defined(LINUX_2_6) +# include +# include +# include +# include +# endif +# include +# include +# include +#endif + +#define MAX_E1_CHANNELS 32 +#define MAX_FR_CHANNELS (1007+1) + +#define WAN_ENABLE 0x01 +#define WAN_DISABLE 0x02 + +#ifndef min +#define min(a,b) (((a)<(b))?(a):(b)) +#endif +#ifndef max +#define max(a,b) (((a)>(b))?(a):(b)) +#endif + +#define is_digit(ch) (((ch)>=(unsigned)'0'&&(ch)<=(unsigned)'9')?1:0) +#define is_alpha(ch) ((((ch)>=(unsigned)'a'&&(ch)<=(unsigned)'z')||\ + ((ch)>=(unsigned)'A'&&(ch)<=(unsigned)'Z'))?1:0) +#define is_hex_digit(ch) ((((ch)>=(unsigned)'0'&&(ch)<=(unsigned)'9')||\ + ((ch)>=(unsigned)'a'&&(ch)<=(unsigned)'f')||\ + ((ch)>=(unsigned)'A'&&(ch)<=(unsigned)'F'))?1:0) + + +/****** Data Structures *****************************************************/ + +#if defined(__LINUX__) +typedef struct +{ /****** X.25 specific data **********/ + netdevice_t *svc_to_dev_map[MAX_X25_LCN]; + netdevice_t *pvc_to_dev_map[MAX_X25_LCN]; + netdevice_t *tx_dev; + netdevice_t *cmd_dev; + u32 no_dev; + unsigned long hdlc_buf_status_off; + atomic_t tx_interrupts_pending; + + /* FIXME: Move this out of the union */ + u16 timer_int_enabled; + netdevice_t *poll_device; + atomic_t command_busy; + + u32 udp_type; + u8 udp_pkt_src; + u32 udp_lcn; + netdevice_t * udp_dev; + wan_udp_pkt_t udp_pkt_data; + atomic_t udp_pkt_len; + + u8 LAPB_hdlc; /* Option to turn off X25 and run only LAPB */ + u8 logging; /* Option to log call messages */ + u8 oob_on_modem; /* Option to send modem status to the api */ + u16 num_of_ch; /* Number of channels configured by the user */ + struct tq_struct x25_poll_task; + struct timer_list x25_timer; + /* Proc fs */ + wan_x25_conf_t x25_adm_conf; + wan_x25_conf_t x25_conf; + atomic_t tx_interrupt_cmd; + struct sk_buff_head trace_queue; + unsigned long trace_timeout; + unsigned short trace_lost_cnt; + + unsigned long card_ready; +} sdla_x25_t; +#endif + +typedef struct +{ /****** frame relay specific data ***/ + unsigned long rxmb_base_off; /* -> first Rx buffer */ + unsigned long rxmb_last_off; /* -> last Rx buffer */ + unsigned long rx_base_off; /* S508 receive buffer base */ + unsigned long rx_top_off; /* S508 receive buffer end */ + unsigned short node_dlci[100]; + unsigned short dlci_num; + netdevice_t* dlci_to_dev_map[MAX_FR_CHANNELS]; + atomic_t tx_interrupts_pending; + + /* FIXME: Move this out of the union */ + unsigned short timer_int_enabled; + + int udp_type; + char udp_pkt_src; + unsigned udp_dlci; + wan_udp_pkt_t udp_pkt_data; + atomic_t udp_pkt_len; + void* trc_el_base; /* first trace element */ + void* trc_el_last; /* last trace element */ + void* curr_trc_el; /* current trace element */ + unsigned short trc_bfr_space; /* trace buffer space */ + netdevice_t* arp_dev; +#if defined(__LINUX__) + spinlock_t if_send_lock; +#endif + unsigned char issue_fs_on_startup; + /* Proc fs */ + unsigned short t391; + unsigned short t392; + unsigned short n391; + unsigned short n392; + unsigned short n393; + void* update_dlci; + unsigned char auto_dlci_cfg; +} sdla_fr_t; + +typedef struct +{ /****** PPP-specific data ***********/ + char if_name[WAN_IFNAME_SZ+1]; /* interface name */ + unsigned long txbuf_off; /* -> current Tx buffer */ + unsigned long txbuf_base_off; /* -> first Tx buffer */ + unsigned long txbuf_last_off; /* -> last Tx buffer */ + unsigned long txbuf_next_off; /* Next Tx buffer to use */ + unsigned long rxbuf_base_off; /* -> first Rx buffer */ + unsigned long rxbuf_last_off; /* -> last Rx buffer */ + unsigned long rx_base_off; /* S508 receive buffer base */ + unsigned long rx_top_off; /* S508 receive buffer end */ + unsigned long rxbuf_next_off; /* Next Rx buffer to use */ + char ip_mode; /* STATIC/HOST/PEER IP Mode */ + char authenticator; /* Authenticator for PAP/CHAP */ + /* FIXME: Move this out of the union */ + unsigned char comm_enabled; /* Is comm enabled or not */ + unsigned char peer_route; /* Process Peer Route */ +} sdla_ppp_t; + +typedef struct +{ /* Cisco HDLC-specific data */ + char if_name[WAN_IFNAME_SZ+1]; /* interface name */ + int comm_port;/* Communication Port O or 1 */ + unsigned char usedby; /* Used by WANPIPE or API */ + unsigned long rxmb_off; /* Receive mail box */ + /*unsigned long flags_off;*/ /* flags */ + unsigned long txbuf_off; /* -> current Tx buffer */ + unsigned long txbuf_base_off; /* -> first Tx buffer */ + unsigned long txbuf_last_off; /* -> last Tx buffer */ + unsigned long rxbuf_base_off; /* -> first Rx buffer */ + unsigned long rxbuf_last_off; /* -> last Rx buffer */ + unsigned long rx_base_off; /* S508 receive buffer base */ + unsigned long rx_top_off; /* S508 receive buffer end */ + void* tx_status; /* Tx status element */ + void* rx_status; /* Rx status element */ + unsigned char receive_only; /* high speed receivers */ + unsigned short protocol_options; + unsigned short kpalv_tx; /* Tx kpalv timer */ + unsigned short kpalv_rx; /* Rx kpalv timer */ + unsigned short kpalv_err; /* Error tolerance */ + unsigned short slarp_timer; /* SLARP req timer */ + unsigned state; /* state of the link */ + unsigned char api_status; + unsigned char update_call_count; + unsigned short api_options; /* for async config */ + unsigned char async_mode; + unsigned short tx_bits_per_char; + unsigned short rx_bits_per_char; + unsigned short stop_bits; + unsigned short parity; + unsigned short break_timer; + unsigned short inter_char_timer; + unsigned short rx_complete_length; + unsigned short xon_char; + unsigned short xoff_char; + /* FIXME: Move this out of the union */ + unsigned char comm_enabled; /* Is comm enabled or not */ + /* FIXME: Move this out of the union */ + unsigned char backup; + int TracingEnabled; /* For enabling Tracing */ + unsigned long curr_trace_addr; /* Used for Tracing */ + unsigned long start_trace_addr; + unsigned long end_trace_addr; + unsigned long base_addr_trace_buffer; + unsigned long end_addr_trace_buffer; + unsigned short number_trace_elements; + unsigned available_buffer_space; + unsigned long router_start_time; + unsigned char route_status; + unsigned char route_removed; + unsigned long tick_counter; + /* FIXME: Move this out of the union */ + unsigned short timer_int_enabled; + unsigned long router_up_time; +#if defined(__LINUX__) + spinlock_t if_send_lock; +#endif + void * prot; +} sdla_chdlc_t; + +typedef struct +{ + void* tx_status; /* Tx status element */ + void* rx_status; /* Rx status element */ + void* trace_status; /* Trace status element */ + void* txbuf; /* -> current Tx buffer */ + void* txbuf_base; /* -> first Tx buffer */ + void* txbuf_last; /* -> last Tx buffer */ + void* rxbuf_base; /* -> first Rx buffer */ + void* rxbuf_last; /* -> last Rx buffer */ + void* tracebuf; /* -> current Trace buffer */ + void* tracebuf_base; /* -> current Trace buffer */ + void* tracebuf_last; /* -> current Trace buffer */ + unsigned rx_base; /* receive buffer base */ + unsigned rx_end; /* receive buffer end */ + unsigned trace_base; /* trace buffer base */ + unsigned trace_end; /* trace buffer end */ +} sdla_hdlc_t; + +#if defined(__LINUX__) +typedef struct +{ + char if_name[WAN_IFNAME_SZ+1]; /* interface name */ + int comm_port;/* Communication Port O or 1 */ + unsigned char usedby; /* Used by WANPIPE or API */ + unsigned long rxmb_off; /* Receive mail box */ + /* unsigned long flags_off; */ /* flags */ + unsigned long txbuf_off; /* -> current Tx buffer */ + unsigned long txbuf_base_off; /* -> first Tx buffer */ + unsigned long txbuf_last_off; /* -> last Tx buffer */ + unsigned long rxbuf_base_off; /* -> first Rx buffer */ + unsigned long rxbuf_last_off; /* -> last Rx buffer */ + unsigned long rx_base_off; /* S508 receive buffer base */ + unsigned long rx_top_off; /* S508 receive buffer end */ + void* tx_status; /* FIXME: Not used Tx status element */ + void* rx_status; /* FIXME: Not used Rx status element */ + unsigned short protocol_options; + unsigned state; /* state of the link */ + unsigned char api_status; + unsigned char update_call_count; + unsigned short api_options; /* for async config */ + unsigned short tx_bits_per_char; + unsigned short rx_bits_per_char; + unsigned short stop_bits; + unsigned short parity; + + unsigned long tq_working; + void *time_slot_map[MAX_E1_CHANNELS]; + struct tasklet_struct wanpipe_rx_task; + struct tasklet_struct wanpipe_tx_task; + unsigned char time_slots; + unsigned char tx_scratch_buf[MAX_E1_CHANNELS*50]; + unsigned short tx_scratch_buf_len; + atomic_t tx_interrupts; + unsigned short tx_chan_multiple; + unsigned int wait_for_buffers; + struct sdla *sw_card; + struct sk_buff_head rx_isr_queue; + struct sk_buff_head rx_isr_free_queue; + + /* FIXME: Move this out of the union */ + unsigned short timer_int_enabled; + unsigned long tx_idle_off; + unsigned long rx_discard_off; + + wan_bitstrm_conf_t cfg; + + unsigned char rbs_sig[32]; + unsigned char serial; + +} sdla_bitstrm_t; +#endif + +typedef struct +{ + char if_name[WAN_IFNAME_SZ+1]; /* interface name */ + int comm_port;/* Communication Port O or 1 */ + unsigned char usedby; /* Used by WANPIPE or API */ + unsigned char state; + /* unsigned long flags_off; */ /* flags */ + unsigned long rxmb_off; /* Receive mail box */ + unsigned long txbuf_off; /* -> current Tx buffer */ + unsigned long txbuf_base_off; /* -> first Tx buffer */ + unsigned long txbuf_last_off; /* -> last Tx buffer */ + unsigned long rxbuf_base_off; /* -> first Rx buffer */ + unsigned long rxbuf_last_off; /* -> last Rx buffer */ + unsigned long rx_base_off; /* S508 receive buffer base */ + unsigned long rx_top_off; /* S508 receive buffer end */ + void* tx_status; /* Tx status element */ + void* rx_status; /* Rx status element */ + + unsigned int line_cfg_opt; + unsigned int modem_cfg_opt; + unsigned int modem_status_timer; + unsigned int api_options; + unsigned int protocol_options; + unsigned int protocol_specification; + unsigned int stats_history_options; + unsigned int max_length_msu_sif; + unsigned int max_unacked_tx_msus; + unsigned int link_inactivity_timer; + unsigned int t1_timer; + unsigned int t2_timer; + unsigned int t3_timer; + unsigned int t4_timer_emergency; + unsigned int t4_timer_normal; + unsigned int t5_timer; + unsigned int t6_timer; + unsigned int t7_timer; + unsigned int t8_timer; + unsigned int n1; + unsigned int n2; + unsigned int tin; + unsigned int tie; + unsigned int suerm_error_threshold; + unsigned int suerm_number_octets; + unsigned int suerm_number_sus; + unsigned int sie_interval_timer; + unsigned int sio_interval_timer; + unsigned int sios_interval_timer; + unsigned int fisu_interval_timer; +} sdla_ss7_t; + +typedef struct +{ + char if_name[WAN_IFNAME_SZ+1]; /* interface name */ + int comm_port;/* Communication Port O or 1 */ + unsigned char usedby; /* Used by WANPIPE or API */ + unsigned char state; + /*FIXME: Move this out of the union */ + unsigned char comm_enabled; +} sdla_sdlc_t; + +typedef struct +{ + void *adapter; + unsigned char EncapMode; +} sdla_adsl_t; + +#if defined(__LINUX__) +typedef struct +{ + unsigned long rxmb_off; /* Receive mail box */ + /* unsigned long flags_off; */ /* flags */ + unsigned long txbuf_off; /* -> current Tx buffer */ + unsigned long txbuf_base_off; /* -> first Tx buffer */ + unsigned long txbuf_last_off; /* -> last Tx buffer */ + unsigned long rxbuf_base_off; /* -> first Rx buffer */ + unsigned long rxbuf_last_off; /* -> last Rx buffer */ + unsigned long rx_base_off; /* S508 receive buffer base */ + void* tx_status; /* Tx status element */ + void* rx_status; /* Rx status element */ + wan_tasklet_t wanpipe_rx_task; + struct sk_buff_head wp_rx_free_list; + struct sk_buff_head wp_rx_used_list; + struct sk_buff_head wp_rx_data_list; + struct sk_buff_head wp_tx_prot_list; + unsigned char state; + wan_timer_t atm_timer; + void *tx_dev; + void *trace_info; + void *atm_device; + wan_atm_conf_t atm_cfg; +} sdla_atm_t; +#endif + +#if defined(__LINUX__) +typedef struct +{ + void* rxmb; /* Receive mail box */ + void* flags; /* flags */ + void* tx_status; /* Tx status element */ + void* rx_status; /* Rx status element */ + void* txbuf; /* -> current Tx buffer */ + void* txbuf_base; /* -> first Tx buffer */ + void* txbuf_last; /* -> last Tx buffer */ + void* rxbuf_base; /* -> first Rx buffer */ + void* rxbuf_last; /* -> last Rx buffer */ + unsigned rx_base; /* S508 receive buffer base */ + wan_tasklet_t wanpipe_rx_task; + struct sk_buff_head wp_rx_free_list; + struct sk_buff_head wp_rx_used_list; + unsigned char state; +} sdla_pos_t; +#endif + +typedef struct +{ + unsigned long time_slot_map; + unsigned long logic_ch_map; + unsigned char num_of_time_slots; + unsigned char top_logic_ch; + unsigned long bar; + void *trace_info; + void *dev_to_ch_map[MAX_E1_CHANNELS]; + void *rx_dma_ptr; + void *tx_dma_ptr; + wan_xilinx_conf_t cfg; + unsigned long dma_mtu_off; + unsigned short dma_mtu; + unsigned char state_change_exit_isr; + unsigned long active_ch_map; + unsigned long fifo_addr_map; + wan_timer_t led_timer; + unsigned char tdmv_sync; + unsigned int chip_cfg_status; + wan_taskq_t port_task; + unsigned int port_task_cmd; + unsigned long wdt_rx_cnt; + unsigned long wdt_tx_cnt; + unsigned int security_id; + unsigned int security_cnt; + unsigned char firm_ver; + unsigned int chip_security_cnt; + unsigned long rx_timeout,gtimeout; + unsigned int comm_enabled; + unsigned int lcfg_reg; + unsigned int tdmv_master_if_up; + unsigned int tdmv_mtu; + unsigned int tdmv_zaptel_cfg; + netskb_t *tdmv_api_rx; + netskb_t *tdmv_api_tx; + wan_skb_queue_t tdmv_api_tx_list; + + unsigned int tdmv_dchan_cfg_on_master; + unsigned int tdmv_chan; + unsigned int tdmv_dchan_active_ch; + void *tdmv_chan_ptr; + + unsigned char led_ctrl; +} sdla_xilinx_t; + +typedef struct +{ + unsigned long current_offset; + unsigned long total_len; + unsigned long total_num; + unsigned long status; +} sdla_debug_t; + +/* Adapter Data Space. + * This structure is needed because we handle multiple cards, otherwise + * static data would do it. + */ +typedef struct sdla +{ + char devname[WAN_DRVNAME_SZ+1]; /* card name */ + void* hw; /* hardware configuration */ + wan_device_t wandev; /* WAN device data space */ + + unsigned open_cnt; /* number of open interfaces */ + unsigned long state_tick; /* link state timestamp */ + unsigned intr_mode; /* Type of Interrupt Mode */ + unsigned long in_isr; /* interrupt-in-service flag */ + char buff_int_mode_unbusy; /* flag for carrying out dev_tint */ + char dlci_int_mode_unbusy; /* flag for carrying out dev_tint */ + unsigned long configured; /* flag for previous configurations */ + + unsigned short irq_dis_if_send_count; /* Disabling irqs in if_send*/ + unsigned short irq_dis_poll_count; /* Disabling irqs in poll routine*/ + unsigned short force_enable_irq; + char TracingEnabled; /* flag for enabling trace */ + global_stats_t statistics; /* global statistics */ + unsigned long mbox_off; /* -> mailbox offset */ + wan_mbox_t wan_mbox; /* mailbox structure */ + unsigned long rxmb_off; /* -> receive mailbox */ + wan_mbox_t wan_rxmb; /* rx mailbox structure */ + unsigned long flags_off; /* -> adapter status flags */ + unsigned long fe_status_off; /* FE status structure offset */ +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) + unsigned char rx_data[MAX_PACKET_SIZE]; /* Rx buffer */ + unsigned int rx_len; /* Rx data len */ + unsigned char tx_data[MAX_PACKET_SIZE]; /* Tx buffer */ + unsigned int tx_len; /* Tx data len */ +#endif + void (*isr)(struct sdla* card); /* interrupt service routine */ + void (*poll)(struct sdla* card); /* polling routine */ + int (*exec)(struct sdla* card, void* u_cmd, void* u_data); + /* Used by the listen() system call */ +#if defined(__LINUX__) + /* Wanpipe Socket Interface */ + int (*func) (netskb_t*, struct sock *); + struct sock *sk; +#endif + + /* Shutdown function */ + void (*disable_comm) (struct sdla *card); + + /* Secondary Port Device: Piggibacking */ + struct sdla *next; + struct sdla *list; + +#if defined(__LINUX__) + /* TTY driver variables */ + unsigned char tty_opt; + struct tty_struct *tty; + unsigned int tty_minor; + unsigned int tty_open; + unsigned char *tty_buf; + struct sk_buff_head tty_rx_empty; + struct sk_buff_head tty_rx_full; + struct tq_struct tty_task_queue; +#endif + union + { +#if defined(__LINUX__) + sdla_x25_t x; + sdla_bitstrm_t b; + sdla_atm_t atm; + sdla_pos_t pos; +#endif + sdla_fr_t f; + sdla_ppp_t p; + sdla_chdlc_t c; + sdla_hdlc_t h; + sdla_ss7_t s; + sdla_sdlc_t sdlc; + sdla_adsl_t adsl; + sdla_xilinx_t aft; + sdla_debug_t debug; + } u; + unsigned char irq_equalize; + + /*????????????????*/ + /*Should be in wandev */ + unsigned int type; /* card type */ + unsigned int adptr_type; /* adapter type */ + unsigned char adptr_subtype; /* adapter subtype */ + wan_tasklet_t debug_task; + wan_timer_t debug_timer; + unsigned long debug_running; + unsigned char wan_debugging_state; /* WAN debugging state */ + int wan_debug_last_msg; /* Last WAN debug message */ + int (*wan_debugging)(struct sdla*);/* link debugging routine */ + unsigned long (*get_crc_frames)(struct sdla*);/* get no of CRC frames */ + unsigned long (*get_abort_frames)(struct sdla*);/* get no of Abort frames */ + unsigned long (*get_tx_underun_frames)(struct sdla*);/* get no of TX underun frames */ + unsigned short timer_int_enabled; + unsigned char backup; + unsigned long comm_enabled; + unsigned long update_comms_stats; + + sdla_fe_t fe; /* front end structures */ + + unsigned int rCount; + + /* Wanpipe Socket Interface */ + int (*get_snmp_data)(struct sdla*, netdevice_t*, void*); + + unsigned long intr_perm_off; + unsigned long intr_type_off; + + /* Hardware interface function pointers */ + sdlahw_iface_t hw_iface; + + int (*bind_api_to_svc)(struct sdla*, void *sk_id); + + unsigned long spurious; + + unsigned long intcount; + +#if defined(CONFIG_PRODUCT_WANPIPE_TDM_VOICE) + wan_tdmv_iface_t tdmv_iface; + wan_tdmv_t wan_tdmv; +#endif + +#if defined(CONFIG_PRODUCT_WANPIPE_GENERIC) + struct sdla* same_card; +#endif + + +#if defined(__FreeBSD__) +# if defined(NETGRAPH) + int running; /* something is attached so we are running */ + /* ---netgraph bits --- */ + int datahooks; /* number of data hooks attached */ + node_p node; /* netgraph node */ + hook_p hook; /* data hook */ + hook_p debug_hook; +# if defined(ALTQ) + struct ifaltq xmitq_hipri; /* hi-priority transmit queue */ + struct ifaltq xmitq; /* transmit queue */ +# else + struct ifqueue xmitq_hipri; /* hi-priority transmit queue */ + struct ifqueue xmitq; /* transmit queue */ +# endif + int flags; /* state */ +# define WAN_RUNNING 0x01 /* board is active */ +# define WAN_OACTIVE 0x02 /* output is active */ + int out_dog; /* watchdog cycles output count-down */ +# if ( __FreeBSD__ >= 3 ) + struct callout_handle handle; /* timeout(9) handle */ +# endif + u_long lastinbytes, lastoutbytes; /* a second ago */ + u_long inrate, outrate; /* highest rate seen */ + u_long inlast; /* last input N secs ago */ + u_long out_deficit; /* output since last input */ + void (*wan_down)(struct sdla*); + int (*wan_up)(struct sdla*); + void (*wan_start)(struct sdla*); +# endif /* NETGRAPH */ + /* per card statistics */ + u_long inbytes, outbytes; /* stats */ + u_long oerrors, ierrors; + u_long opackets, ipackets; +#endif /* __FreeBSD__ */ +} sdla_t; + +/****** Public Functions ****************************************************/ + +void wanpipe_open (sdla_t* card); /* wpmain.c */ +void wanpipe_close (sdla_t* card); /* wpmain.c */ + +int wpx_init (sdla_t* card, wandev_conf_t* conf); /* wpx.c */ +int wpf_init (sdla_t* card, wandev_conf_t* conf); /* wpf.c */ +int wpp_init (sdla_t* card, wandev_conf_t* conf); /* wpp.c */ +int wpc_init (sdla_t* card, wandev_conf_t* conf); /* Cisco HDLC */ +int wp_asyhdlc_init (sdla_t* card, wandev_conf_t* conf); /* Async HDLC */ +int wpbsc_init (sdla_t* card, wandev_conf_t* conf); /* BSC streaming */ +int wph_init(sdla_t* card, wandev_conf_t* conf); /* HDLC support */ +int wpft1_init (sdla_t* card, wandev_conf_t* conf); /* FT1 Config support */ +int wp_mprot_init(sdla_t* card, wandev_conf_t* conf); /* Sync PPP on top of RAW CHDLC */ +int wpbit_init (sdla_t* card, wandev_conf_t* conf); /* Bit Stream driver */ +int wpedu_init(sdla_t* card, wandev_conf_t* conf); /* Educational driver */ +int wpss7_init(sdla_t* card, wandev_conf_t* conf); /* SS7 driver */ +int wp_bscstrm_init(sdla_t* card, wandev_conf_t* conf); /* BiSync Streaming Nasdaq */ +int wp_hdlc_fr_init(sdla_t* card, wandev_conf_t* conf); /* Frame Relay over HDLC RAW Streaming */ +int wp_adsl_init(sdla_t* card, wandev_conf_t* conf); /* ADSL Driver */ +int wp_sdlc_init(sdla_t* card, wandev_conf_t* conf); /* SDLC Driver */ +int wp_atm_init(sdla_t* card, wandev_conf_t* conf); /* ATM Driver */ +int wp_pos_init(sdla_t* card, wandev_conf_t* conf); /* POS Driver */ +int wp_xilinx_init(sdla_t* card, wandev_conf_t* conf); /* Xilinx Hardware Support */ +int wp_aft_te1_init(sdla_t* card, wandev_conf_t* conf); /* Xilinx Hardware Support */ +int wp_aft_analog_init(sdla_t* card, wandev_conf_t* conf); /* Xilinx Hardware Support */ +int wp_adccp_init(sdla_t* card, wandev_conf_t* conf); +int wp_xilinx_if_init(sdla_t* card, netdevice_t* dev); +int wp_aft_te3_init(sdla_t* card, wandev_conf_t* conf); /* AFT TE3 Hardware Support */ +int wp_aft_te1_ss7_init(sdla_t* card, wandev_conf_t* conf); /* AFT TE1 SS7 Hardware Support */ +int aft_global_hw_device_init(void); + +int wanpipe_globals_util_init(void); /* Initialize All Global Tables */ + +#if defined(__LINUX__) +extern int wanpipe_queue_tq (struct tq_struct *); +extern int wanpipe_mark_bh (void); +extern int change_dev_flags (netdevice_t *, unsigned); +extern unsigned long get_ip_address (netdevice_t *dev, int option); +extern void add_gateway(sdla_t *, netdevice_t *); + +#if 0 +extern void fastcall wp_tasklet_hi_schedule_per_cpu(struct tasklet_struct *t, int cpu_no); +extern void wp_tasklet_per_cpu_init (void); +#endif + +//FIXME: Take it out +//extern int wan_reply_udp( unsigned char *data, unsigned int mbox_len, int trace_opt); +//extern int wan_udp_pkt_type(sdla_t* card,unsigned char *data); + +extern int wanpipe_sdlc_unregister(netdevice_t *dev); +extern int wanpipe_sdlc_register(netdevice_t *dev, void *wp_sdlc_reg); +//ALEX_TODAY extern int check_conf_hw_mismatch(sdla_t *card, unsigned char media); +#endif + +void adsl_vcivpi_update(sdla_t* card, wandev_conf_t* conf); + +#ifdef CONFIG_PRODUCT_WANPIPE_ANNEXG +extern struct wanpipe_lapb_register_struct lapb_protocol; +#endif + +int wan_snmp_data(sdla_t* card, netdevice_t* dev, int cmd, struct ifreq* ifr); + +int wan_capture_trace_packet(sdla_t *card, wan_trace_t* trace_info, netskb_t *skb, char direction); +int wan_capture_trace_packet_offset(sdla_t *card, wan_trace_t* trace_info, netskb_t *skb, int off,char direction); + +#if defined(__LINUX__) +int wan_verify_iovec(struct msghdr *m, struct iovec *iov, char *address, int mode); +int wan_memcpy_fromiovec(unsigned char *kdata, struct iovec *iov, int len); +int wan_memcpy_toiovec(struct iovec *iov, unsigned char *kdata, int len); +#endif + +/* LIP ATM prototypes */ +int init_atm_idle_buffer(unsigned char *buff, int buff_len, char *if_name, char hardware_flip); +int atm_add_data_to_skb(void* skb, void *data, int data_len, char *if_name); +int atm_pad_idle_cells_in_tx_skb(void *skb, void *tx_idle_skb, char *if_name); +void *atm_tx_skb_dequeue(void* wp_tx_pending_list, void *tx_idle_skb, char *if_name); + + +#if defined(__FreeBSD__) && defined(NETGRAPH) +int wan_ng_init(sdla_t*); +int wan_ng_remove(sdla_t*); +#endif + +#endif /* __KERNEL__ */ +#endif /* _WANPIPE_H */ diff -Nur linux.org/include/linux/wanpipe_iface.h linux-2.6.17/include/linux/wanpipe_iface.h --- linux.org/include/linux/wanpipe_iface.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/wanpipe_iface.h 2006-08-30 10:07:15.000000000 +0000 @@ -0,0 +1,123 @@ + + +#ifndef __WANPIPE_IFACE_H +# define __WANPIPE_IFACE_H + +#if defined(__LINUX__) +# include +#endif + +#define WAN_IFACE_NETDEV 0x01 +#define WAN_IFACE_SPPP 0x02 + +#if defined(__NetBSD__) || defined (__FreeBSD__) || defined(__OpenBSD__) + +# define IF_IFACE_V35 0x1001 +# define IF_IFACE_T1 0x1002 +# define IF_IFACE_E1 0x1003 +# define IF_IFACE_SYNC_SERIAL 0x1004 + +# define IF_PROTO_HDLC 0x2001 +# define IF_PROTO_PPP 0x2002 +# define IF_PROTO_CISCO 0x2003 +# define IF_PROTO_FR 0x2004 +# define IF_PROTO_FR_ADD_PVC 0x2005 +# define IF_PROTO_FR_DEL_PVC 0x2006 +# define IF_PROTO_X25 0x2007 +# define WAN_PROTO_X25 0x2007 + +# define IF_GET_PROTO 0x3001 + +# define te1_settings void +# define sync_serial_settings void + +#elif defined(__LINUX__) + +# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) +//# define ifs_size data_length +//# define SIOCWANDEV SIOCDEVICE +# elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) +//# define ifs_size size +# else +//# define ifs_size data_length +#ifndef SIOCWANDEV +# define SIOCWANDEV SIOCDEVICE +#endif +# endif + +#endif + +#if defined(OLD_IFSETTINGS_STRUCT) +# define ifs_size data_length +# define ifs_te1 data +# define ifs_sync data +# define ifs_cisco data +# define ifs_fr data +# define ifs_fr_pvc data +# define ifs_fr_pvc_info data +#else +# define ifs_size size +# define ifs_te1 ifs_ifsu.te1 +# define ifs_sync ifs_ifsu.sync +# define ifs_cisco ifs_ifsu.cisco +# define ifs_fr ifs_ifsu.fr +# define ifs_fr_pvc ifs_ifsu.fr_pvc +# define ifs_fr_pvc_info ifs_ifsu.fr_pvc_info +#endif + + +#define WANHDLC_CONF_INTERFACE 0x0001 +#define WANHDLC_CONF_CLOCKING 0x0002 +#define WANHDLC_CONF_MTU 0x0004 +#define WANHDLC_CONF_UDPPORT 0x0008 +#define WANHDLC_CONF_TTL 0x0010 + +typedef struct { + unsigned long mask; + char interface; + unsigned bps; + unsigned mtu; + unsigned udp_port; + unsigned ttl; +} wan_dev_conf_t; + +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) +typedef struct { int dummy; } cisco_proto, fr_proto, fr_proto_pvc; +struct if_settings +{ + unsigned int type; + unsigned int data_length; + void* data; +}; +#endif + +/* WANPIPE Generic function interface */ +# if defined(WAN_KERNEL) + +/* ifType - SNMP */ +#if 0 +/* moved to wanpipe_defines.h */ +#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) +# define WAN_IFT_OTHER IFT_OTHER +# define WAN_IFT_ETHER IFT_ETHER +# define WAN_IFT_PPP IFT_PPP +#elif defined(__LINUX__) +# define WAN_IFT_OTHER 0x00 +# define WAN_IFT_ETHER 0x00 +# define WAN_IFT_PPP 0x00 +#endif +#endif + +typedef struct +{ + netdevice_t*(*alloc)(int, int ifType); + void(*free)(netdevice_t*); + int(*attach)(netdevice_t*, char*, int); + void(*detach)(netdevice_t*, int); + int(*input)(netdevice_t*, netskb_t*); + int(*set_proto)(netdevice_t*, struct ifreq*); + int(*attach_eth)(netdevice_t*, char*, int); +} wan_iface_t; + +# endif +#endif /* __WANPIPE_IFACE_H */ diff -Nur linux.org/include/linux/wanpipe_includes.h linux-2.6.17/include/linux/wanpipe_includes.h --- linux.org/include/linux/wanpipe_includes.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/wanpipe_includes.h 2006-08-30 10:07:15.000000000 +0000 @@ -0,0 +1,353 @@ +/* + ************************************************************************ + * wanpipe_includes.h * + * WANPIPE(tm) Global includes for Sangoma drivers * + * * + * Author: Alex Feldman * + *======================================================================* + * Aug 10 2002 Alex Feldman Initial version * + * * + ************************************************************************ + */ + +#ifndef __WANPIPE_INCLUDES_H +# define __WANPIPE_INCLUDES_H + +#if !defined(__NetBSD__) && !defined(__FreeBSD__) && !defined (__OpenBSD__) && !defined(__WINDOWS__) && !defined(__SOLARIS__) && !defined(__LINUX__) +# if defined(__KERNEL__) +# define __LINUX__ +# endif +#endif + +#if defined (__KERNEL__) || defined (KERNEL) || defined (_KERNEL) +# ifndef WAN_KERNEL +# define WAN_KERNEL +# endif +#endif + + +#if defined(__FreeBSD__) +/* +** *** F R E E B S D *** +# include +*/ +# include +# if (__FreeBSD_version > 600000) +# include +# else +# include +# endif +# include +# include +# include +# include +# include +# if (__FreeBSD_version > 400000) +# include +# else +# include +# endif +# if (__FreeBSD_version >= 410000) +# include +# endif +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# ifdef __SDLA_HW_LEVEL +# include +# include +# include +# include +# include +# endif +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# if (__FreeBSD_version >= 501000) +# include +# elif (__FreeBSD_version > 400000) +# include +# endif +# include +# include +# include +# include +# include +# include +# include +# include +#ifdef NETGRAPH +# include +# include +#endif /* NETGRAPH */ +# include +# if (__FreeBSD_version < 500000) +# include +# endif +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +#elif defined(__NetBSD__) +/* +** *** N E T B S D *** +*/ +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +#elif defined(__OpenBSD__) +/* +** *** O P E N B S D *** +*/ +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# if !defined(OpenBSD3_9) +# include +# endif +# include +# include +# include +/*# include */ +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +#elif defined(__LINUX__) +#ifdef __KERNEL__ +/* +** *** L I N U X *** +*/ +# include +# include /**/ +# include /* OS configuration options */ +# if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) +# if !(defined __NO_VERSION__) && !defined(_K22X_MODULE_FIX_) +# define __NO_VERSION__ +# endif +# endif +# if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) + /* Remove experimental SEQ support */ +# define _LINUX_SEQ_FILE_H +#endif +# include +# include +# include +# include +# include +# include /* offsetof, etc. */ +# include /* returns codes */ +# include /* inline memset, etc */ +# include +# include /* printk()m and other usefull stuff */ +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include /* phys_to_virt() */ +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include /* vmalloc, vfree */ +# include /* copy_to/from_user */ +# include /* __initfunc et al. */ +# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) +# include +# endif +# ifdef CONFIG_INET +# include +# endif +#endif +#elif defined(__SOLARIS__) +/* +** *** S O L A R I S *** +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#elif defined(__WINDOWS__) +/* +** *** W I N D O W S *** +*/ +# if !defined(USER_MODE) +# include "stddcls.h" +# include /* PCI configuration struct */ +# include /* NDIS functions */ +/* For drivers running over "Sangoma bus" (only Windows 2000/XP) */ +# include +# include +# include +# endif +#elif defined (__SOLARIS__) +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +#else +# error "Unsupported Operating System!"; +#endif + +#endif /* __WANPIPE_INCLUDES_H */ + diff -Nur linux.org/include/linux/wanpipe_kernel.h linux-2.6.17/include/linux/wanpipe_kernel.h --- linux.org/include/linux/wanpipe_kernel.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/wanpipe_kernel.h 2006-08-30 10:07:15.000000000 +0000 @@ -0,0 +1,445 @@ + +#ifndef _WANPIPE_KERNEL_H +#define _WANPIPE_KERNEL_H + +#ifdef __KERNEL__ + +#include + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,9) +# define MODULE_LICENSE(a) +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,10) +# define snprintf(a,b,c,d...) sprintf(a,c,##d) +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15) +# define wp_ip_rt_ioctl(_cmd_,_rptr_) -EINVAL +# define wp_devinet_ioctl(_cmd_,_rptr_) -EINVAL +#else +# define wp_ip_rt_ioctl(_cmd_,_rptr_) ip_rt_ioctl(_cmd_,_rptr_) +# define wp_devinet_ioctl(_cmd_,_rptr_) devinet_ioctl(_cmd_,_rptr_) +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) +/* KERNEL 2.6.X */ + + #define LINUX_2_6 + #define netdevice_t struct net_device + + #define FREE_READ 1 + #define FREE_WRITE 0 + + #define stop_net_queue(a) netif_stop_queue(a) + #define start_net_queue(a) netif_start_queue(a) + #define is_queue_stopped(a) netif_queue_stopped(a) + #define wake_net_dev(a) netif_wake_queue(a) + #define is_dev_running(a) netif_running(a) + #define wan_dev_kfree_skb(a,b) dev_kfree_skb_any(a) + + #define tq_struct work_struct + + #define wan_call_usermodehelper(a,b,c) call_usermodehelper(a,b,c,0) + + #define pci_present() 1 + + static inline void wan_schedule_task(struct tq_struct *tq) + { + schedule_work(tq); + } + + #define ADMIN_CHECK() {if (!capable(CAP_SYS_ADMIN)) {\ + DEBUG_EVENT("wanpipe: ADMIN_CHECK: Failed Cap=0x%X Fsuid=0x%X Euid=0x%X\n", \ + current->cap_effective,current->fsuid,current->euid);\ + return -EPERM; \ + }\ + } + + #define NET_ADMIN_CHECK() {if (!capable(CAP_NET_ADMIN)){\ + DEBUG_EVENT("wanpipe: NET_ADMIN_CHECK: Failed Cap=0x%X Fsuid=0x%X Euid=0x%X\n", \ + current->cap_effective,current->fsuid,current->euid);\ + return -EPERM; \ + }\ + } + + #define WAN_IRQ_RETVAL(a) return a + + #define mark_bh(a) + + #define wan_clear_bit(a,b) clear_bit((a),(unsigned long*)(b)) + #define wan_set_bit(a,b) set_bit((a),(unsigned long*)(b)) + #define wan_test_bit(a,b) test_bit((a),(unsigned long*)(b)) + #define wan_test_and_set_bit(a,b) test_and_set_bit((a),(unsigned long*)(b)) + #define wan_test_and_clear_bit(a,b) test_and_clear_bit((a),(unsigned long*)(b)) + + #define dev_init_buffers(a) + + #define WP_PDE(_a) PDE(_a) + + + + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,9) + # define wp_rcu_read_lock(in_dev) rcu_read_lock() + # define wp_rcu_read_unlock(in_dev) rcu_read_unlock() + # define wp_readb(ptr) readb((void __iomem *)(ptr)) + # define wp_reads(ptr) reads((void __iomem *)(ptr)) + # define wp_readl(ptr) readl((void __iomem *)(ptr)) + # define wp_writeb(data,ptr) writeb(data,(void __iomem *)(ptr)) + # define wp_writew(data,ptr) writew(data,(void __iomem *)(ptr)) + # define wp_writel(data,ptr) writel(data,(void __iomem *)(ptr)) + # define wp_memset_io(ptr,data,len) memset_io((void __iomem *)(ptr),data,len) + #else + # define wp_rcu_read_lock(in_dev) read_lock_bh(&in_dev->lock) + # define wp_rcu_read_unlock(in_dev) read_unlock_bh(&in_dev->lock) + # define wp_readb(ptr) readb((ptr)) + # define wp_reads(ptr) reads((ptr)) + # define wp_readl(ptr) readl((ptr)) + # define wp_writeb(data,ptr) writeb(data,(ptr)) + # define wp_writew(data,ptr) writew(data,(ptr)) + # define wp_writel(data,ptr) writel(data,(ptr)) + # define wp_memset_io(ptr,data,len) memset_io((ptr),data,len) + #endif + + #if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,14) + #define htonl __constant_htonl + #define htons __constant_htons + #define ntohl __constant_ntohl + #define ntohs __constant_ntohs + #endif + + +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) +/* -------------------------------------------------- + * KERNEL 2.4.X + * -------------------------------------------------*/ + + #define LINUX_2_4 + #define netdevice_t struct net_device + + #define FREE_READ 1 + #define FREE_WRITE 0 + + #define stop_net_queue(a) netif_stop_queue(a) + #define start_net_queue(a) netif_start_queue(a) + #define is_queue_stopped(a) netif_queue_stopped(a) + #define wake_net_dev(a) netif_wake_queue(a) + #define is_dev_running(a) netif_running(a) + #define wan_dev_kfree_skb(a,b) dev_kfree_skb_any(a) + #define pci_get_device(a,b,c) pci_find_device(a,b,c) + + #define __dev_get(a) dev_get(a) + + static inline void wan_schedule_task(struct tq_struct *tq) + { + schedule_task(tq); + } + + #ifndef INIT_WORK + # define INIT_WORK INIT_TQUEUE + #endif + + #define wan_call_usermodehelper(a,b,c) call_usermodehelper(a,b,c) + + #define ADMIN_CHECK() {if (!capable(CAP_SYS_ADMIN)) {\ + DEBUG_EVENT("wanpipe: ADMIN_CHECK: Failed Cap=0x%X Fsuid=0x%X Euid=0x%X\n", \ + current->cap_effective,current->fsuid,current->euid);\ + return -EPERM; \ + }\ + } + + #define NET_ADMIN_CHECK() {if (!capable(CAP_NET_ADMIN)){\ + DEBUG_EVENT("wanpipe: NET_ADMIN_CHECK: Failed Cap=0x%X Fsuid=0x%X Euid=0x%X\n", \ + current->cap_effective,current->fsuid,current->euid);\ + return -EPERM; \ + }\ + } + + #define WAN_IRQ_RETVAL(a) return + #ifndef IRQ_NONE + # define IRQ_NONE (0) + #endif + + #ifndef IRQ_HANDLED + # define IRQ_HANDLED (1) + #endif + + #define irqreturn_t void + + #define wan_clear_bit(a,b) clear_bit((a),(b)) + #define wan_set_bit(a,b) set_bit((a),(b)) + #define wan_test_bit(a,b) test_bit((a),(b)) + #define wan_test_and_set_bit(a,b) test_and_set_bit((a),(b)) + #define wan_test_and_clear_bit(a,b) test_and_clear_bit((a),(b)) + + static inline struct proc_dir_entry *WP_PDE(const struct inode *inode) + { + return (struct proc_dir_entry *)inode->u.generic_ip; + } + + #define wp_rcu_read_lock(in_dev) read_lock_bh(&in_dev->lock) + #define wp_rcu_read_unlock(in_dev) read_unlock_bh(&in_dev->lock) + #define wp_readb(ptr) readb((ptr)) + #define wp_reads(ptr) reads((ptr)) + #define wp_readl(ptr) readl((ptr)) + + #define wp_writeb(data,ptr) writeb(data,(ptr)) + #define wp_writew(data,ptr) writew(data,(ptr)) + #define wp_writel(data,ptr) writel(data,(ptr)) + #define wp_memset_io(ptr,data,len) memset_io((ptr),data,len) + + + +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0) +/*----------------------------------------------------- + * KERNEL 2.2.X + * ---------------------------------------------------*/ + + #define LINUX_2_1 + #define net_device device + #define netdevice_t struct device + #define FREE_READ 1 + #define FREE_WRITE 0 + + #define S_IRUGO 0 + + #define __exit + + #ifndef get_order + # define get_order(x) __get_order(x) + #endif + + #define pci_get_device(a,b,c) pci_find_device(a,b,c) + #define wan_dev_kfree_skb(a,b) kfree_skb(a) + #define dev_kfree_skb_any(a) kfree_skb(a) + + #define netif_wake_queue(dev) do { \ + clear_bit(0, &(dev)->tbusy); \ + mark_bh(NET_BH); \ + } while(0) + #define netif_start_queue(dev) do { \ + (dev)->tbusy = 0; \ + (dev)->interrupt = 0; \ + (dev)->start = 1; \ + } while (0) + + #define netif_stop_queue(dev) (set_bit(0, &(dev)->tbusy)) + #define netif_running(dev) (dev)->start + #define netdevice_start(dev) (dev)->start = 1 + #define netdevice_stop(dev) (dev)->start = 0 + #define netif_queue_stopped(dev) (test_bit(0,&(dev)->tbusy)) + #define netif_set_tx_timeout(dev, tf, tm) + + #define stop_net_queue(dev) netif_stop_queue(dev) + #define start_net_queue(dev) netif_start_queue(dev) + #define is_queue_stopped(dev) netif_queue_stopped(dev) + #define wake_net_dev(dev) netif_wake_queue(dev) + #define is_dev_running(dev) netif_running(dev) + + #define dev_kfree_skb_irq(x) kfree_skb(x) + + #define tasklet_struct tq_struct + + #define __dev_get(a) dev_get(a) + + #ifndef DECLARE_WAITQUEUE + #define DECLARE_WAITQUEUE(wait, current) struct wait_queue wait = { current, NULL } + #endif + + #define tasklet_kill(a) { if ((a)->sync) {} } + + #define request_mem_region(addr, size, name) ((void *)1) + #define release_mem_region(addr, size) + #define pci_enable_device(x) (0) + #define pci_resource_start(dev, bar) dev->base_address[bar] + + #define wp_rcu_read_lock(in_dev) + #define wp_rcu_read_unlock(in_dev) + #define wp_readb(ptr) readb((ptr)) + #define wp_reads(ptr) reads((ptr)) + #define wp_readl(ptr) readl((ptr)) + #define wp_writeb(data,ptr) writeb(data,(ptr)) + #define wp_writew(data,ptr) writew(data,(ptr)) + #define wp_writel(data,ptr) writel(data,(ptr)) + #define wp_memset_io(ptr,data,len) memset_io((ptr),data,len) + + static inline void tasklet_hi_schedule(struct tasklet_struct *tasklet) + { + queue_task(tasklet, &tq_immediate); + mark_bh(IMMEDIATE_BH); + } + + static inline void tasklet_schedule(struct tasklet_struct *tasklet) + { + queue_task(tasklet, &tq_immediate); + mark_bh(IMMEDIATE_BH); + } + + static inline void tasklet_init(struct tasklet_struct *tasklet, + void (*func)(unsigned long), + unsigned long data) + { + tasklet->next = NULL; + tasklet->sync = 0; + tasklet->routine = (void (*)(void *))func; + tasklet->data = (void *)data; + } + + static inline void wan_schedule_task(struct tq_struct *tq) + { + queue_task(tq, &tq_scheduler); + } + + /* Setup Dma Memory size copied directly from 3c505.c */ + static inline int __get_order(unsigned long size) + { + int order; + + size = (size - 1) >> (PAGE_SHIFT - 1); + order = -1; + do { + size >>= 1; + order++; + } while (size); + return order; + } + + typedef int (get_info_t)(char *, char **, off_t, int, int); + + #define ADMIN_CHECK() {if (!capable(CAP_SYS_ADMIN)) return -EPERM;} + #define NET_ADMIN_CHECK() {if (!capable(CAP_NET_ADMIN)) return -EPERM;} + + #define WAN_IRQ_RETVAL(a) return + #ifndef IRQ_NONE + # define IRQ_NONE (0) + #endif + + #ifndef IRQ_HANDLED + # define IRQ_HANDLED (1) + #endif + + typedef unsigned long mm_segment_t; + #define irqreturn_t void + + #ifndef INIT_WORK + # define INIT_WORK INIT_TQUEUE + #endif + + #define wan_clear_bit(a,b) clear_bit((a),(b)) + #define wan_set_bit(a,b) set_bit((a),(b)) + #define wan_test_bit(a,b) test_bit((a),(b)) + #define wan_test_and_set_bit(a,b) test_and_set_bit((a),(b)) + #define wan_test_and_clear_bit(a,b) test_and_clear_bit((a),(b)) + + static inline struct proc_dir_entry *WP_PDE(const struct inode *inode) + { + return (struct proc_dir_entry *)inode->u.generic_ip; + } + +#else +/* KERNEL 2.0.X */ + + + #define LINUX_2_0 + #define netdevice_t struct device + + static inline struct proc_dir_entry *WP_PDE(const struct inode *inode) + { + return (struct proc_dir_entry *)inode->u.generic_ip; + } + + #define test_and_set_bit set_bit + #define net_ratelimit() 1 + + #define stop_net_queue(a) (set_bit(0, &a->tbusy)) + #define start_net_queue(a) (clear_bit(0,&a->tbusy)) + #define is_queue_stopped(a) (a->tbusy) + #define wake_net_dev(a) {clear_bit(0,&a->tbusy);mark_bh(NET_BH);} + #define is_dev_running(a) (test_bit(0,(void*)&a->start)) + #define wan_dev_kfree_skb(a,b) kfree_skb(a,b) + #define pci_get_device(a,b,c) pci_find_device(a,b,c) + #define spin_lock_init(a) + #define spin_lock(a) + #define spin_unlock(a) + + #define __dev_get(a) dev_get(a) + + #define netif_wake_queue(dev) do { \ + clear_bit(0, &dev->tbusy); \ + mark_bh(NET_BH); \ + } while(0) + #define netif_start_queue(dev) do { \ + dev->tbusy = 0; \ + dev->interrupt = 0; \ + dev->start = 1; \ + } while (0) + #define netif_stop_queue(dev) set_bit(0, &dev->tbusy) + #define netif_running(dev) dev->start + #define netdevice_start(dev) dev->start = 1 + #define netdevice_stop(dev) dev->start = 0 + #define netif_set_tx_timeout(dev, tf, tm) + #define dev_kfree_skb_irq(x) kfree_skb(x) + + typedef int (write_proc_t)(char *, char **, off_t, int, int); + + #define net_device_stats enet_statistics + + static inline int copy_from_user(void *a, void *b, int len){ + int err = verify_area(VERIFY_READ, b, len); + if (err) + return err; + + memcpy_fromfs (a, b, len); + return 0; + } + + static inline int copy_to_user(void *a, void *b, int len){ + int err = verify_area(VERIFY_WRITE, b, len); + if (err) + return err; + memcpy_tofs (a, b,len); + return 0; + } + + #define WAN_IRQ_RETVAL(a) return + #ifndef IRQ_NONE + # define IRQ_NONE (0) + #endif + + #ifndef IRQ_HANDLED + # define IRQ_HANDLED (1) + #endif + + typedef unsigned long mm_segment_t; + #define irqreturn_t void + +#endif + +static inline int open_dev_check(netdevice_t *dev) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,18) + return is_dev_running(dev); +#else + return 0; +#endif +} + +#else + +#include + +/* This file is not being included from kernel space + * we need to define what kersdladrv_pci_tblnel version we are + * running */ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) + #define LINUX_2_6 +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) + #define LINUX_2_4 +#else + #define LINUX_2_4 +#endif + + +#endif +#endif diff -Nur linux.org/include/linux/wanpipe_lapb_iface.h linux-2.6.17/include/linux/wanpipe_lapb_iface.h --- linux.org/include/linux/wanpipe_lapb_iface.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/wanpipe_lapb_iface.h 2006-08-30 10:07:15.000000000 +0000 @@ -0,0 +1,49 @@ +/* + * These are the public elements of the Linux LAPB module. + */ + +#ifndef _WP_LAPB_IFACE_H +#define _WP_LAPB_IFACE_H + + +enum lapb_ioctl_cmds { + SIOCG_LAPB_CONF, + SIOCS_LAPB_NEW_X25_CONF, + SIOCS_LAPB_DEL_X25_CONF, + SIOCG_LAPB_STATUS, +}; + + +#if 0 +typedef struct wp_lapb_reg +{ + int (*prot_state_change) (void *, int, unsigned char *, int); + int (*chan_state_change) (void *, int, unsigned char *, int); + int (*tx_down) (void *, void *); + int (*rx_up) (void *, void *); +}wp_lapb_reg_t; +#endif + +extern void *wp_register_lapb_prot(void *, char *, + void *, + wplip_prot_reg_t *); +extern int wp_unregister_lapb_prot(void *); + +extern void *wp_register_lapb_chan_prot(void *callback_dev_ptr, + void *link_ptr, + char *devname, + void *cfg_ptr, + unsigned char type); + +extern int wp_unregister_lapb_chan_prot(void *dev_ptr); + + +extern int wp_lapb_open(void *lapb_ptr); +extern int wp_lapb_close(void *lapb_ptr); +extern int wp_lapb_rx(void *lapb_ptr, void *skb); +extern int wp_lapb_bh(void *lapb_ptr); +extern int wp_lapb_tx(void *lapb_ptr, void *skb, int type); +extern int wp_lapb_timer(void *lapb_ptr, unsigned int *period, unsigned int); + + +#endif diff -Nur linux.org/include/linux/wanpipe_lapb_kernel.h linux-2.6.17/include/linux/wanpipe_lapb_kernel.h --- linux.org/include/linux/wanpipe_lapb_kernel.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/wanpipe_lapb_kernel.h 2006-08-30 10:07:15.000000000 +0000 @@ -0,0 +1,92 @@ +/* + * These are the public elements of the Linux LAPB module. + */ + +#include +#include +#include +#include "wanpipe_x25_kernel.h" + +#ifndef LAPB_KERNEL_H +#define LAPB_KERNEL_H + +#define LAPB_OK 0 +#define LAPB_BADTOKEN 1 +#define LAPB_INVALUE 2 +#define LAPB_CONNECTED 3 +#define LAPB_NOTCONNECTED 4 +#define LAPB_REFUSED 5 +#define LAPB_TIMEDOUT 6 +#define LAPB_NOMEM 7 + +#define LAPB_STANDARD 0x00 +#define LAPB_EXTENDED 0x01 + +#define LAPB_SLP 0x00 +#define LAPB_MLP 0x02 + +#define LAPB_DTE 0x00 +#define LAPB_DCE 0x04 + +enum lapb_ioctl_cmds { + SIOCC_PC_RESERVED = (SIOC_WANPIPE_DEVPRIVATE), + SIOCG_LAPB_CONF, + SIOCS_LAPB_NEW_X25_CONF, + SIOCS_LAPB_DEL_X25_CONF, + SIOCG_LAPB_STATUS, +}; + + +#ifdef __KERNEL__ + +extern int register_lapb_x25_protocol (struct lapb_x25_register_struct * x25_reg); +extern void unregister_lapb_x25_protocol (void); + + +extern int lapb_x25_register(struct net_device *lapb_dev, + char *dev_name, + struct net_device **new_dev); + +extern int lapb_x25_unregister(struct net_device *x25_dev); + +extern int lapb_x25_setparms (struct net_device *lapb_dev, + struct net_device *x25_dev, + struct x25_parms_struct *x25_parms); + + +struct wanpipe_lapb_register_struct { + + unsigned long init; + + int (*lapb_register)(struct net_device *dev, + char *dev_name, char *hw_name, + struct net_device **new_dev); + int (*lapb_unregister)(struct net_device *dev); + + int (*lapb_getparms)(struct net_device *dev, struct lapb_parms_struct *parms); + int (*lapb_setparms)(struct net_device *dev, struct lapb_parms_struct *parms); + void (*lapb_mark_bh) (struct net_device *dev); + void (*lapb_link_up) (struct net_device *dev); + void (*lapb_link_down) (struct net_device *dev); + int (*lapb_rx) (struct net_device *dev, struct sk_buff *skb); + + int (*lapb_x25_register)(struct net_device *lapb_dev, + char *dev_name, + struct net_device **new_dev); + + int (*lapb_x25_unregister)(struct net_device *x25_dev); + + int (*lapb_x25_setparms) (struct net_device *lapb_dev, + struct net_device *x25_dev, + struct x25_parms_struct *x25_parms); + int (*lapb_get_map)(struct net_device*, struct seq_file *); + void (*lapb_get_active_inactive)(struct net_device*, wp_stack_stats_t*); +}; + +extern int register_wanpipe_lapb_protocol (struct wanpipe_lapb_register_struct *lapb_reg); +extern void unregister_wanpipe_lapb_protocol (void); + +#endif + + +#endif diff -Nur linux.org/include/linux/wanpipe_lapd_iface.h linux-2.6.17/include/linux/wanpipe_lapd_iface.h --- linux.org/include/linux/wanpipe_lapd_iface.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/wanpipe_lapd_iface.h 2006-08-30 10:07:15.000000000 +0000 @@ -0,0 +1,61 @@ +/* + * These are the public elements of the Binary lapd module. + */ + +#ifndef _WP_LAPD_IFACE_H +#define _WP_LAPD_IFACE_H + +/* Mandatory Define here */ +#ifdef WANLIP_DRIVER + +#define ETH_P_LAPD 0x0030 + +enum lapd_ioctl_cmds { + SIOCG_LAPD_CONF, + SIOCG_LAPD_STATUS, +}; + +extern void *wp_register_lapd_prot (void *, + char *, + void *, + wplip_prot_reg_t *); + +extern int wp_unregister_lapd_prot (void *); + +extern void *wp_register_lapd_chan (void *if_ptr, + void *prot_ptr, + char *devname, + void *cfg_ptr, + unsigned char type); + +extern int wp_unregister_lapd_chan (void *chan_ptr); + +extern int wp_lapd_open (void *prot_ptr); +extern int wp_lapd_close (void *prot_ptr); +extern int wp_lapd_rx (void *prot_ptr, void *skb); +extern int wp_lapd_bh (void *prot_ptr); +extern int wp_lapd_tx (void *prot_ptr, void *skb, int type); +extern int wp_lapd_timer (void *prot_ptr, unsigned int *period, + unsigned int carrier_reliable); +extern int wp_lapd_pipemon (void *prot_ptr, int cmd, int addr, + unsigned char* data, unsigned int *len); + +#endif + + +/* Any public structures shared between LIP and + * Object Code */ + + + + +/* This code should go into wanpipe_cfg.h */ +typedef struct wan_lapd_if_conf +{ + /* IMPLEMENT USER CONFIG OPTIONS HERE */ + unsigned char data; + + +}wan_lapd_if_conf_t; + +#endif diff -Nur linux.org/include/linux/wanpipe_lip_atm_iface.h linux-2.6.17/include/linux/wanpipe_lip_atm_iface.h --- linux.org/include/linux/wanpipe_lip_atm_iface.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/wanpipe_lip_atm_iface.h 2006-08-30 10:07:15.000000000 +0000 @@ -0,0 +1,69 @@ +/***************************************************************************** +* wanpipe_lip_atm_iface.h WANPIPE(tm) ATM ALL5 SAR Interface Header +* +* Authors: David Rokhvarg +* +* Copyright: (c) 2003 Sangoma Technologies Inc. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version +* 2 of the License, or (at your option) any later version. +* ============================================================================ +* September 15, 2005 David Rokhvarg Initial Version +*****************************************************************************/ + + +#ifndef _WANPIPE_LIP_ATM_IFACE_H +#define _WANPIPE_LIP_ATM_IFACE_H + +#include + +#define wplist_insert_dev(dev, list) do{\ + dev->next = list;\ + list = dev;\ + }while(0) + +#define wplist_remove_dev(dev,cur,prev,list)\ + do{\ + if ((cur=list) == dev){\ + list=cur->next;\ + break;\ + }else{\ + while (cur!=NULL && cur->next!=NULL){\ + prev=cur;\ + cur=cur->next;\ + if (cur==dev){\ + prev->next=cur->next;\ + break;\ + }\ + }\ + }\ + }while(0) + +extern void *wp_register_atm_prot(void *link_ptr, + char *devname, + void *cfg, + wplip_prot_reg_t *atm_reg); + +extern int wp_unregister_atm_prot(void *prot_ptr); + +extern void *wp_register_atm_chan(void *if_ptr, + void *prot_ptr, + char *devname, + void *cfg, + unsigned char type); + +extern int wp_unregister_atm_chan(void *chan_ptr); + +extern int wp_atm_open_chan (void *chan_ptr); +extern int wp_atm_close_chan(void *chan_ptr); +extern int wp_atm_ioctl (void *chan_ptr, int cmd, void *arg); + +extern int wp_atm_rx (void * prot_ptr, void *rx_pkt); +extern int wp_atm_timer (void *prot_ptr, unsigned int *period, unsigned int carrier_reliable); +extern int wp_atm_tx (void * chan_ptr, void *skb, int type); +extern int wp_atm_pipemon(void *chan, int cmd, int dlci, unsigned char* data, unsigned int *len); +extern int wp_atm_snmp(void* chan_ptr, void* data); + +#endif diff -Nur linux.org/include/linux/wanpipe_lip.h linux-2.6.17/include/linux/wanpipe_lip.h --- linux.org/include/linux/wanpipe_lip.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/wanpipe_lip.h 2006-08-30 10:07:15.000000000 +0000 @@ -0,0 +1,682 @@ +/* $Header$ */ + +#ifndef _WANPIPE_LIP_HEADER_ +#define _WANPIPE_LIP_HEADER_ + + +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# if defined(CONFIG_PRODUCT_WANPIPE_LAPB) +# include +# endif +# if defined(CONFIG_PRODUCT_WANPIPE_XDLC) +# include +# endif +#else +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# if defined(CONFIG_PRODUCT_WANPIPE_LAPB) +# include +# endif +# if defined(CONFIG_PRODUCT_WANPIPE_LAPD) +# include +# endif +# if defined(CONFIG_PRODUCT_WANPIPE_XDLC) +# include +# endif +# if defined(CONFIG_PRODUCT_WANPIPE_XMTP2) +# include +# endif +# include +# include + +# ifdef WPLIP_TTY_SUPPORT +# include +# include +# include +# endif + +#endif + + + + +#ifdef WAN_KERNEL + +/* + *********************************************************************************** + * * + * X25HDR.C is the 'C' header file for the Sangoma X.25 code for the S508 adapter. * + * * + *********************************************************************************** +*/ + +#define LIP_OK 0 +#define TCPIP 0 + +#define MAX_CALL_REQ_ASYNC_PKT 512 + +#define NON_D_OPT 3 +#define D_OPT 2 + +#define FLOW_CONTROL_MASK 0x1F + +#define ONE_BYTE 1 +#define MAX_TOKENS 31 + +#define MODNAME "wanpipe_lip" + +#define MAX_LINK_RX_Q_LEN 10 +#define MAX_TAIL_ROOM 16 +#define MAX_LIP_LINKS 255 + +#if 0 +/* This option defaults the inital network + * interface state to STOPPED/DISABLED. + * + * In this case, all traffic will be blocked + * and data pushed back up the protocol stack. + * This can cause memory starvation if there are + * many interfaces running, because each interface + * queue can be up to 100 packets, and fames will + * only be dropped once the queue is overfilled + * + * By disabling this option, all packets received + * by the interface in disconnected state, will be + * silently discarded with carrier stat incremented. + */ +#define WANPIPE_LIP_IFNET_QUEUE_POLICY_INIT_OFF +#endif + +/* BH flags */ +enum{ + WPLIP_BH_RUNNING, + WPLIP_RX_FSM_RUNNING, + WPLIP_SMP_CONFLICT, + WPLIP_BH_AWAITING_KICK, + WPLIP_LINK_TIMER_EXPIRED, + WPLIP_MORE_LINK_TX, + WPLIP_LINK_DOWN, + WPLIP_KICK, + WPLIP_TTY_BUSY + +}; + + +/* LIP DEV Critical */ +enum { + WPLIP_TX_WINDOW_CLOSED, + WPLIP_SEND_AWAITING_KICK, + WPLIP_TIMER_EXPIRED, + WPLIP_DEV_DOWN, + WPLIP_DEV_UNREGISTER, + WPLIP_RX, + WPLIP_IOCTL_SMP, + WPLIP_DEV_SENDING +}; + +#define MAX_RX_FACIL_CODE 30 + +#define BH_DEBUG 0 + +#define SOFT_INIT 0 +#define HARD_INIT 1 +#define MAX_SOFTIRQ_TIMEOUT 2 + +/* + * Physical X25 Link + * Each Link can support multiple logical + * channels (svc). + */ +#define MAX_LCN 255 +#define MAX_DECODE_BUF_SZ 1000 +#define MAX_PROC_NAME 10 + +#ifndef MAX_PROC_EVENTS +#define MAX_PROC_EVENTS 20 +#endif +#define MAX_PROC_EVENT_SIZE X25_CALL_STR_SZ+200+1 + + +/*#define MAX_TX_BUF 10*/ +#define MAX_TX_BUF 10 +#define MAX_ATM_TX_BUF 35 +#define MAX_RX_Q 32 + +#define WPLIP_MAGIC_LINK 0xDAFE1234 +#define WPLIP_MAGIC_DEV 0xDAFE4321 +#define WPLIP_MAGIC_DEV_EL 0xDAFE4444 + +#define WPLIP_ASSERT_MAGIC(ptr,magic,ret) \ + if ((*(unsigned long*)ptr) != magic) { \ + DEBUG_EVENT("%s:%d: Error Invalid Magic number in Link dev!\n", \ + __FUNCTION__,__LINE__); \ + return ret ; \ + } +#define WPLIP_ASSERT_MAGIC_VOID(ptr,magic) \ + if ((*(unsigned long*)ptr) != magic) { \ + DEBUG_EVENT("%s:%d: Error Invalid Magic number in Link dev!\n", \ + __FUNCTION__,__LINE__); \ + return; \ + } + +struct wplip_dev; + +WAN_LIST_HEAD(wplip_link_list,wplip_link); + +typedef struct wplip_link +{ + unsigned long magic; + WAN_LIST_ENTRY(wplip_link) list_entry; + + /* List of all Logic channel + * devices attached to the link + * + * Packet direction UP + * */ + WAN_LIST_HEAD(,wplip_dev) list_head_ifdev; + unsigned int dev_cnt; + wan_rwlock_t dev_list_lock; + + + /* List of Tx Devices attached + * to the Link. + * + * Packet direction DOWN + * + * Eg. Load balancing over multiple + * links */ + + WAN_LIST_HEAD(,wplip_dev_list) list_head_tx_ifdev; + unsigned int tx_dev_cnt; + wan_rwlock_t tx_dev_list_lock; + + + unsigned char state; + unsigned char carrier_state; + unsigned char prot_state; + + void *prot; + wan_timer_t prot_timer; + + unsigned char protocol; + + + /* Internal control information */ + wan_timer_info_t timer; + + unsigned long tq_working; + + wan_rwlock_t map_lock; + void *api_sk_id; + + wan_spinlock_t bh_lock; + + unsigned char name [MAX_PROC_NAME]; +#if 0 + struct proc_dir_entry *proc_dir; + unsigned char *proc_event_log [MAX_PROC_EVENTS]; + atomic_t proc_event_offset; +#endif + + wan_skb_queue_t tx_queue; + wan_skb_queue_t rx_queue; + wan_tasklet_t task; + + struct wplip_dev *cur_tx; + + int link_num; + + atomic_t refcnt; + + unsigned char tty_opt; + +#ifdef WPLIP_TTY_SUPPORT + struct tty_struct *tty; + unsigned int tty_minor; + unsigned int tty_open; + unsigned char *tty_buf; + wan_skb_queue_t tty_rx; + wan_taskq_t tty_task_queue; + unsigned char async_mode; +#endif + + wan_taskq_t prot_task; + +} wplip_link_t; + + +#define CALL_REQUEST_INFO_SZ 512 + + +/* + * The logic channel per link connection control structure. + */ +typedef struct wplip_dev{ + + wanpipe_common_t common; + + unsigned long magic; + WAN_LIST_ENTRY(wplip_dev) list_entry; + + unsigned short critical; + + /* Internal control information */ + wan_skb_queue_t tx_queue; + + /* The link we are part of */ + wplip_link_t *lip_link; + + void *sk_id; + unsigned char api_state; +#if defined(__LINUX__) + struct proc_dir_entry *dent; +#endif + struct net_device_stats ifstats; + + unsigned char used; + unsigned char protocol; + + unsigned char name[MAX_PROC_NAME]; + + unsigned char udp_pkt_data[sizeof(wan_udp_pkt_t)+10]; + unsigned int udp_pkt_len; + + unsigned long ipx_net_num; + + unsigned int prot_addr; + + unsigned int max_mtu_sz; + + atomic_t refcnt; + pid_t pid; + + unsigned int interface_down; + wan_taskq_t if_task; + +} wplip_dev_t; + +typedef struct wplip_dev_list +{ + unsigned long magic; + netdevice_t *dev; + WAN_LIST_ENTRY(wplip_dev_list) list_entry; +}wplip_dev_list_t; + + +typedef struct wplip_prot_iface +{ + unsigned int init; + wplip_prot_reg_t reg; + void*(*prot_link_register)(void *link_ptr, + char *devname, + void *cfg, + wplip_prot_reg_t *reg); + + int (*prot_link_unregister)(void *prot_ptr); + + void*(*prot_chan_register)(void *if_ptr, + void *prot_ptr, + char *devname, + void *cfg, + unsigned char type); + + int (*prot_chan_unregister)(void *chan_ptr); + + int (*open_chan) (void *chan_ptr); + int (*close_chan)(void *chan_ptr); + + int (*tx) (void *chan_ptr, void *skb, int type); + int (*ioctl) (void *chan_ptr, int cmd, void *arg); + int (*pipemon)(void *chan, + int cmd, + int dlci, + unsigned char* data, + unsigned int *len); + + int (*rx) (void *prot_ptr, void *rx_pkt); + int (*timer) (void *prot_ptr, unsigned int *period, unsigned int); + int (*bh) (void *); + int (*snmp) (void *, void *); + int (*task) (void *prot_ptr); + +}wplip_prot_iface_t; + +#define MAX_LIP_PROTOCOLS 255 + +#define WPLIP_PROT_ASSERT(prot,ret) \ + if (prot >= MAX_LIP_PROTOCOLS){ \ + DEBUG_EVENT("%s:%d: Lip Error: Invalid Protocol 0x%X\n",\ + __FUNCTION__,__LINE__,prot);\ + return ret; \ + } + +#define WPLIP_PROT_FUNC_ASSERT(prot,func,ret) \ + if (prot->func == NULL){ \ + DEBUG_EVENT("%s:%d: Lip Error: Protocol function not supported\n",\ + __FUNCTION__,__LINE__);\ + return ret; \ + } + +#define WPLIP_PROT_EXIST(prot,ret) \ + if (wplip_prot_ops[prot] == NULL){ \ + DEBUG_EVENT("%s:%d: Lip Error: Unsupported/UnCompiled Protocol 0x%X\n",\ + __FUNCTION__,__LINE__,prot);\ + return ret; \ + } + + +#define wplip_hold(_dev) wan_atomic_inc(&(_dev)->refcnt) +#define wplip_put(_dev) wan_atomic_dec(&(_dev)->refcnt) + +#define wplip_get_link(_reg) (_reg)->wplip_link +#define wplip_get_lipdev(_dev) (wplip_dev_t*)wan_netif_priv((_dev)) + +#define wplip_liplink_magic(_link) ((_link)->magic == WPLIP_MAGIC_LINK) +#define wplip_lipdev_magic(_lipdev) ((_lipdev)->magic == WPLIP_MAGIC_DEV) + + +/* Function Prototypes */ + +/* wanpipe_lip_iface.c */ +extern unsigned char wplip_link_num[]; +extern wan_rwlock_t wplip_link_lock; +extern struct wplip_link_list list_head_link; +extern int wplip_data_rx_up(wplip_dev_t* lip_dev, void *skb); +extern int wplip_data_tx_down(wplip_link_t *lip_link, void *skb); +extern int wplip_callback_tx_down(void *lip_dev, void *skb); +extern int wplip_link_callback_tx_down(void *lip_link, void *skb); +extern int wplip_callback_kick_prot_task(void *lip_link); +extern int wplip_set_hw_idle_frame (void *liplink_ptr, unsigned char *data, int len); + +/* wanpipe_lip_sub.c */ +extern wplip_link_t* wplip_create_link(char *devname); +extern void wplip_remove_link(wplip_link_t *lip_link); +extern void wplip_insert_link(wplip_link_t *lip_link); +extern int wplip_link_exists(wplip_link_t *lip_link); +extern void wplip_free_link(wplip_link_t *lip_link); + + +#if 1 +extern wplip_dev_t* wplip_create_lipdev(char *dev_name,int); +#else +extern wplip_dev_t* wplip_create_lipdev(char *dev_name); +#endif +extern void wplip_free_lipdev(wplip_dev_t *lip_dev); +extern int wplip_lipdev_exists(wplip_link_t *lip_link, char *dev_name); +extern void wplip_remove_lipdev(wplip_link_t *lip_link, + wplip_dev_t *lip_dev); +extern void wplip_insert_lipdev(wplip_link_t *wplip_link, + wplip_dev_t *wplip_dev); + +extern unsigned int dec_to_uint (unsigned char* str, int len); + +/* wanpipe_lip_netdev.c */ +extern int wplip_open_dev(netdevice_t *dev); +extern int wplip_stop_dev(netdevice_t *dev); +extern struct net_device_stats * wplip_ifstats (netdevice_t *dev); +extern int wplip_if_send (netskb_t *skb, netdevice_t *dev); +extern int wplip_if_init(netdevice_t *dev); +extern void wplip_kick(void *wplip_id,int reason); + + +# ifdef WPLIP_TTY_SUPPORT +/* wanpipe_lip_tty.c */ +extern int wplip_reg_tty(wplip_link_t *lip_link, wanif_conf_t *conf); +extern int wplip_unreg_tty(wplip_link_t *lip_link); +extern int wanpipe_tty_trigger_poll(wplip_link_t *lip_link); +extern void wplip_tty_receive(wplip_link_t *lip_link, void *skb); +#endif + +/* wanpipe_lip_prot.c */ +extern int wplip_init_prot(void); +extern int wplip_free_prot(void); +extern int wplip_reg_link_prot(wplip_link_t *lip_link, wanif_conf_t *conf); +extern int wplip_unreg_link_prot(wplip_link_t *lip_link); +extern int wplip_reg_lipdev_prot(wplip_dev_t *lip_dev, wanif_conf_t *conf); +extern int wplip_unreg_lipdev_prot(wplip_dev_t *lip_dev); +extern int wplip_open_lipdev_prot(wplip_dev_t *lip_dev); +extern int wplip_close_lipdev_prot(wplip_dev_t *lip_dev); +extern int wplip_prot_rx(wplip_link_t *lip_link, netskb_t *skb); + +#if 0 +extern void wplip_prot_rx_kick(wplip_dev_t *lip_dev); +#endif +extern int wplip_prot_kick(wplip_link_t *lip_link, wplip_dev_t *lip_dev); +extern int wplip_prot_tx(wplip_dev_t *lip_dev, wan_api_tx_hdr_t *api_tx_hdr, netskb_t *skb, int type); +extern int wplip_prot_oob(wplip_dev_t *lip_dev, unsigned char*, int reason); +extern int wplip_prot_ioctl(wplip_dev_t *lip_dev, int cmd, void *arg); +extern int wplip_prot_udp_mgmt_pkt(wplip_dev_t * lip_dev, wan_udp_pkt_t *wan_udp_pkt); +extern int wplip_prot_udp_snmp_pkt(wplip_dev_t * lip_dev, int cmd, struct ifreq* ifr); + + +extern int wplip_link_prot_change_state(void *wplip_id, + int state, + unsigned char*,int); +extern int wplip_lipdev_prot_change_state(void *wplip_id, + int state, + unsigned char*,int); + + +extern unsigned int wplip_get_ipv4_addr (void *wplip_id, int type); +extern int wplip_set_ipv4_addr (void *wplip_id, + unsigned int, + unsigned int, + unsigned int, + unsigned int); +extern void wplip_add_gateway(void *wplip_id); +extern void wplip_trigger_if_task(wplip_dev_t *lip_dev); + +void wplip_ipxwan_switch_net_num(unsigned char *sendpacket, + unsigned long network_number, + unsigned long *orig_dnet, + unsigned long *orig_snet, + unsigned char incoming); + + +void wplip_ipxwan_restore_net_num(unsigned char *sendpacke, + unsigned long orig_dnet, + unsigned long orig_snet); + + +int wplip_handle_ipxwan(wplip_dev_t *lip_dev, void *skb); + +#if 0 +extern int gdbg_flag; +#endif + +static __inline int wplip_trigger_bh(wplip_link_t *lip_link) +{ + if (wan_test_bit(WPLIP_LINK_DOWN,&lip_link->tq_working)){ + return -ENETDOWN; + } + + if (wan_skb_queue_len(&lip_link->rx_queue)){ + WAN_TASKLET_SCHEDULE((&lip_link->task)); + return 0; + } + + if (wan_test_bit(WPLIP_BH_AWAITING_KICK,&lip_link->tq_working)){ +#if 0 + if (gdbg_flag){ + DEBUG_EVENT("%s: Waiting for kick!\n", + __FUNCTION__); + } +#endif + return -EBUSY; + } + +#if 0 + gdbg_flag=0; +#endif + WAN_TASKLET_SCHEDULE((&lip_link->task)); + return 0; +} + +static __inline int wplip_kick_trigger_bh(wplip_link_t *lip_link) +{ + wan_clear_bit(WPLIP_BH_AWAITING_KICK,&lip_link->tq_working); + WAN_TASKLET_SCHEDULE((&lip_link->task)); + return 0; +} + +static __inline int wplip_decode_protocol(wplip_dev_t *lip_dev, void *ptr) +{ +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) + struct sockaddr *sa = (struct sockaddr *)ptr; + + + switch (sa->sa_family){ + + case AF_INET: + return WPLIP_IP; + case AF_INET6: + return WPLIP_IPV6; + case AF_IPX: + return WPLIP_IPX; + default: + return WPLIP_IP; + } + +#elif defined(__LINUX__) + struct sk_buff *skb=(struct sk_buff*)ptr; + + if (lip_dev->common.usedby == BRIDGE || + lip_dev->common.usedby == BRIDGE_NODE){ + return WPLIP_ETH; + + } + + if (lip_dev->common.lip_prot == WANCONFIG_LAPD) { + return WPLIP_LAPD; + } + + if (lip_dev->common.usedby == STACK){ + switch (lip_dev->common.lip_prot){ + case WANCONFIG_PPP: + case WANCONFIG_TTY: + return WPLIP_PPP; + case WANCONFIG_FR: + return WPLIP_FR; + } + /* Break out down */ + } + + switch (htons(skb->protocol)){ + + case ETH_P_IP: + return WPLIP_IP; + case ETH_P_IPV6: + return WPLIP_IPV6; + case ETH_P_IPX: + return WPLIP_IPX; + } + + return WPLIP_IP; +#else +# error ("wplip_decode_protocol: Unknown Protocol!\n"); +#endif + +} + + +#if defined(__LINUX__) +static __inline void wp_lip_config_bridge_mode(wplip_dev_t *lip_dev) +{ + netdevice_t * dev = lip_dev->common.dev; + /* Setup the interface for Bridging */ + int hw_addr=0; + ether_setup(dev); + + /* Use a random number to generate the MAC address */ + memcpy(dev->dev_addr, "\xFE\xFC\x00\x00\x00\x00", 6); + get_random_bytes(&hw_addr, sizeof(hw_addr)); + *(int *)(dev->dev_addr + 2) += hw_addr; +} +#endif + + + +/*__KERNEL__*/ +#endif + +/*_WANPIPE_X25_HEADER_*/ +#endif + + + +#define WPLIP_ASSERT(reg,ret) if (!(reg)) {\ + DEBUG_EVENT("%s:%d Assert Error!\n", \ + __FUNCTION__,__LINE__); \ + return ret; \ + } + +#define WPLIP_ASSERT_VOID(reg) if (!(reg)) {\ + DEBUG_EVENT("%s:%d Assert Error!\n", \ + __FUNCTION__,__LINE__); \ + return; \ + } + +#define FUNC_BEGIN() DEBUG_EVENT("%s:%d ---Begin---\n",__FUNCTION__,__LINE__); +#define FUNC_END() DEBUG_EVENT("%s:%d ---End---\n\n",__FUNCTION__,__LINE__); + + +#define X25_DEBUG_MEM + +#ifdef X25_DEBUG_MEM + + #define X25_SKB_DEC(x) atomic_sub(x,&x25_skb_alloc) + #define X25_SKB_INC(x) atomic_add(x,&x25_skb_alloc) + + #define ALLOC_SKB(skb,len) { skb = dev_alloc_skb(len); \ + if (skb != NULL){ X25_SKB_INC(skb->truesize);}else{ WAN_MEM_ASSERT("X25");} } + #define KFREE_SKB(skb) { X25_SKB_DEC(skb->truesize); dev_kfree_skb_any(skb); } + + + #define X25_MEM_DEC(x) atomic_sub(x,&x25_mem_alloc) + #define X25_MEM_INC(x) atomic_add(x,&x25_mem_alloc) + + #define KMALLOC(ptr,len,flag) { ptr=kmalloc(len, flag); \ + if (ptr != NULL){ X25_MEM_INC(len);} else {WAN_MEM_ASSERT("X25");}} + #define KFREE(ptr) {X25_MEM_DEC(sizeof(*ptr)); kfree(ptr);} + +#else + #define KMALLOC(ptr,len,flag) ptr=kmalloc(len, flag) + #define KFREE(ptr) kfree(ptr) + + #define ALLOC_SKB(new_skb,len, dsp) new_skb = dev_alloc_skb(len) + #define KFREE_SKB(skb) dev_kfree_skb_any(skb) + + #define X25_SKB_DEC(x) + #define X25_SKB_INC(x) + #define X25_MEM_DEC(x) + #define X25_MEM_INC(x) +#endif + +#define is_digit(ch) (((ch)>=(unsigned)'0'&&(ch)<=(unsigned)'9')?1:0) diff -Nur linux.org/include/linux/wanpipe_lip_kernel.h linux-2.6.17/include/linux/wanpipe_lip_kernel.h --- linux.org/include/linux/wanpipe_lip_kernel.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/wanpipe_lip_kernel.h 2006-08-30 10:07:15.000000000 +0000 @@ -0,0 +1,58 @@ +/***************************************************************************** +* wanpipe_lip_kernel.h +* +* Header file for the Sangoma lip network layer +* +* Author: Nenad Corbic +* +* Copyright: (c) 2004 Sangoma Technologies Inc. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version +* 2 of the License, or (at your option) any later version. +* ============================================================================ +* +* Feb 16, 2004 Nenad Corbic Initial Version +* +*****************************************************************************/ + +#ifndef __WP_LIP_KERNEL_H_ +#define __WP_LIP_KERNEL_H + +typedef struct wplip_reg +{ + unsigned long init; + + int (*wplip_register) (void**,wanif_conf_t *,char *); + int (*wplip_prot_reg) (void*, char*, wanif_conf_t *); + int (*wplip_prot_unreg) (void*, char*); + + int (*wplip_bind_link) (void*, netdevice_t *); + int (*wplip_unbind_link) (void*, netdevice_t *); + + int (*wplip_if_reg) (void*, char*, wanif_conf_t *); + int (*wplip_if_unreg) (netdevice_t *); + + void (*wplip_disconnect) (void*, int); + void (*wplip_connect) (void*, int); + + int (*wplip_rx) (void*, void *); + void (*wplip_kick) (void*, int); + + int (*wplip_unreg) (void*); + + int (*wplip_get_if_status) (void *, void *); + +}wplip_reg_t; + + +enum { + LIP_RAW, + LIP_FRAME_RELAY, + LIP_PPP, + LIP_CHDLC, +}; + +#endif +/* __WP_LIP_KERNEL_H_ */ diff -Nur linux.org/include/linux/wanpipe_pchdlc_iface.h linux-2.6.17/include/linux/wanpipe_pchdlc_iface.h --- linux.org/include/linux/wanpipe_pchdlc_iface.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/wanpipe_pchdlc_iface.h 2006-08-30 10:07:15.000000000 +0000 @@ -0,0 +1,33 @@ + +#ifndef __PCHDLC_H__ +#define __PCHDLC_H__ + + + +void *wp_register_sppp_prot(void *link_ptr, char *devname, + wan_sppp_if_conf_t *cfg, + wp_sppp_reg_t *prot_reg); + + + +extern void wp_sppp_attach (struct ppp_device *pd); +extern void wp_sppp_detach (struct net_device *dev); +extern void wp_sppp_input (struct net_device *dev, struct sk_buff *m); +extern int wp_sppp_do_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd); +extern struct sk_buff *sppp_dequeue (struct net_device *dev); +extern int sppp_isempty (struct net_device *dev); +extern void sppp_flush (struct net_device *dev); +extern int wp_sppp_open (struct net_device *dev); +extern int wp_sppp_reopen (struct net_device *dev); +extern int wp_sppp_close (struct net_device *dev); + + + + + + + + + +#endif + diff -Nur linux.org/include/linux/wanpipe_snmp.h linux-2.6.17/include/linux/wanpipe_snmp.h --- linux.org/include/linux/wanpipe_snmp.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/wanpipe_snmp.h 2006-08-30 10:07:15.000000000 +0000 @@ -0,0 +1,242 @@ +/***************************************************************************** +* wansnmp.h Definitions for the WAN SNMP. +* +* Author: Alex Feldman +* +* ============================================================================ +* Aug 20, 2001 Alex Feldman Initial version. +* This version includes SNMP mibs for Frame Relay, +* PPP and X25 (v-1.0.1). +* +* Apr 10, 2003 Alex Feldman Add support SNMP mib for DS1 (v-1.0.4). +* +*/ + +#ifndef __WANSNMP_H +# define __WANSNMP_H + +#define WANPIPE_SNMP_VERSION "1.0.4" + +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined (__OpenBSD__) +# define SIOC_WANPIPE_SNMP _IOWR('i', 100, struct ifreq) +# define SIOC_WANPIPE_SNMP_IFSPEED _IOWR('i', 101, struct ifreq) +#else +//# include +#endif + +#define SNMP_READ 1 +#define SNMP_WRITE 2 + +/* + ******************************************************************** + * X.25 + */ +#define X25_STATION_DECODE(station) \ + (station == WANOPT_DTE) ? "DTE" : \ + (station == WANOPT_DCE) ? "DCE" : "DXE" + +/* + * SNMP X.25 defines + */ +#define SNMP_X25_DTE 1 +#define SNMP_X25_DCE 2 +#define SNMP_X25_DXE 3 + +#define SNMP_X25_MODULO8 1 +#define SNMP_X25_MODULO128 2 + +#define SNMP_X25_INCOMING 1 +#define SNMP_X25_OUTGOING 2 +#define SNMP_X25_PVC 3 + +/* x25CallParmAcceptReverseCharging */ +#define SNMP_X25_ARC_DEFAULT 1 +#define SNMP_X25_ARC_ACCEPT 2 +#define SNMP_X25_ARC_REFUSE 3 +#define SNMP_X25_ARC_NEVERACCEPT 4 + +/* x25CallParmProposeReverseCharging */ +#define SNMP_X25_PRC_DEFAULT 1 +#define SNMP_X25_PRC_REVERSE 2 +#define SNMP_X25_PRC_LOCAL 3 + +/* x25CallParmFastSelecet */ +#define SNMP_X25_FS_DEFAULT 1 +#define SNMP_X25_FS_NOTSPECIFIED 2 +#define SNMP_X25_FS_FASTSELECT 3 +#define SNMP_X25_FS_RESTRICTEDFASTRESP 4 +#define SNMP_X25_FS_NOFASTSELECT 5 +#define SNMP_X25_FS_NORESTRICTEDFASTSEL 6 + +/* x25CallParmInThruPutClassSize */ +/* x25CallParmOutThruPutClassSize */ +#define SNMP_X25_THRUCLASS_TCRES1 1 +#define SNMP_X25_THRUCLASS_TCRES2 2 +#define SNMP_X25_THRUCLASS_TC75 3 +#define SNMP_X25_THRUCLASS_TC150 4 +#define SNMP_X25_THRUCLASS_TC300 5 +#define SNMP_X25_THRUCLASS_TC600 6 +#define SNMP_X25_THRUCLASS_TC1200 7 +#define SNMP_X25_THRUCLASS_TC2400 8 +#define SNMP_X25_THRUCLASS_TC4800 9 +#define SNMP_X25_THRUCLASS_TC9600 10 +#define SNMP_X25_THRUCLASS_TC19200 11 +#define SNMP_X25_THRUCLASS_TC48000 12 +#define SNMP_X25_THRUCLASS_TC64000 13 +#define SNMP_X25_THRUCLASS_TCRES14 14 +#define SNMP_X25_THRUCLASS_TCRES15 15 +#define SNMP_X25_THRUCLASS_TCRES16 16 +#define SNMP_X25_THRUCLASS_TCNONE 17 +#define SNMP_X25_THRUCLASS_TCDEF 18 + +/* x25CallParmChargingInfo */ +#define SNMP_X25_CHARGINGINFO_DEF 1 +#define SNMP_X25_CHARGINGINFO_NOFACL 2 +#define SNMP_X25_CHARGINGINFO_NOCHRGINFO 3 +#define SNMP_X25_CHARGINGINFO_CHARGINFO 4 + +/* x25CallParmExptData */ +#define SNMP_X25_EXPTDATA_DEFULT 1 +#define SNMP_X25_EXPTDATA_NOEXPTDATA 2 +#define SNMP_X25_EXPTDATA_EXPTDATA 3 + +#define SNMP_X25_MAX_CIRCUIT_NUM 4096 +/* + ******************************************************************** + * Frame Relay + */ +#define FR_STATION_DECODE(station) \ + (station == WANOPT_CPE) ? "CPE" : "Node" + +/* + * SNMP defines + */ +#define SNMP_FR_UNICAST 1 +#define SNMP_FR_ONEWAY 2 +#define SNMP_FR_TWOWAY 3 +#define SNMP_FR_NWAY 4 + +#define SNMP_FR_STATIC 1 +#define SNMP_FR_DYNAMIC 2 + +#define SNMP_FR_INVALID 1 +#define SNMP_FR_ACTIVE 2 +#define SNMP_FR_INACTIVE 3 + +#define SNMP_FR_NOLMICONF 1 +#define SNMP_FR_LMIREV 2 +#define SNMP_FR_ANSIT1617D 3 +#define SNMP_FR_ANSIT1617B 4 +#define SNMP_FR_ITUT933A 5 +#define SNMP_FR_ANSIT1617D1994 6 + +#define SNMP_FR_Q921_ADDR 1 +#define SNMP_FR_Q922MARCH90 2 +#define SNMP_FR_Q922NOV90 3 +#define SNMP_FR_Q922 4 + +#define SNMP_FR_2BYTE_ADDR 2 +#define SNMP_FR_3BYTE_ADDR 3 +#define SNMP_FR_4BYTE_ADDR 4 + +#define SNMP_FR_NONBROADCAST 1 +#define SNMP_FR_BROADCAST 2 + +#define SNMP_FR_RUNNING 1 +#define SNMP_FR_FAULT 2 +#define SNMP_FR_INITIALIZING 3 + +#define SNMP_FR_ENABLED 1 +#define SNMP_FR_DISABLED 2 + +#define SNMP_FR_UNKNOWNERR 1 +#define SNMP_FR_RECEIVESHORT 2 +#define SNMP_FR_RECEIVELONG 3 +#define SNMP_FR_ILLEGALADDR 4 +#define SNMP_FR_UNKNOWNADDR 5 +#define SNMP_FR_DLCMIPROTOERR 6 +#define SNMP_FR_DLCMIUNKNOWNERR 7 +#define SNMP_FR_DLCMISEQERR 8 +#define SNMP_FR_DLCMIUNKNOWNRPT 9 +#define SNMP_FR_NOERRSINCERESET 10 + +#define SNMP_FR_ERRDATA_LEN 1600 + + +/* + ******************************************************************** + * Point-to-Point + */ + +#define SNMP_PPP_IPOPENED 1 +#define SNMP_PPP_IPNOTOPENED 2 + +#define SNMP_PPP_COMPR_PROT_NONE 1 +#define SNMP_PPP_COMPR_PROT_VJ_TCP 2 + + +/* + ******************************************************************** + * T1/E1 + */ +#define SNMP_DSX1_NOALARM 1 +#define SNMP_DSX1_RCVFARENDLOF 2 +#define SNMP_DSX1_XMTFARENDLOF 4 +#define SNMP_DSX1_RCVAIS 8 +#define SNMP_DSX1_XMTAIS 16 +#define SNMP_DSX1_LOSSOFFRAME 32 +#define SNMP_DSX1_LOSSOFSIGNAL 64 +#define SNMP_DSX1_LOOPBACKSTATE 128 +#define SNMP_DSX1_T16AIS 2568 +#define SNMP_DSX1_RCVFARENDLOMF 512 +#define SNMP_DSX1_XMTFARENDLOMF 1024 +#define SNMP_DSX1_RCVTESTCODE 2048 +#define SNMP_DSX1_OTHERFAILURE 4096 +#define SNMP_DSX1_UNAVAILSIGSTATE 8192 +#define SNMP_DSX1_NETEUIPOOS 16384 +#define SNMP_DSX1_RCVPAYLOADAIS 32768 +#define SNMP_DSX1_DS2PERFTHRESHOLD 65536 + +/* + ******************************************************************** + * Common Defines + */ +#ifndef MAX_OID_LEN +# define MAX_OID_LEN 128 +#endif + +/* +***************************************************************************** + TYPEDEF/STRUCTURES +****************************************************************************** +*/ +/* SNMP */ +#define snmp_val value.val +#define snmp_data value.data + +typedef struct wanpipe_snmp +{ + int snmp_namelen; + unsigned char snmp_name[MAX_OID_LEN]; + int snmp_cmd; + int snmp_magic; + union { + long val; + char data[1024]; + } value; +} wanpipe_snmp_t; + + +#if !defined(WANLIP_DRIVER) + +#define SNMP_FR_SET_ERR(chan, type, data, len) {struct timeval tv; \ + do_gettimeofday(&tv); \ + chan->err_type = type; \ + memcpy(chan->err_data, data, len); \ + chan->err_time = tv.tv_sec; \ + chan->err_faults++;} + +#endif + + +#endif /* __WANSNMP_H */ diff -Nur linux.org/include/linux/wanpipe_sppp_iface.h linux-2.6.17/include/linux/wanpipe_sppp_iface.h --- linux.org/include/linux/wanpipe_sppp_iface.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/wanpipe_sppp_iface.h 2006-08-30 10:07:15.000000000 +0000 @@ -0,0 +1,416 @@ +/* + * These are the public elements of the Linux sppp module. + */ + +#ifndef _WP_SPPP_IFACE_H +#define _WP_SPPP_IFACE_H + +#ifdef WANLIP_DRIVER + +enum sppp_ioctl_cmds { + SIOCG_SPPP_CONF, + SIOCS_SPPP_NEW_X25_CONF, + SIOCS_SPPP_DEL_X25_CONF, + SIOCG_SPPP_STATUS, +}; + +extern void *wp_register_chdlc_prot(void *, + char *, + void *, + wplip_prot_reg_t *); +extern void *wp_register_ppp_prot(void *, + char *, + void *, + wplip_prot_reg_t *); + +extern int wp_unregister_sppp_prot(void *); + +extern void *wp_register_sppp_chan(void *if_ptr, + void *prot_ptr, + char *devname, + void *cfg_ptr, + unsigned char type); + +extern int wp_unregister_sppp_chan(void *chan_ptr); + +extern int wp_sppp_open(void *sppp_ptr); +extern int wp_sppp_close(void *sppp_ptr); +extern int wp_sppp_rx(void *sppp_ptr, void *skb); +extern int wp_sppp_bh(void *sppp_ptr); +extern int wp_sppp_tx(void *sppp_ptr, void *skb, int type); +extern int wp_sppp_timer(void *sppp_ptr, unsigned int *period, unsigned int carrier_reliable); +extern int wp_sppp_pipemon(void *sppp, int cmd, int addr, unsigned char* data, unsigned int *len); +extern int wp_sppp_task(void *sppp_ptr); + +#endif + + +/*===================================================== + * PPP Commands and Statistics + *====================================================*/ + +/* 'command' field defines */ +#define PPP_READ_CODE_VERSION 0x10 /* configuration commands */ +#define PPP_SET_CONFIG 0x05 +#define PPP_READ_CONFIG 0x06 +#define PPP_SET_INTR_FLAGS 0x20 +#define PPP_READ_INTR_FLAGS 0x21 +#define PPP_SET_INBOUND_AUTH 0x30 +#define PPP_SET_OUTBOUND_AUTH 0x31 +#define PPP_GET_CONNECTION_INFO 0x32 +#define PPP_GET_LINK_STATUS 0x34 + +#define PPP_COMM_ENABLE 0x03 /* operational commands */ +#define PPP_COMM_DISABLE 0x04 +#define PPP_SEND_SIGN_FRAME 0x23 +#define PPP_READ_SIGN_RESPONSE 0x24 +#define PPP_DATALINE_MONITOR 0x33 + +#define PPP_READ_STATISTICS 0x07 /* statistics commands */ +#define PPP_FLUSH_STATISTICS 0x08 +#define PPP_READ_ERROR_STATS 0x09 +#define PPP_FLUSH_ERROR_STATS 0x0A +#define PPP_READ_PACKET_STATS 0x12 +#define PPP_FLUSH_PACKET_STATS 0x13 +#define PPP_READ_LCP_STATS 0x14 +#define PPP_FLUSH_LCP_STATS 0x15 +#define PPP_READ_LPBK_STATS 0x16 +#define PPP_FLUSH_LPBK_STATS 0x17 +#define PPP_READ_IPCP_STATS 0x18 +#define PPP_FLUSH_IPCP_STATS 0x19 +#define PPP_READ_IPXCP_STATS 0x1A +#define PPP_FLUSH_IPXCP_STATS 0x1B +#define PPP_READ_PAP_STATS 0x1C +#define PPP_FLUSH_PAP_STATS 0x1D +#define PPP_READ_CHAP_STATS 0x1E +#define PPP_FLUSH_CHAP_STATS 0x1F + +#pragma pack(1) +/*---------------------------------------------------------------------------- + * Packet Statistics (returned by the PPP_READ_PACKET_STATS command). + */ +typedef struct ppp_pkt_stats +{ + unsigned short rx_bad_header ; /* 00: */ + unsigned short rx_prot_unknwn ; /* 02: */ + unsigned short rx_too_large ; /* 04: */ + unsigned short rx_lcp ; /* 06: */ + unsigned short tx_lcp ; /* 08: */ + unsigned short rx_ipcp ; /* 0A: */ + unsigned short tx_ipcp ; /* 0C: */ + unsigned short rx_ipxcp ; /* 0E: */ + unsigned short tx_ipxcp ; /* 10: */ + unsigned short rx_pap ; /* 12: */ + unsigned short tx_pap ; /* 14: */ + unsigned short rx_chap ; /* 16: */ + unsigned short tx_chap ; /* 18: */ + unsigned short rx_lqr ; /* 1A: */ + unsigned short tx_lqr ; /* 1C: */ + unsigned short rx_ip ; /* 1E: */ + unsigned short tx_ip ; /* 20: */ + unsigned short rx_ipx ; /* 22: */ + unsigned short tx_ipx ; /* 24: */ + unsigned short rx_ipv6cp ; /* 26: */ + unsigned short tx_ipv6cp ; /* 28: */ + unsigned short rx_ipv6 ; /* 2A: */ + unsigned short tx_ipv6 ; /* 2C: */ +} ppp_pkt_stats_t; + +/*---------------------------------------------------------------------------- + * LCP Statistics (returned by the PPP_READ_LCP_STATS command). + */ +typedef struct ppp_lcp_stats +{ + unsigned short rx_unknown ; /* 00: unknown LCP type */ + unsigned short rx_conf_rqst ; /* 02: Configure-Request */ + unsigned short rx_conf_ack ; /* 04: Configure-Ack */ + unsigned short rx_conf_nak ; /* 06: Configure-Nak */ + unsigned short rx_conf_rej ; /* 08: Configure-Reject */ + unsigned short rx_term_rqst ; /* 0A: Terminate-Request */ + unsigned short rx_term_ack ; /* 0C: Terminate-Ack */ + unsigned short rx_code_rej ; /* 0E: Code-Reject */ + unsigned short rx_proto_rej ; /* 10: Protocol-Reject */ + unsigned short rx_echo_rqst ; /* 12: Echo-Request */ + unsigned short rx_echo_reply ; /* 14: Echo-Reply */ + unsigned short rx_disc_rqst ; /* 16: Discard-Request */ + unsigned short tx_conf_rqst ; /* 18: Configure-Request */ + unsigned short tx_conf_ack ; /* 1A: Configure-Ack */ + unsigned short tx_conf_nak ; /* 1C: Configure-Nak */ + unsigned short tx_conf_rej ; /* 1E: Configure-Reject */ + unsigned short tx_term_rqst ; /* 20: Terminate-Request */ + unsigned short tx_term_ack ; /* 22: Terminate-Ack */ + unsigned short tx_code_rej ; /* 24: Code-Reject */ + unsigned short tx_proto_rej ; /* 26: Protocol-Reject */ + unsigned short tx_echo_rqst ; /* 28: Echo-Request */ + unsigned short tx_echo_reply ; /* 2A: Echo-Reply */ + unsigned short tx_disc_rqst ; /* 2E: Discard-Request */ + unsigned short rx_too_large ; /* 30: packets too large */ + unsigned short rx_ack_inval ; /* 32: invalid Conf-Ack */ + unsigned short rx_rej_inval ; /* 34: invalid Conf-Reject */ + unsigned short rx_rej_badid ; /* 36: Conf-Reject w/bad ID */ +} ppp_lcp_stats_t; + +/*---------------------------------------------------------------------------- + * Loopback Error Statistics (returned by the PPP_READ_LPBK_STATS command). + */ +typedef struct ppp_lpbk_stats +{ + unsigned short conf_magic ; /* 00: */ + unsigned short loc_echo_rqst ; /* 02: */ + unsigned short rem_echo_rqst ; /* 04: */ + unsigned short loc_echo_reply ; /* 06: */ + unsigned short rem_echo_reply ; /* 08: */ + unsigned short loc_disc_rqst ; /* 0A: */ + unsigned short rem_disc_rqst ; /* 0C: */ + unsigned short echo_tx_collsn ; /* 0E: */ + unsigned short echo_rx_collsn ; /* 10: */ +} ppp_lpbk_stats_t; + +/*---------------------------------------------------------------------------- + * Protocol Statistics (returned by the PPP_READ_IPCP_STATS and + * PPP_READ_IPXCP_STATS commands). + */ +typedef struct ppp_prot_stats +{ + unsigned short rx_unknown ; /* 00: unknown type */ + unsigned short rx_conf_rqst ; /* 02: Configure-Request */ + unsigned short rx_conf_ack ; /* 04: Configure-Ack */ + unsigned short rx_conf_nak ; /* 06: Configure-Nak */ + unsigned short rx_conf_rej ; /* 08: Configure-Reject */ + unsigned short rx_term_rqst ; /* 0A: Terminate-Request */ + unsigned short rx_term_ack ; /* 0C: Terminate-Ack */ + unsigned short rx_code_rej ; /* 0E: Code-Reject */ + unsigned short reserved ; /* 10: */ + unsigned short tx_conf_rqst ; /* 12: Configure-Request */ + unsigned short tx_conf_ack ; /* 14: Configure-Ack */ + unsigned short tx_conf_nak ; /* 16: Configure-Nak */ + unsigned short tx_conf_rej ; /* 18: Configure-Reject */ + unsigned short tx_term_rqst ; /* 1A: Terminate-Request */ + unsigned short tx_term_ack ; /* 1C: Terminate-Ack */ + unsigned short tx_code_rej ; /* 1E: Code-Reject */ + unsigned short rx_too_large ; /* 20: packets too large */ + unsigned short rx_ack_inval ; /* 22: invalid Conf-Ack */ + unsigned short rx_rej_inval ; /* 24: invalid Conf-Reject */ + unsigned short rx_rej_badid ; /* 26: Conf-Reject w/bad ID */ +} ppp_prot_stats_t; + +/*---------------------------------------------------------------------------- + * PAP Statistics (returned by the PPP_READ_PAP_STATS command). + */ +typedef struct ppp_pap_stats +{ + unsigned short rx_unknown ; /* 00: unknown type */ + unsigned short rx_auth_rqst ; /* 02: Authenticate-Request */ + unsigned short rx_auth_ack ; /* 04: Authenticate-Ack */ + unsigned short rx_auth_nak ; /* 06: Authenticate-Nak */ + unsigned short reserved ; /* 08: */ + unsigned short tx_auth_rqst ; /* 0A: Authenticate-Request */ + unsigned short tx_auth_ack ; /* 0C: Authenticate-Ack */ + unsigned short tx_auth_nak ; /* 0E: Authenticate-Nak */ + unsigned short rx_too_large ; /* 10: packets too large */ + unsigned short rx_bad_peerid ; /* 12: invalid peer ID */ + unsigned short rx_bad_passwd ; /* 14: invalid password */ +} ppp_pap_stats_t; + +/*---------------------------------------------------------------------------- + * CHAP Statistics (returned by the PPP_READ_CHAP_STATS command). + */ +typedef struct ppp_chap_stats +{ + unsigned short rx_unknown ; /* 00: unknown type */ + unsigned short rx_challenge ; /* 02: Authenticate-Request */ + unsigned short rx_response ; /* 04: Authenticate-Ack */ + unsigned short rx_success ; /* 06: Authenticate-Nak */ + unsigned short rx_failure ; /* 08: Authenticate-Nak */ + unsigned short reserved ; /* 0A: */ + unsigned short tx_challenge ; /* 0C: Authenticate-Request */ + unsigned short tx_response ; /* 0E: Authenticate-Ack */ + unsigned short tx_success ; /* 10: Authenticate-Nak */ + unsigned short tx_failure ; /* 12: Authenticate-Nak */ + unsigned short rx_too_large ; /* 14: packets too large */ + unsigned short rx_bad_peerid ; /* 16: invalid peer ID */ + unsigned short rx_bad_passwd ; /* 18: invalid password */ + unsigned short rx_bad_md5 ; /* 1A: invalid MD5 format */ + unsigned short rx_bad_resp ; /* 1C: invalid response */ +} ppp_chap_stats_t; + +/*---------------------------------------------------------------------------- + * Connection Information (returned by the PPP_GET_CONNECTION_INFO command). + */ +typedef struct ppp_conn_info +{ + unsigned short remote_mru ; /* 00: */ + unsigned char ip_options ; /* 02: */ + unsigned char ip_local[4] ; /* 03: */ + unsigned char ip_remote[4] ; /* 07: */ + unsigned char ipx_options ; /* 0B: */ + unsigned char ipx_network[4] ; /* 0C: */ + unsigned char ipx_local[6] ; /* 10: */ + unsigned char ipx_remote[6] ; /* 16: */ + unsigned char ipx_router[48] ; /* 1C: */ + unsigned char auth_status ; /* 4C: */ + unsigned char peer_id[0] ; /* 4D: */ +} ppp_conn_info_t; + +#pragma pack() + +/*===================================================== + * CHDLC Commands and Statistics + *====================================================*/ + +#define READ_CHDLC_OPERATIONAL_STATS 0x27 +#define FLUSH_CHDLC_OPERATIONAL_STATS 0x28 +#define READ_GLOBAL_CONFIGURATION 0x03 +#define READ_CHDLC_CODE_VERSION 0x20 +#define READ_CHDLC_CONFIGURATION 0x23 + + +/* ---------------------------------------------------------------------------- + * Constants for the READ_CHDLC_OPERATIONAL_STATS command + * --------------------------------------------------------------------------*/ + +#pragma pack(1) + +/* the CHDLC operational statistics structure */ +typedef struct { + + /* Data frame transmission statistics */ + unsigned int Data_frames_Tx_count ; + /* # of frames transmitted */ + unsigned int Data_bytes_Tx_count ; + /* # of bytes transmitted */ + unsigned int Data_Tx_throughput ; + /* transmit throughput */ + unsigned int no_ms_for_Data_Tx_thruput_comp ; + /* millisecond time used for the Tx throughput computation */ + unsigned int Tx_Data_discard_lgth_err_count ; + /* number of Data frames discarded (length error) */ + unsigned int reserved_Data_frm_Tx_stat1 ; + /* reserved for later */ + unsigned int reserved_Data_frm_Tx_stat2 ; + /* reserved for later */ + unsigned int reserved_Data_frm_Tx_stat3 ; + /* reserved for later */ + + /* Data frame reception statistics */ + unsigned int Data_frames_Rx_count ; + /* number of frames received */ + unsigned int Data_bytes_Rx_count ; + /* number of bytes received */ + unsigned int Data_Rx_throughput ; + /* receive throughput */ + unsigned int no_ms_for_Data_Rx_thruput_comp ; + /* millisecond time used for the Rx throughput computation */ + unsigned int Rx_Data_discard_short_count ; + /* received Data frames discarded (too short) */ + unsigned int Rx_Data_discard_long_count ; + /* received Data frames discarded (too long) */ + unsigned int Rx_Data_discard_inactive_count ; + /* received Data frames discarded (link inactive) */ + unsigned int reserved_Data_frm_Rx_stat1 ; + /* reserved for later */ + + /* SLARP frame transmission/reception statistics */ + /* number of SLARP Request frames transmitted */ + unsigned int CHDLC_SLARP_REQ_Tx_count ; + /* number of SLARP Request frames received */ + unsigned int CHDLC_SLARP_REQ_Rx_count ; + /* number of SLARP Reply frames transmitted */ + unsigned int CHDLC_SLARP_REPLY_Tx_count ; + /* number of SLARP Reply frames received */ + unsigned int CHDLC_SLARP_REPLY_Rx_count ; + /* number of SLARP keepalive frames transmitted */ + unsigned int CHDLC_SLARP_KPALV_Tx_count ; + /* number of SLARP keepalive frames received */ + unsigned int CHDLC_SLARP_KPALV_Rx_count ; + /* reserved for later */ + unsigned int reserved_SLARP_stat1 ; + /* reserved for later */ + unsigned int reserved_SLARP_stat2 ; + + /* CDP frame transmission/reception statistics */ + unsigned int CHDLC_CDP_Tx_count ; + /* number of CDP frames transmitted */ + unsigned int CHDLC_CDP_Rx_count ; + /* number of CDP frames received */ + unsigned int reserved_CDP_stat1 ; + /* reserved for later */ + unsigned int reserved_CDP_stat2 ; + /* reserved for later */ + unsigned int reserved_CDP_stat3 ; + /* reserved for later */ + unsigned int reserved_CDP_stat4 ; + /* reserved for later */ + unsigned int reserved_CDP_stat5 ; + /* reserved for later */ + unsigned int reserved_CDP_stat6 ; + /* reserved for later */ + + /* Incomming frames with a format error statistics */ + unsigned short Rx_frm_incomp_CHDLC_hdr_count ; + /* frames received of with incomplete Cisco HDLC header */ + unsigned short Rx_frms_too_long_count ; + /* frames received of excessive length count */ + unsigned short Rx_invalid_CHDLC_addr_count ; + /* frames received with an invalid CHDLC address count */ + unsigned short Rx_invalid_CHDLC_ctrl_count ; + /* frames received with an invalid CHDLC control field count */ + unsigned short Rx_invalid_CHDLC_type_count ; + /* frames received of an invalid CHDLC frame type count */ + unsigned short Rx_SLARP_invalid_code_count ; + /* SLARP frame received with an invalid packet code */ + unsigned short Rx_SLARP_Reply_bad_IP_addr ; + /* SLARP Reply received - bad IP address */ + unsigned short Rx_SLARP_Reply_bad_netmask ; + /* SLARP Reply received - bad netmask */ + unsigned int reserved_frm_format_err1 ; + /* reserved for later */ + unsigned int reserved_frm_format_err2 ; + /* reserved for later */ + unsigned int reserved_frm_format_err3 ; + /* reserved for later */ + unsigned int reserved_frm_format_err4 ; + /* reserved for later */ + + /* CHDLC timeout/retry statistics */ + unsigned short SLARP_Rx_keepalive_TO_count ; + /* timeout count for incomming SLARP frames */ + unsigned short SLARP_Request_TO_count ; + /* timeout count for SLARP Request frames */ + unsigned int To_retry_reserved_stat1 ; + /* reserved for later */ + unsigned int To_retry_reserved_stat2 ; + /* reserved for later */ + unsigned int To_retry_reserved_stat3 ; + /* reserved for later */ + + /* CHDLC link active/inactive and loopback statistics */ + unsigned short link_active_count ; + /* number of times that the link went active */ + unsigned short link_inactive_modem_count ; + /* number of times that the link went inactive (modem failure) */ + unsigned short link_inactive_keepalive_count ; + /* number of times that the link went inactive (keepalive failure) */ + unsigned short link_looped_count ; + /* link looped count */ + unsigned int link_status_reserved_stat1 ; + /* reserved for later use */ + unsigned int link_status_reserved_stat2 ; + /* reserved for later use */ + + /* miscellaneous statistics */ + unsigned int reserved_misc_stat1 ; + /* reserved for later */ + unsigned int reserved_misc_stat2 ; + /* reserved for later */ + unsigned int reserved_misc_stat3 ; + /* reserved for later */ + unsigned int reserved_misc_stat4 ; + /* reserved for later */ + +} CHDLC_OPERATIONAL_STATS_STRUCT, chdlc_stat_t; + +#pragma pack() + + +#endif diff -Nur linux.org/include/linux/wanpipe_syncppp.h linux-2.6.17/include/linux/wanpipe_syncppp.h --- linux.org/include/linux/wanpipe_syncppp.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/wanpipe_syncppp.h 2006-08-30 10:07:15.000000000 +0000 @@ -0,0 +1,306 @@ +/* + * Defines for synchronous PPP/Cisco link level subroutines. + * + * Copyright (C) 1994 Cronyx Ltd. + * Author: Serge Vakulenko, + * + * This software is distributed with NO WARRANTIES, not even the implied + * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Authors grant any other persons or organizations permission to use + * or modify this software as long as this message is kept with the software, + * all derivative works or modified versions. + * + * Version 1.7, Wed Jun 7 22:12:02 MSD 1995 + * + * Version 2.1, Wed Mar 26 10:03:00 EDT 2003 + * + * + */ + +/* + * + * Changes: v2.1 by David Rokhvarg + * + * Changed for use by Sangoma WANPIPE driver. Added MD5 algorithm + * declarations. + * + */ + +#ifndef _SYNCPPP_H_ +#define _SYNCPPP_H_ 1 + +#ifdef __KERNEL__ + +#define PPP_ALLSTATIONS 0xff /* All-Stations broadcast address */ +#define PPP_UI 0x03 /* Unnumbered Information */ +#define PPP_IP 0x0021 /* Internet Protocol */ +#define PPP_ISO 0x0023 /* ISO OSI Protocol */ +#define PPP_XNS 0x0025 /* Xerox NS Protocol */ +#define PPP_IPX 0x002b /* Novell IPX Protocol */ +#define PPP_LCP 0xc021 /* Link Control Protocol */ +#define PPP_IPCP 0x8021 /* Internet Protocol Control Protocol */ +#define PPP_PAP 0xc023 /* Password Authentication Protocol */ +#define PPP_CHAP 0xc223 /* Challenge-Handshake Auth Protocol */ + +struct slcp { + u16 state; /* state machine */ + u32 magic; /* local magic number */ + u_char echoid; /* id of last keepalive echo request */ + u_char confid; /* id of last configuration request */ + + u32 opts; /* LCP options to send (bitfield) */ + u32 mru; /* our max receive unit */ + u32 their_mru; /* their max receive unit */ + u32 protos; /* bitmask of protos that are started */ + /* restart max values, see RFC 1661 */ + int timeout; + int max_terminate; + int max_configure; + int max_failure; +}; + +struct sipcp { + u16 state; /* state machine */ + u_char confid; /* id of last configuration request */ +}; + +#define IDX_LCP 0 /* idx into state table */ +#define IDX_IPCP 1 /* idx into state table */ +#define IDX_IPV6CP 2 /* idx into state table */ + +#define AUTHNAMELEN 64 +#define AUTHKEYLEN 16 + +struct sauth { + u_short proto; /* authentication protocol to use */ + u_short flags; +#define AUTHFLAG_NOCALLOUT 1 /* do not require authentication on */ + /* callouts */ +#define AUTHFLAG_NORECHALLENGE 2 /* do not re-challenge CHAP */ + u_char name[AUTHNAMELEN]; /* system identification name */ + u_char secret[AUTHKEYLEN]; /* secret password */ + u_char challenge[AUTHKEYLEN]; /* random challenge */ +}; + +#define IDX_PAP 3 +#define IDX_CHAP 4 + +#define IDX_COUNT (IDX_CHAP + 1) /* bump this when adding cp's! */ + +/* + * Don't change the order of this. Ordering the phases this way allows + * for a comparision of ``pp_phase >= PHASE_AUTHENTICATE'' in order to + * know whether LCP is up. + */ +enum ppp_phase { + PHASE_DEAD, PHASE_ESTABLISH, PHASE_TERMINATE, + PHASE_AUTHENTICATE, PHASE_NETWORK +}; + +#define PP_MTU 1500 /* default/minimal MRU */ +#define PP_MAX_MRU 2048 /* maximal MRU we want to negotiate */ + +/* + * This is a cut down struct sppp (see below) that can easily be + * exported to/ imported from userland without the need to include + * dozens of kernel-internal header files. It is used by the + * SPPPIO[GS]DEFS ioctl commands below. + */ +struct sppp_parms { + enum ppp_phase pp_phase; /* phase we're currently in */ + int enable_vj; /* VJ header compression enabled */ + int enable_ipv6; /* + * Enable IPv6 negotiations -- only + * needed since each IPv4 i/f auto- + * matically gets an IPv6 address + * assigned, so we can't use this as + * a decision. + */ + struct slcp lcp; /* LCP params */ + struct sipcp ipcp; /* IPCP params */ + struct sipcp ipv6cp; /* IPv6CP params */ + struct sauth myauth; /* auth params, i'm peer */ + struct sauth hisauth; /* auth params, i'm authenticator */ +}; + +/* + * Definitions to pass struct sppp_parms data down into the kernel + * using the SIOC[SG]IFGENERIC ioctl interface. + * + * In order to use this, create a struct spppreq, fill in the cmd + * field with SPPPIOGDEFS, and put the address of this structure into + * the ifr_data portion of a struct ifreq. Pass this struct to a + * SIOCGIFGENERIC ioctl. Then replace the cmd field by SPPPIOSDEFS, + * modify the defs field as desired, and pass the struct ifreq now + * to a SIOCSIFGENERIC ioctl. + */ + +#define SPPPIOGDEFS ((caddr_t)(('S' << 24) + (1 << 16) +\ + sizeof(struct sppp_parms))) +#define SPPPIOSDEFS ((caddr_t)(('S' << 24) + (2 << 16) +\ + sizeof(struct sppp_parms))) + +struct spppreq { + int cmd; + struct sppp_parms defs; +}; + +/* bits for pp_flags */ +#define PP_KEEPALIVE 0x01 /* use keepalive protocol */ + /* 0x04 was PP_TIMO */ +#define PP_CALLIN 0x08 /* we are being called */ +#define PP_NEEDAUTH 0x10 /* remote requested authentication */ + +struct sppp +{ + struct sppp * pp_next; /* next interface in keepalive list */ + u32 pp_flags; /* use Cisco protocol instead of PPP */ + u16 pp_alivecnt; /* keepalive packets counter */ + u16 pp_loopcnt; /* loopback detection counter */ + //u32 pp_seq; /* local sequence number */ + //u32 pp_rseq; /* remote sequence number */ + struct slcp lcp; /* LCP params */ + struct sipcp ipcp; /* IPCP params */ + u32 ibytes,obytes; /* Bytes in/out */ + u32 ipkts,opkts; /* Packets in/out */ + struct timer_list pp_timer; + struct net_device *pp_if; + char pp_link_state; /* Link status */ + + u32 pp_seq[IDX_COUNT]; /* local sequence number */ + u32 pp_rseq[IDX_COUNT]; /* remote sequence number */ + enum ppp_phase pp_phase; /* phase we're currently in */ + int state[IDX_COUNT]; /* state machine */ + u_char confid[IDX_COUNT]; /* id of last configuration request */ + int rst_counter[IDX_COUNT]; /* restart counter */ + int fail_counter[IDX_COUNT]; /* negotiation failure counter */ + int confflags; /* administrative configuration flags */ +#define CONF_ENABLE_VJ 0x01 /* VJ header compression enabled */ +#define CONF_ENABLE_IPV6 0x02 /* IPv6 administratively enabled */ + time_t pp_last_recv; /* time last packet has been received */ + time_t pp_last_sent; /* time last packet has been sent */ + + struct sauth myauth; /* auth params, i'm peer */ + struct sauth hisauth; /* auth params, i'm authenticator */ + struct timer_list pp_auth_timer; + u32 pp_auth_flags; + + unsigned char dynamic_ip; + unsigned long local_ip; + unsigned long remote_ip; + unsigned char gateway; + + struct tq_struct sppp_task; + unsigned long task_working; + int dynamic_failures; + + unsigned char hwdevname[IFNAMSIZ+1]; +}; + +struct ppp_device +{ + struct net_device *dev; /* Network device pointer */ + struct sppp sppp; /* Synchronous PPP */ +}; + +#include + +static inline struct sppp *sppp_of(netdevice_t *dev) +{ + wanpipe_common_t *chan=dev->priv; + struct ppp_device *pppdev=(struct ppp_device *)chan->prot_ptr; + return &pppdev->sppp; +} + +#if 0 +#define sppp_of(dev) \ + (& \ + ((struct ppp_device *) \ + (\ + ((wanpipe_common_t *)\ + ((dev)->priv)\ + )->prot_ptr\ + )->sppp\ + ) +#endif + +#define PP_KEEPALIVE 0x01 /* use keepalive protocol */ +#define PP_CISCO 0x02 /* use Cisco protocol instead of PPP */ +#define PP_TIMO 0x04 /* cp_timeout routine active */ +#define PP_DEBUG 0x08 +#define PP_TIMO1 0x20 /* one of the authentication timeout routines is active */ + +#define PPP_MTU 1500 /* max. transmit unit */ + +#define LCP_STATE_CLOSED 0 /* LCP state: closed (conf-req sent) */ +#define LCP_STATE_ACK_RCVD 1 /* LCP state: conf-ack received */ +#define LCP_STATE_ACK_SENT 2 /* LCP state: conf-ack sent */ +#define LCP_STATE_OPENED 3 /* LCP state: opened */ + +#define IPCP_STATE_CLOSED 0 /* IPCP state: closed (conf-req sent) */ +#define IPCP_STATE_ACK_RCVD 1 /* IPCP state: conf-ack received */ +#define IPCP_STATE_ACK_SENT 2 /* IPCP state: conf-ack sent */ +#define IPCP_STATE_OPENED 3 /* IPCP state: opened */ + +#define SPPP_LINK_DOWN 0 /* link down - no keepalive */ +#define SPPP_LINK_UP 1 /* link is up - keepalive ok */ + +void wp_sppp_attach (struct ppp_device *pd); +void wp_sppp_detach (struct net_device *dev); +void wp_sppp_input (struct net_device *dev, struct sk_buff *m); +int wp_sppp_do_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd); +struct sk_buff *sppp_dequeue (struct net_device *dev); +int sppp_isempty (struct net_device *dev); +void sppp_flush (struct net_device *dev); +int wp_sppp_open (struct net_device *dev); +int wp_sppp_reopen (struct net_device *dev); +int wp_sppp_close (struct net_device *dev); + +#ifndef wp_min +#define wp_min(x,y) \ + ({ unsigned int __x = (x); unsigned int __y = (y); __x < __y ? __x: __y; }) +#endif + +#ifndef wp_max +#define wp_max(x,y) \ + ({ unsigned int __x = (x); unsigned int __y = (y); __x > __y ? __x: __y; }) +#endif + +#endif + +#define SPPPIOCCISCO (SIOCDEVPRIVATE) +#define SPPPIOCPPP (SIOCDEVPRIVATE+1) +#define SPPPIOCDEBUG (SIOCDEVPRIVATE+2) +#define SPPPIOCSFLAGS (SIOCDEVPRIVATE+3) +#define SPPPIOCGFLAGS (SIOCDEVPRIVATE+4) + + +#define AUTHNAMELEN 64 +#define AUTHKEYLEN 16 + +#include +#ifdef __BIG_ENDIAN +#define WORDS_BIGENDIAN +#endif + +typedef u32 UWORD32; +typedef u32 UINT32; +typedef u8 UINT8; +typedef u16 UINT16; + +#define md5byte unsigned char + +struct wp_MD5Context { + UWORD32 buf[4]; + UWORD32 bytes[2]; + UWORD32 in[16]; +}; + +void wp_MD5Init(struct wp_MD5Context *context); +void wp_MD5Update(struct wp_MD5Context *context, md5byte const *buf, unsigned len); +void wp_MD5Final(unsigned char digest[16], struct wp_MD5Context *context); +void wp_MD5Transform(UWORD32 buf[4], UWORD32 const in[16]); + + +#endif /* _SYNCPPP_H_ */ diff -Nur linux.org/include/linux/wanpipe_tdm_api_ec.h linux-2.6.17/include/linux/wanpipe_tdm_api_ec.h --- linux.org/include/linux/wanpipe_tdm_api_ec.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/wanpipe_tdm_api_ec.h 2006-08-30 10:07:15.000000000 +0000 @@ -0,0 +1,102 @@ +/***************************************************************************** +* wanpipe_tdm_api.c +* +* WANPIPE(tm) AFT TE1 Hardware Support +* +* Authors: Nenad Corbic +* +* Copyright: (c) 2003-2005 Sangoma Technologies Inc. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version +* 2 of the License, or (at your option) any later version. +* ============================================================================ +* Oct 04, 2005 Nenad Corbic Initial version. +*****************************************************************************/ + + +typedef struct wanpipe_tdm_api_ec { + echo_can_state_t *ec; + echo_can_disable_detector_state_t txecdis; + echo_can_disable_detector_state_t rxecdis; + unsigned int echocancel; + unsigned int echostate; + unsigned int echolastupdate; + unsigned int echotimer; + netskb_t *tx_skb; +}wanpipe_tdm_api_ec_t; + + +static __inline void wanpipe_tdm_api_ec_init(wanpipe_tdm_api_ec_t *ec_eng) +{ + netskb_t *skb = ec_eng->tx_skb; + + ec_eng->echostate = ECHO_STATE_IDLE; + ec_eng->echolastupdate = 0; + ec_eng->echotimer = 0; + ec_eng->tx_skb=NULL; + + if (skb) { + wan_skb_free(skb); + } + + return; +} + +static __inline int wanpipe_tdm_api_ec_create (wanpipe_tdm_api_ec_t *ec_eng, int tap_size) +{ + ec_eng->ec = echo_can_create(tap_size, 0); + if (!ec_eng->ec) { + return -EINVAL; + } + ec_eng->echocancel = tap_size; + ec_eng->tx_skb = NULL; + + wanpipe_tdm_api_ec_init (ec_eng); + + echo_can_disable_detector_init(&chan->txecdis); + echo_can_disable_detector_init(&chan->rxecdis); + + return 0; +} + +static __inline int wanpipe_tdm_api_ec_free (wanpipe_tdm_api_ec_t *ec_eng, int tap_size) +{ + echo_can_state_t *ec_tmp=ec_eng->ec; + + wanpipe_tdm_api_ec_init (ec_eng); + ec_eng->echocancel = 0; + ec_eng->ec=NULL; + + if (ec_tmp){ + echo_can_free(ec); + } + + return 0; +} + + +static __inline int wanpipe_tdm_api_ec_train (wanpipe_tdm_api_ec_t *ec_eng, int t_period) +{ + if (ec_eng->ec){ + ec_eng->echostate = ECHO_STATE_PRETRAINING; + ec_eng->echotimer = t_period; + return 0; + } + + return -ENODEV; +} + +static __inline int wanpipe_tdm_api_ec_tx(wanpipe_tdm_api_ec_t *ec_eng, netskb_t *skb) +{ + if (ec_eng->ec){ + if (ec_eng->echostate == ECHO_STATE_STARTTRAINING) { + /* Transmit impulse now */ + *(short*)(wan_skb_data(skb)) = 16384; + ec_eng->echostate = ECHO_STATE_AWAITINGECHO; + } + } + + return 0; +} diff -Nur linux.org/include/linux/wanpipe_tdm_api.h linux-2.6.17/include/linux/wanpipe_tdm_api.h --- linux.org/include/linux/wanpipe_tdm_api.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/wanpipe_tdm_api.h 2006-08-30 10:07:15.000000000 +0000 @@ -0,0 +1,422 @@ +/***************************************************************************** +* wanpipe_tdm_api.h +* +* WANPIPE(tm) AFT TE1 Hardware Support +* +* Authors: Nenad Corbic +* +* Copyright: (c) 2003-2005 Sangoma Technologies Inc. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version +* 2 of the License, or (at your option) any later version. +* ============================================================================ +* Oct 04, 2005 Nenad Corbic Initial version. +*****************************************************************************/ + +#ifndef __WANPIPE_TDM_API_H_ +#define __WANPIPE_TDM_API_H_ + +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) +# include +# include +# include +# include +#else +# include +# include +# include +# include +# include +#endif + +enum wanpipe_tdm_api_cmds { + + SIOC_WP_TDM_GET_USR_MTU_MRU, /* 0x00 */ + + SIOC_WP_TDM_SET_USR_PERIOD, /* 0x01 */ + SIOC_WP_TDM_GET_USR_PERIOD, /* 0x02 */ + + SIOC_WP_TDM_SET_HW_MTU_MRU, /* 0x03 */ + SIOC_WP_TDM_GET_HW_MTU_MRU, /* 0x04 */ + + SIOC_WP_TDM_SET_CODEC, /* 0x05 */ + SIOC_WP_TDM_GET_CODEC, /* 0x06 */ + + SIOC_WP_TDM_SET_POWER_LEVEL, /* 0x07 */ + SIOC_WP_TDM_GET_POWER_LEVEL, /* 0x08 */ + + SIOC_WP_TDM_TOGGLE_RX, /* 0x09 */ + SIOC_WP_TDM_TOGGLE_TX, /* 0x0A */ + + SIOC_WP_TDM_GET_HW_CODING, /* 0x0B */ + SIOC_WP_TDM_SET_HW_CODING, /* 0x0C */ + + SIOC_WP_TDM_GET_FULL_CFG, /* 0x0D */ + + SIOC_WP_TDM_SET_EC_TAP, /* 0x0E */ + SIOC_WP_TDM_GET_EC_TAP, /* 0x0F */ + + SIOC_WP_TDM_ENABLE_RBS_EVENTS, /* 0x10 */ + SIOC_WP_TDM_DISABLE_RBS_EVENTS, /* 0x11 */ + SIOC_WP_TDM_WRITE_RBS_BITS, /* 0x12 */ + + SIOC_WP_TDM_GET_STATS, /* 0x13 */ + SIOC_WP_TDM_FLUSH_BUFFERS, /* 0x14 */ + + SIOC_WP_TDM_READ_EVENT, /* 0x15 */ + + SIOC_WP_TDM_ENABLE_DTMF_EVENTS, /* 0x16 */ + SIOC_WP_TDM_DISABLE_DTMF_EVENTS, /* 0x17 */ + + SIOC_WP_TDM_ENABLE_RM_DTMF_EVENTS, /* 0x18 */ + SIOC_WP_TDM_DISABLE_RM_DTMF_EVENTS, /* 0x19 */ + + SIOC_WP_TDM_ENABLE_RXHOOK_EVENTS, /* 0x1A */ + SIOC_WP_TDM_DISABLE_RXHOOK_EVENTS, /* 0x1B */ + + SIOC_WP_TDM_NOTSUPP /* */ + + +}; + +enum wanpipe_tdm_api_events { + WP_TDM_EVENT_RBS, + WP_TDM_EVENT_DTMF, + WP_TDM_EVENT_NONE, + WP_TDM_EVENT_RXHOOK, + WP_TDM_EVENT_RING +}; + +#define WPTDM_A_BIT WAN_RBS_SIG_A +#define WPTDM_B_BIT WAN_RBS_SIG_B +#define WPTDM_C_BIT WAN_RBS_SIG_C +#define WPTDM_D_BIT WAN_RBS_SIG_D + +typedef struct { + union { + struct { + unsigned char _event_type; + unsigned char _rbs_rx_bits; + unsigned int _time_stamp; + union { + struct { + unsigned char rbs_bits; + }rbs; + struct { + unsigned char state; + }rxhook; + struct { + unsigned char state; + }ring; + struct { + unsigned char digit; /* DTMF: digit */ + unsigned char port; /* DTMF: SOUT/ROUT */ + unsigned char type; /* DTMF: PRESET/STOP */ + }dtmf; + } u_event; + }wp_event; + struct { + unsigned char _rbs_rx_bits; + unsigned int _time_stamp; + }wp_rx; + unsigned char reserved[16]; + }wp_rx_hdr_u; +#define wp_api_event_type wp_rx_hdr_u.wp_event._event_type +#define wp_api_event_rbs_rx_bits wp_rx_hdr_u.wp_event._rbs_rx_bits +#define wp_api_event_time_stamp wp_rx_hdr_u.wp_event._time_stamp +#define wp_api_event_rxhook_state wp_rx_hdr_u.wp_event.u_event.rxhook.state +#define wp_api_event_ring_state wp_rx_hdr_u.wp_event.u_event.ring.state +#define wp_api_event_dtmf_digit wp_rx_hdr_u.wp_event.u_event.dtmf.digit +#define wp_api_event_dtmf_type wp_rx_hdr_u.wp_event.u_event.dtmf.type +#define wp_api_event_dtmf_port wp_rx_hdr_u.wp_event.u_event.dtmf.port +} wp_tdm_api_rx_hdr_t; + +typedef struct { + wp_tdm_api_rx_hdr_t hdr; + unsigned char data[1]; +} wp_tdm_api_rx_element_t; + +typedef struct { + union { + struct { + unsigned char _rbs_rx_bits; + unsigned int _time_stamp; + }wp_tx; + unsigned char reserved[16]; + }wp_tx_hdr_u; +#define wp_api_time_stamp wp_tx_hdr_u.wp_tx._time_stamp +} wp_tdm_api_tx_hdr_t; + +typedef struct { + wp_tdm_api_tx_hdr_t hdr; + unsigned char data[1]; +} wp_tdm_api_tx_element_t; + + + +typedef struct wp_tdm_chan_stats +{ + unsigned int rx_packets; /* total packets received */ + unsigned int tx_packets; /* total packets transmitted */ + unsigned int rx_bytes; /* total bytes received */ + unsigned int tx_bytes; /* total bytes transmitted */ + unsigned int rx_errors; /* bad packets received */ + unsigned int tx_errors; /* packet transmit problems */ + unsigned int rx_dropped; /* no space in linux buffers */ + unsigned int tx_dropped; /* no space available in linux */ + unsigned int multicast; /* multicast packets received */ + unsigned int collisions; + + /* detailed rx_errors: */ + unsigned int rx_length_errors; + unsigned int rx_over_errors; /* receiver ring buff overflow */ + unsigned int rx_crc_errors; /* recved pkt with crc error */ + unsigned int rx_frame_errors; /* recv'd frame alignment error */ + unsigned int rx_fifo_errors; /* recv'r fifo overrun */ + unsigned int rx_missed_errors; /* receiver missed packet */ + + /* detailed tx_errors */ + unsigned int tx_aborted_errors; + unsigned int tx_carrier_errors; + unsigned int tx_fifo_errors; + unsigned int tx_heartbeat_errors; + unsigned int tx_window_errors; + +}wp_tdm_chan_stats_t; + + + +typedef struct wanpipe_tdm_api_cmd{ + + unsigned int cmd; + unsigned int hw_tdm_coding; /* Set/Get HW TDM coding: uLaw muLaw */ + unsigned int hw_mtu_mru; /* Set/Get HW TDM MTU/MRU */ + unsigned int usr_period; /* Set/Get User Period in ms */ + unsigned int tdm_codec; /* Set/Get TDM Codec: SLinear */ + unsigned int power_level; /* Set/Get Power level treshold */ + unsigned int rx_disable; /* Enable/Disable Rx */ + unsigned int tx_disable; /* Enable/Disable Tx */ + unsigned int usr_mtu_mru; /* Set/Get User TDM MTU/MRU */ + unsigned int ec_tap; /* Echo Cancellation Tap */ + unsigned int rbs_poll; /* Enable/Disable RBS Polling */ + unsigned int rbs_rx_bits; /* Rx RBS Bits */ + unsigned int rbs_tx_bits; /* Tx RBS Bits */ + unsigned int hdlc; /* HDLC based device */ + unsigned int idle_flag; /* IDLE flag to Tx */ + wp_tdm_chan_stats_t stats; /* TDM Statistics */ + wp_tdm_api_rx_hdr_t event; /* TDM Event */ + +}wanpipe_tdm_api_cmd_t; + +typedef struct wanpipe_tdm_api_event{ + + int (*wp_rbs_event)(int fd, unsigned char rbs_bits); + int (*wp_dtmf_event)(int fd, unsigned char dtmf, unsigned char type); + int (*wp_rxhook_event)(int fd, unsigned char state); + +}wanpipe_tdm_api_event_t; + +typedef struct wanpipe_tdm_api{ + wanpipe_tdm_api_cmd_t wp_tdm_cmd; + wanpipe_tdm_api_event_t wp_tdm_event; +}wanpipe_tdm_api_t; + + + + +#ifdef WAN_KERNEL + +#define WP_TDM_API_MAX_LEN 1024 +#define WP_TDM_API_CHUNK_SZ 8 + +enum { + WP_TDM_HDLC_TX, + WP_TDM_DOWN +}; + +typedef struct wanpipe_tdm_api_dev { + + u32 init; + void *chan; + void *card; + char name[WAN_IFNAME_SZ]; + wan_spinlock_t lock; + + u32 used; + u32 tdm_span; + u32 tdm_chan; + u8 state; + u8 hdlc_framing; + u32 active_ch; /* ALEX */ + + wanpipe_tdm_api_cmd_t cfg; + + wan_skb_queue_t wp_rx_list; + wan_skb_queue_t wp_rx_free_list; + netskb_t *rx_skb; + + wan_skb_queue_t wp_tx_list; + wan_skb_queue_t wp_tx_free_list; + netskb_t *tx_skb; + + wan_skb_queue_t wp_event_list; + + wp_tdm_api_rx_hdr_t *rx_hdr; + wp_tdm_api_tx_hdr_t tx_hdr; + + u32 poll_event; + wait_queue_head_t poll_wait; + + u32 rbs_poll_cnt; + u32 busy; + u32 tx_q_len; + u32 critical; + u32 master; + + /* Used For non channelized drivers */ + u8 rx_data[WP_TDM_API_CHUNK_SZ]; + u8 tx_data[WP_TDM_API_CHUNK_SZ]; + +#if 0 + int (*get_hw_mtu_mru)(void *chan); + int (*set_hw_mtu_mru)(void *chan, u32 hw_mtu_mru); + int (*get_usr_mtu_mru)(void *chan); + int (*set_usr_mtu_mru)(void *chan, u32 usr_mtu_mru); +#endif + + int (*event_ctrl)(void *chan, wan_event_ctrl_t*); + int (*read_rbs_bits)(void *chan, u32 ch, u8 *rbs_bits); + int (*write_rbs_bits)(void *chan, u32 ch, u8 rbs_bits); + int (*write_hdlc_frame)(void *chan, netskb_t *skb); + + + /* Hash pointers used to implement + * SPAN/CHAN to Device mapping */ + u32 hash_init; + struct wanpipe_tdm_api_dev **hash_pprev; + struct wanpipe_tdm_api_dev *hash_next; + +}wanpipe_tdm_api_dev_t; + +static __inline int is_tdm_api(void *chan, wanpipe_tdm_api_dev_t *tdm_api) +{ + + if (wan_test_bit(0,&tdm_api->init)) { + return 1; + } + + if (tdm_api->chan == chan){ + return 1; + } + return 0; +} +static __inline int is_tdm_api_stopped(wanpipe_tdm_api_dev_t *tdm_api) +{ + return wan_test_bit(0,&tdm_api->busy); +} + +static __inline void wp_tdm_api_stop(wanpipe_tdm_api_dev_t *tdm_api) +{ + wan_set_bit(0,&tdm_api->busy); +} + +static __inline void wp_tdm_api_start(wanpipe_tdm_api_dev_t *tdm_api) +{ + wan_clear_bit(0,&tdm_api->busy); +} + +extern int wanpipe_tdm_api_rx_tx (wanpipe_tdm_api_dev_t *tdm_api, + u8 *rx_data, u8 *tx_data, int len); +extern int wanpipe_tdm_api_reg(wanpipe_tdm_api_dev_t *tdm_api); +extern int wanpipe_tdm_api_unreg(wanpipe_tdm_api_dev_t *tdm_api); +extern int wanpipe_tdm_api_update_state(wanpipe_tdm_api_dev_t *tdm_api, int state); +extern int wanpipe_tdm_api_rx_hdlc (wanpipe_tdm_api_dev_t *tdm_api, netskb_t *skb); +extern int wanpipe_tdm_api_kick(wanpipe_tdm_api_dev_t *tdm_api); + + +/*=============================================================== + * wphash_sar_dev + * wpunhash_sar_dev + * wp_find_sar_dev_by_vpivci + * + * Hashing functions used to map SPAN/CHAN to TDM API devices + */ +#define WP_TDMAPI_HASH_SZ (4096 >> 2) +#define vpivci_hashfn(x) ((((x) >> 8) ^ (x)) & (WP_TDMAPI_HASH_SZ - 1)) + +static inline wanpipe_tdm_api_dev_t *wp_find_tdm_api_dev(void **hash, + unsigned int key, + unsigned int span, + unsigned int chan) +{ + wanpipe_tdm_api_dev_t *p, **htable; + + htable = (wanpipe_tdm_api_dev_t **)&hash[vpivci_hashfn(key)]; + + for(p = *htable; p ;p = p->hash_next){ + if (p->tdm_span == span && p->tdm_chan == chan){ + break; + } + } + + return p; +} + +static inline int wphash_tdm_api_dev(void **hash, wanpipe_tdm_api_dev_t *p, int hashid) +{ + wanpipe_tdm_api_dev_t **htable = (wanpipe_tdm_api_dev_t **)&hash[vpivci_hashfn(hashid)]; + + + if (wan_test_bit(0,&p->hash_init)){ + DEBUG_EVENT("%s: Critical Error: Init Sar in wphash_sar_dev!\n", + p->name); + return -1; + } + + if (wp_find_tdm_api_dev(hash, hashid, p->tdm_span, p->tdm_chan)){ + DEBUG_EVENT("%s:%s: Error: device SPAN=%i CHAN=%i already in use!\n", + __FUNCTION__,p->name,p->tdm_span,p->tdm_chan); + return -1; + } + + if((p->hash_next = *htable) != NULL) + (*htable)->hash_pprev = &p->hash_next; + + *htable = p; + p->hash_pprev = htable; + + wan_set_bit(0,&p->hash_init); + return 0; +} + +static inline void wpunhash_tdm_api_dev(wanpipe_tdm_api_dev_t *p) +{ + if (p->hash_next) + p->hash_next->hash_pprev = p->hash_pprev; + + *p->hash_pprev = p->hash_next; + + wan_clear_bit(0,&p->init); +} + +static inline int wp_tdmapi_check_mtu(void* pcard, unsigned long timeslot_map, int chunksz, int *mtu) +{ + sdla_t *card = (sdla_t*)pcard; + int x, num_of_channels = 0, max_channels; + + max_channels = GET_TE_CHANNEL_RANGE(&card->fe); + for (x = 0; x < max_channels; x++) { + if (wan_test_bit(x,×lot_map)){ + num_of_channels++; + } + } + *mtu = chunksz * num_of_channels; + return 0; +} + + +#endif + +#endif diff -Nur linux.org/include/linux/wanpipe_tty_iface.h linux-2.6.17/include/linux/wanpipe_tty_iface.h --- linux.org/include/linux/wanpipe_tty_iface.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/wanpipe_tty_iface.h 2006-08-30 10:07:15.000000000 +0000 @@ -0,0 +1,23 @@ + +#ifndef _WP_TTY_IFACE_H +#define _WP_TTY_IFACE_H + +#ifdef WANLIP_DRIVER + +typedef struct wp_tty_reg +{ + int (*prot_set_state) (void *, int, unsigned char *, int); + int (*chan_set_state) (void *, int, unsigned char *, int); + int (*tx_down) (void *, void *); + int (*rx_up) (void *, void *); + int mtu; +}wp_tty_reg_t; + +extern void *wp_register_tty_prot(void *, char *, + wan_tty_conf_t *, + wp_tty_reg_t *); + +extern int wp_unregister_tty_prot(void *); + +#endif + diff -Nur linux.org/include/linux/wanpipe_version.h linux-2.6.17/include/linux/wanpipe_version.h --- linux.org/include/linux/wanpipe_version.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/wanpipe_version.h 2006-08-30 10:07:15.000000000 +0000 @@ -0,0 +1,37 @@ +#ifndef __WANPIPE_VERSION__ +#define __WANPIPE_VERSION__ + + +#define WANPIPE_COPYRIGHT_DATES "(c) 1994-2005" +#define WANPIPE_COMPANY "Sangoma Technologies Inc" + +/********** LINUX **********/ +#define WANPIPE_VERSION "2.3.4" +#define WANPIPE_SUB_VERSION "7" +#define WANPIPE_VERSION_BETA 1 +#define WANPIPE_LITE_VERSION "1.1.1" + +/********** FreeBSD **********/ +#define WANPIPE_VERSION_FreeBSD "2.8.4" +#define WANPIPE_SUB_VERSION_FreeBSD "6" +#define WANPIPE_VERSION_BETA_FreeBSD 1 +#define WANPIPE_LITE_VERSION_FreeBSD "1.1.1" + +/********** OpenBSD **********/ +#define WANPIPE_VERSION_OpenBSD "1.6.4" +#define WANPIPE_SUB_VERSION_OpenBSD "4" +#define WANPIPE_VERSION_BETA_OpenBSD 1 +#define WANPIPE_LITE_VERSION_OpenBSD "1.1.1" + +/********** NetBSD **********/ +#define WANPIPE_VERSION_NetBSD "1.1.1" +#define WANPIPE_SUB_VERSION_NetBSD "5" +#define WANPIPE_VERSION_BETA_NetBSD 1 + +/********** Windows **********/ +#define WANPIPE_VERSION_Windows "1.1.1" +#define WANPIPE_SUB_VERSION_Windows "4" +#define WANPIPE_VERSION_BETA_Windows 1 + +#endif + diff -Nur linux.org/include/linux/wanpipe_x25_kernel.h linux-2.6.17/include/linux/wanpipe_x25_kernel.h --- linux.org/include/linux/wanpipe_x25_kernel.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/wanpipe_x25_kernel.h 2006-08-30 10:07:16.000000000 +0000 @@ -0,0 +1,378 @@ +/* + * These are the public elements of the Linux X25 module. + */ + +#ifndef WANPIPE_X25_KERNEL_H +#define WANPIPE_X25_KERNEL_H + +#include +#include +#include +#include + +#define X25_OK 0 +#define X25_BADTOKEN 1 +#define X25_INVALUE 2 +#define X25_CONNECTED 3 +#define X25_NOTCONNECTED 4 +#define X25_REFUSED 5 +#define X25_TIMEDOUT 6 +#define X25_NOMEM 7 + +#define X25_STANDARD 0x00 +#define X25_EXTENDED 0x01 + +#define X25_SLP 0x00 +#define X25_MLP 0x02 + +#define X25_DTE 0x00 +#define X25_DCE 0x04 + +#define WAN_ADDRESS_SZ 31 +#define X25_CALL_STR_SZ 512 +#define WAN_IF_LABEL_SZ 15 + +#define M_BIT 1 +#define CLEAR_NO_WAIT 0x00 +#define CLEAR_WAIT_FOR_DATA 0x80 + +/* X.25 packet types */ +#define DATA_PKT 0x00 +#define RR_PKT 0x01 +#define RNR_PKT 0x05 +#define REJ_PKT 0x09 +#define CALL_REQUEST_PKT 0x0B +#define CALL_ACCEPT_PKT 0x0F +#define CLEAR_REQUEST_PKT 0x13 +#define CLEAR_CONF_PKT 0x17 +#define RESET_REQUEST_PKT 0x1B +#define RESET_CONF_PKT 0x1F +#define RESTART_REQUEST_PKT 0xFB +#define RESTART_CONF_PKT 0xFF +#define INTERRUPT_PKT 0x23 +#define INTERRUPT_CONF_PKT 0x27 +#define DIAGNOSTIC_PKT 0xF1 +#define REGISTRATION_REQUEST_PKT 0xF3 +#define REGISTRATION_CONF_PKT 0xF7 + + + +enum { + SIOC_X25_PLACE_CALL = (SIOC_ANNEXG_PLACE_CALL), + SIOC_X25_CLEAR_CALL = (SIOC_ANNEXG_CLEAR_CALL), + SIOC_X25_API_RESERVED = (SIOC_WANPIPE_DEVPRIVATE), + + SIOC_X25_GET_CALL_DATA, + SIOC_X25_SET_CALL_DATA, + + SIOC_X25_ACCEPT_CALL, + SIOC_X25_RESET_CALL, + SIOC_X25_DEBUG, + SIOC_X25_SET_LCN_PID, + SIOC_X25_SET_LCN_LABEL, + SIOC_X25_INTERRUPT, + SIOC_X25_HDLC_LINK_STATUS +}; + + +#define SIOC_WANPIPE_GET_CALL_DATA SIOC_X25_GET_CALL_DATA +#define SIOC_WANPIPE_SET_CALL_DATA SIOC_X25_SET_CALL_DATA +#define SIOC_WANPIPE_ACCEPT_CALL SIOC_X25_ACCEPT_CALL +#define SIOC_WANPIPE_CLEAR_CALL SIOC_X25_CLEAR_CALL +#define SIOC_WANPIPE_RESET_CALL SIOC_X25_RESET_CALL +#define SIOC_WANPIPE_INTERRUPT SIOC_X25_INTERRUPT +#define SIOC_WANPIPE_GET_LAPB_STATUS SIOC_X25_HDLC_LINK_STATUS + + +#define DECODE_X25_CMD(cmd) ((cmd==SIOC_X25_PLACE_CALL)?"X25 PLACE CALL" : \ + (cmd==SIOC_X25_CLEAR_CALL)?"X25 CLEAR CALL" : \ + (cmd==SIOC_X25_GET_CALL_DATA)?"X25 GET CALL" : \ + (cmd==SIOC_X25_SET_CALL_DATA)?"X25 SET CALL" : \ + (cmd==SIOC_X25_ACCEPT_CALL)?"X25 ACCEPT CALL" : \ + (cmd==SIOC_X25_RESET_CALL)?"X25 RESET CALL" : \ + (cmd==SIOC_X25_DEBUG)?"X25 DEBUG" : \ + (cmd==SIOC_X25_INTERRUPT)?"X25 INTERRUPT" : \ + (cmd==SIOC_X25_SET_LCN_PID)?"X25 SET PID": \ + (cmd==SIOC_X25_SET_LCN_LABEL)?"X25 SET LABEL" : DECODE_API_CMD(cmd) ) + + + +/*============ bit settings for the 'X25_API_options' ============ */ + +/* don't check the transmit window of the LCN when transmitting data */ +#define DONT_CHK_TX_WIN_ON_DATA_TX 0x0001 + +/*========== bit settings for the 'X25_protocol_options' byte =========*/ + +/* registration pragmatics supported */ +#define REGISTRATION_PRAGMATICS_SUPP 0x0001 +/* a station configured as a DCE will issue Diagnostic packets */ +#define NO_DIAG_PKTS_ISSUED_BY_DCE 0x0002 +/* a Restart Request packet is not issued when entering the ABM */ +#define NO_RESTART_REQ_ON_ENTER_ABM 0x0004 +/* an asynchronous packet does not include a diagnostic field */ +#define NO_DIAG_FIELD_IN_ASYNC_PKTS 0x0008 +/* D-bit pragmatics are not supported */ +#define D_BIT_PRAGMATICS_NOT_SUPPORTED 0x0010 +/* flow control facilities are automatically inserted in call */ +#define AUTO_FLOW_CTRL_PARM_FACIL_INS 0x0020 + /* setup packets */ +#define CALLAC_DOES_NOT_INCL_ADDR_LGTH 0x0040 /* a transmitted or received Call Accept packet does not include */ + /* an address and facilities length field */ +#define HANDLE_ALL_INCOMING_FACILS 0x0080 /* all incoming facilities are supported */ +#define NO_CHK_PROC_INCOMING_FACILS 0x0100 /* incoming facilities are not checked and processed */ + +/* bit settings for the 'X25_response_options' byte */ +#define ALL_DATA_PKTS_ACKED_WITH_RR 0x0001 /* all received Data packets are acknowledged with an RR */ +#define DISABLE_AUTO_CLEAR_CONF 0x0002 /* disable the automatic issing of Clear Confirmation packets */ +#define DISABLE_AUTO_RESET_CONF 0x0004 /* disable the automatic issing of Reset Confirmation packets */ +#define DISABLE_AUTO_RESTART_CONF 0x0008 /* disable the automatic issing of Restart Confirmation packets */ +#define DISABLE_AUTO_INT_CONF 0x0010 /* disable the automatic issing of Interrupt Confirmation packets */ + +/* 'genl_facilities_supported_1' */ +#define FLOW_CTRL_PARM_NEG_SUPP 0x0001 +#define THROUGHPUT_CLASS_NEG_SUPP 0x0002 +#define REV_CHARGING_SUPP 0x0004 +#define FAST_SELECT_SUPP 0x0008 +#define NUI_SELECTION_SUPP 0x0010 +#define CUG_SELECT_BASIC_SUPP 0x0020 +#define CUG_SELECT_EXT_SUPP 0x0040 +#define CUG_OUT_ACC_SEL_BASIC_SUPP 0x0080 +#define CUG_OUT_ACC_SEL_EXT_SUPP 0x0100 +#define BI_CUG_SEL_SUPP 0x0200 +#define RPOA_SEL_BASIC_FORMAT_SUPP 0x0400 +#define RPOA_SEL_EXT_FORMAT_SUPP 0x0800 +#define CALL_DEFLEC_SEL_SUPP 0x1000 +#define CALL_REDIR_DEFLEC_NOTIF_SUPP 0x2000 +#define CALLED_LNE_ADDR_MOD_NOTIF_SUPP 0x4000 +#define TRANSIT_DELAY_SELECT_IND_SUPP 0x8000 + +/* 'genl_facilities_supported_2' */ +#define CHRG_INFO_REQ_SERVICE_SUPP 0x0001 +#define CHRG_INFO_IND_MON_UNIT_SUPP 0x0002 +#define CHRG_INFO_IND_SEG_COUNT_SUPP 0x0004 +#define CHRG_INFO_IND_CALL_DUR_SUPP 0x0008 + +/* 'CCITT_facilities_supported' */ +#define CCITT_CALLING_ADDR_EXT_SUPP 0x0001 +#define CCITT_CALLED_ADDR_EXT_SUPP 0x0002 +#define CCITT_MIN_THROUGH_CLS_NEG_SUPP 0x0004 +#define CCITT_ETE_TX_DELAY_NEG_SUPP 0x0008 +#define CCITT_PRIORITY_SUPP 0x0010 +#define CCITT_PROTECTION_SUPP 0x0020 +#define CCITT_EXPIDITED_DATA_NEG_SUPP 0x0040 + +/* CCITT compatibility levels */ +#define CCITT_1980_COMPATIBILITY 1980 /* 1980 compatibility */ +#define CCITT_1984_COMPATIBILITY 1984 /* 1984 compatibility */ +#define CCITT_1988_COMPATIBILITY 1988 /* 1988 compatibility */ + +/* permitted minimum and maximum values for setting the X.25 configuration */ +#define MIN_PACKET_WINDOW 1 /* the minimum packet window size */ +#define MAX_PACKET_WINDOW 7 /* the maximum packet window size */ +#define MIN_DATA_PACKET_SIZE 16 /* the minimum Data packet size */ +#define MAX_DATA_PACKET_SIZE 4096 /* the maximum Data packet size */ +#define MIN_X25_ASYNC_TIMEOUT 1000 /* the minimum asynchronous packet timeout value */ +#define MAX_X25_ASYNC_TIMEOUT 60000 /* the maximum asynchronous packet timeout value */ +#define MIN_X25_ASYNC_RETRY_COUNT 0 /* the minimum asynchronous packet retry count */ +#define MAX_X25_ASYNC_RETRY_COUNT 250 /* the maximum asynchronous packet retry count */ + + + + + + + + + + + + +#define X25_MAX_DATA 1024 /* max length of X.25 data buffer */ +#pragma pack(1) + +typedef struct { + unsigned char qdm; /* Q/D/M bits */ + unsigned char cause; /* cause field */ + unsigned char diagn; /* diagnostics */ + unsigned char pktType; + unsigned short length; + unsigned char result; + unsigned short lcn; + unsigned short mtu; + unsigned short mru; + char reserved[3]; +}x25api_hdr_t; + +typedef struct { + x25api_hdr_t hdr; + char data[X25_MAX_DATA]; +}x25api_t; + +#pragma pack() + + +/* ---------------------------------------------------------------------------- + * Return codes from interface commands + * --------------------------------------------------------------------------*/ + +#define NO_X25_EXCEP_COND_TO_REPORT 0x51 /* there is no X.25 exception condition to report */ +#define X25_COMMS_DISABLED 0x51 /* X.25 communications are not currently enabled */ +#define X25_COMMS_ENABLED 0x51 /* X.25 communications are currently enabled */ +#define DISABLE_X25_COMMS_BEFORE_CFG 0x51 /* X.25 communications must be disabled before setting the configuration */ +#define X25_CFG_BEFORE_COMMS_ENABLED 0x52 /* perform a SET_X25_CONFIGURATION before enabling X.25 comms */ +#define LGTH_X25_CFG_DATA_INVALID 0x52 /* the length of the passed X.25 configuration data is invalid */ +#define LGTH_X25_INT_DATA_INVALID 0x52 /* the length of the passed interrupt trigger data is invalid */ +#define LINK_LEVEL_NOT_CONNECTED 0x52 /* the HDLC link is not currently in the ABM */ +#define INVALID_X25_CFG_DATA 0x53 /* the passed X.25 configuration data is invalid */ +#define INVALID_X25_APP_IRQ_SELECTED 0x53 /* in invalid IRQ was selected in the SET_X25_INTERRUPT_TRIGGERS */ +#define X25_IRQ_TMR_VALUE_INVALID 0x54 /* an invalid application IRQ timer value was selected */ +#define INVALID_X25_PACKET_SIZE 0x55 /* the X.25 packet size is invalid */ +#define INVALID_X25_LCN_CONFIG 0x56 /* the X.25 logical channel configuration is invalid */ +#define SET_HDLC_CFG_BEFORE_X25_CFG 0x58 /* the HDLC configuration must be set before the X.25 configuration */ +#define HDLC_CFG_INVALID_FOR_X25 0x59 /* the HDLC configuration is invalid for X.25 usage */ +#define INVALID_LCN_SELECTION 0x60 /* the LCN selected is invalid */ +#define NO_LCN_AVAILABLE_CALL_REQ 0x60 /* no LCN is available for an outgoing Call Request */ +#define LCN_NOT_IN_DATA_XFER_ST 0x61 /* the LCN is not in the data transfer mode */ +#define NO_INCOMING_CALL_PENDING 0x61 /* no Call Request/Indication has been received */ +#define NO_CLEAR_REQ_PKT_RECEIVED 0x61 /* no Clear Request/Indication has been received */ +#define NO_RESET_REQ_PKT_RECEIVED 0x61 /* no Reset Request/Indication has been received */ +#define NO_RESTART_REQ_PKT_RECEIVED 0x61 /* no Restart Request/Indication has been received */ +#define NO_INTERRUPT_PKT_RECEIVED 0x61 /* no Interrupt packet has been received */ +#define NO_REGSTR_REQ_PKT_RECEIVED 0x61 /* no Registration Request has been received */ +#define LCN_STATE_INVALID_CLEAR_REQ 0x61 /* the LCN state is invalid for a Clear Request to be issued */ +#define LCN_STATE_INVALID_RESET_REQ 0x61 /* the LCN state is invalid for a Reset Request to be issued */ +#define LCN_STATE_INVALID_INTERRUPT 0x61 /* the LCN state is invalid for an Interrupt packet to be issued */ +#define ASYNC_BFR_IN_USE 0x62 /* the storage buffer used for asynchronous packet formatting is */ + /* currently in use */ +#define DEFINED_WINDOW_SIZE_INVALID 0x62 /* SET_PVC_CONFIGURATION - the selected window size is invalid */ +#define DEFINED_PACKET_SIZE_INVALID 0x63 /* SET_PVC_CONFIGURATION - the selected packet size is invalid */ +#define DATA_TRANSMIT_WINDOW_CLOSED 0x63 /* the transmit packet window is closed */ +#define NO_X25_DATA_PKT_AVAIL 0x63 /* no Data packet is available for reception by the */ + /* application on the selected LCN */ +#define INVALID_X25_PACKET_TYPE 0x63 /* the X25 packet type is invalid */ +#define INVALID_CALL_CONTROL_DEFN 0x63 /* INCOMING_CALL_CONTROL - the call control definition is invalid */ +#define D_BIT_ACK_OUTSTANDING 0x63 /* a response to a transmitted D-bit Data packet has not yet been */ + /* received */ +#define PREV_DATA_RX_NOT_COMPLETE 0x64 /* the application has not completed the previous RECEIVE_X25_DATA_PACKET command */ +#define PREV_DATA_TX_NOT_COMPLETE 0x64 /* the application has not completed the previous SEND_X25_DATA_PACKET command */ +#define INVALID_X25_PKT_LGTH 0x64 /* the length of the outgoing packet is invalid */ +#define CALL_ARGS_LGTH_EXCESSIVE 0x65 /* the outgoing call arguments are of excessive length */ +#define NO_CALLAC_FAST_SEL_RESTR_RESP 0x66 /* an incoming call received with Fast Select */ + /* facilities with restriction on response may not be accepted */ +#define REG_PRAGMATICS_NOT_SUPP 0x67 /* Registration pragmatics are not supported */ +#define PKT_NOT_PERMITTED_AT_DTE 0x68 /* the asynchronous packet may not be transmitted */ + /* at a station configured as a DTE */ +#define PKT_NOT_PERMITTED_AT_DCE 0x68 /* the asynchronous packet may not be transmitted */ + /* at a station configured as a DCE */ +#define USR_DATA_NOT_ALWD_ASYNC_PKT 0x69 /* a user data field is not permitted in the asynchronous packet */ +#define D_BIT_NOT_ALWD_CALL_SETUP_PKT 0x6A /* the D-bit may not be set in the asynchronous packet */ +#define FACIL_NOT_ALWD_OUTGOING_PKT 0x6B /* a facilities field is not permitted in the asynchronous packet */ +#define NO_CALL_DESTINATION_ADDR 0x6C /* - no '-d' definition found in the passed arguments */ +#define INVALID_ARGS_IN_ASYNC_PKT 0x6D /* there are invalid arguments included in the asynchronous packet */ +#define USER_DATA_FIELD_LGTH_ODD 0x6E /* the length of the passed user data is odd */ +#define ASYNC_PKT_RECEIVED 0x70 /* an asynchronous packet has been received */ +#define PROTOCOL_VIOLATION 0x71 /* a protocol violation has occurred */ +#define X25_TIMEOUT 0x72 /* an X.25 timeout has occured */ +#define ASYNC_PKT_RETRY_LIMIT_EXCEEDED 0x73 /* an X.25 asynchronous packet retry limit has been exceeded */ +#define INVALID_X25_COMMAND 0x7F /* the defined X25 interface command is invalid */ + + + +#ifdef __KERNEL__ + + +struct lapb_x25_register_struct { + + unsigned long init; + void (*x25_lapb_connect_indication)(void *x25_id,int reason); + int (*x25_setparms)(struct net_device *dev, struct x25_parms_struct *conf); + void (*x25_lapb_bh_kick)(void *x25_id); + int (*x25_receive_pkt)(void *x25_id, struct sk_buff *skb); + + int (*x25_register)(void **x25_lnk, struct net_device *lapb_dev, char *dev_name, struct net_device **new_dev); + int (*x25_unregister_link)(void *x25_id); + int (*x25_unregister)(struct net_device *x25_dev); + + void (*x25_lapb_disconnect_confirm)(void *x25_id,int reason); + void (*x25_lapb_disconnect_indication)(void *x25_id,int reason); + void (*x25_lapb_connect_confirm)(void *x25_id,int reason); + int (*x25_get_map)(void*, struct seq_file *); + void (*x25_get_active_inactive)(void*,wp_stack_stats_t*); +}; + +struct x25_dsp_register_struct { + unsigned char init; + int (*dsp_register)(struct net_device* x25_dev, char* dev_name, struct net_device **new_dev); + int (*dsp_unregister)(struct net_device** x25_dev, void* dsp_id); + int (*dsp_setparms)(void* dsp_id, void*); + + int (*dsp_call_request)(void* dsp_id, void* sk_id, struct sk_buff* skb); + int (*dsp_call_accept)(void* dsp_id, struct sk_buff* skb); + void (*dsp_svc_up)(void* dsp_id); + void (*dsp_svc_down)(void* dsp_id); + void (*dsp_svc_ready)(void* dsp_id); + void (*dsp_svc_reset)(void* dsp_id); + + int (*dsp_receive_pkt)(void* dsp_id, struct sk_buff *skb); + void (*dsp_x25_bh_kick)(void *dsp_id); + int (*dsp_rx_buf_check)(void *dsp_id, int len); + int (*dsp_oob_msg)(void *dsp_id, struct sk_buff* skb); + int (*dsp_check_dev)(void *dsp_id); + void (*dsp_get_active_inactive)(void*dsp_id,wp_stack_stats_t *); + +}; + + +struct wanpipe_x25_register_struct{ + + unsigned char init; + + int (*x25_bind_api_to_svc)(struct net_device *master_dev, void *sk_id); + int (*x25_bind_listen_to_link)(struct net_device *master_dev, void *sk_id, unsigned short protocol); + int (*x25_unbind_listen_from_link)(void *sk_id,unsigned short protocol); + + int (*x25_dsp_register)(struct net_device *x25_dev, + char *dev_name, + struct net_device **new_dev); + + int (*x25_dsp_unregister)(void* dsp_id); + int (*x25_dsp_setparms) (struct net_device *x25_dev, + void* dsp_id, + void *dsp_parms); + + +}; + +extern int register_wanpipe_x25_protocol (struct wanpipe_x25_register_struct *x25_api_reg); +extern void unregister_wanpipe_x25_protocol (void); + +extern int x25_dsp_register(struct net_device *x25_dev, + char *dev_name, + struct net_device **new_dev); + +extern int x25_dsp_unregister(void* dsp_id); +extern int x25_dsp_setparms (struct net_device *x25_dev, + void* dsp_id, + void *dsp_parms); + +extern void lapb_kickstart_tx (struct net_device *dev); + +extern void lapb_set_mtu (struct net_device *dev, unsigned int mtu); + +extern void lapb_link_unregister (struct net_device *dev); + +extern void x25_dsp_id_unregister(struct net_device *dev); + +extern int x25_dsp_is_svc_ready(struct net_device *dev); + +extern void wan_skb_destructor (struct sk_buff *skb); +#define CALL_LOG(x25_link,format,msg...) { if (x25_link && x25_link->cfg.call_logging){ \ + DEBUG_EVENT(format,##msg); \ + }else if(!x25_link){\ + DEBUG_EVENT(format,##msg); \ + }} + +#endif +#endif + diff -Nur linux.org/include/linux/wanpipe_xdlc_iface.h linux-2.6.17/include/linux/wanpipe_xdlc_iface.h --- linux.org/include/linux/wanpipe_xdlc_iface.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/wanpipe_xdlc_iface.h 2006-08-30 10:07:16.000000000 +0000 @@ -0,0 +1,111 @@ +/* + * These are the public elements of the Linux XDLC module. + */ + +#ifndef _WP_XDLC_IFACE_H +#define _WP_XDLC_IFACE_H + +enum xdlc_error_codes{ + EXCEP_LINK_CONNECTED = 0, + EXCEP_LINK_CONNECTING, + EXCEP_LINK_DISCONNECTED, + EXCEP_LINK_DISCONNECTING, + + EXCEP_OOB_EXCEPTIONS, + + EXCEP_NO_RESPONSE_COUNTER, + EXCEP_FRM_RETRANS_COUNTER, + + EXCEP_RNR_COUNTER, + EXCEP_SEC_NRM_TIMEOUT, + + EXCEP_PRI_RD_FRAME_RECEIVED, + EXCEP_FRM_DM_FRAME_RECEIVED, + EXCEP_SEC_SNRM_FRAME_RECEIVED, + EXCEP_SEC_DISC_FRAME_RECEIVED, + + EXCEP_FRMR_FRAME_RECEIVED, + EXCEP_FRMR_FRAME_TRANSMITTED +}; + +#define XDLC_STATE_DECODE(_state_) (\ + (_state_==EXCEP_LINK_CONNECTED)?"Connected": \ + (_state_==EXCEP_LINK_CONNECTING)?"Connecting": \ + (_state_==EXCEP_LINK_DISCONNECTED)?"Disconnected": \ + (_state_==EXCEP_LINK_DISCONNECTING)?"Disconnecting": "Unknown" ) + + +#define XDLC_EXCEP_DECODE(_error_) (\ + (_error_==EXCEP_NO_RESPONSE_COUNTER)?"No Response Timeout": \ + (_error_==EXCEP_FRM_RETRANS_COUNTER)?"Frame Re-Transmit Timeout": \ + \ + (_error_==EXCEP_RNR_COUNTER)?"Consec RNR Rx Timeout": \ + (_error_==EXCEP_SEC_NRM_TIMEOUT)?"Sec NRM Timeout": \ + \ + (_error_==EXCEP_PRI_RD_FRAME_RECEIVED)?"Pri RD Received": \ + (_error_==EXCEP_FRM_DM_FRAME_RECEIVED)?"DM Frame Received": \ + (_error_==EXCEP_SEC_SNRM_FRAME_RECEIVED)?"Sec SNRM Received": \ + (_error_==EXCEP_SEC_DISC_FRAME_RECEIVED)?"Sec DISC Received": \ + \ + (_error_==EXCEP_FRMR_FRAME_RECEIVED)?"Frame Reject Received": \ + (_error_==EXCEP_FRMR_FRAME_TRANSMITTED)?"Frame Reject Transmiteed" : "None") + +enum xdlc_ioctl_cmds { + SIOCS_XDLC_SET_CONF, + SIOCS_XDLC_GET_CONF, + + SIOCS_XDLC_START, + SIOCS_XDLC_STOP, + + SIOCS_XDLC_ENABLE_IFRAMES, + SIOCS_XDLC_DISABLE_IFRAMES, + + SIOCS_XDLC_CLEAR_POLL_TMR, + SIOCS_XDLC_FLUSH_TX_BUF, + + SIOCS_XDLC_GET_STATS, + SIOCS_XDLC_FLUSH_STATS +}; + +typedef struct{ + unsigned char state; + unsigned char address; + unsigned short exception; +}wp_xdlc_excep_t; + +#if 0 +typedef struct wp_xdlc_reg +{ + int (*prot_state_change) (void *, int, unsigned char*, int); + int (*chan_state_change) (void *, int, unsigned char*, int); + int (*tx_down) (void *, void *); + int (*rx_up) (void *, void *); +}wp_xdlc_reg_t; +#endif + +extern void *wp_reg_xdlc_prot(void *link_ptr, + char *devname, + void *conf, + wplip_prot_reg_t *prot_reg); + +extern int wp_unreg_xdlc_prot(void *xdlc_link_ptr); + +extern void *wp_reg_xdlc_addr(void *, + void *, + char *, + void *, + unsigned char); + +extern int wp_unreg_xdlc_addr(void *); + +extern int wp_xdlc_open(void *); +extern int wp_xdlc_close(void *); +extern int wp_xdlc_rx(void *, void *); +extern int wp_xdlc_rx_kick(void *); +extern int wp_xdlc_bh(void *); +extern int wp_xdlc_tx(void *, void *, int type); +extern int wp_xdlc_timer(void *, unsigned int *period, unsigned int); +extern int wp_xdlc_ioctl(void *, int, void *); + + +#endif diff -Nur linux.org/include/linux/wanpipe_xmtp2_iface.h linux-2.6.17/include/linux/wanpipe_xmtp2_iface.h --- linux.org/include/linux/wanpipe_xmtp2_iface.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/wanpipe_xmtp2_iface.h 2006-08-30 10:07:16.000000000 +0000 @@ -0,0 +1,59 @@ +/* + * These are the public elements of the Binary xmtp2 module. + */ + +#ifndef _WP_XMTP2_IFACE_H +#define _WP_XMTP2_IFACE_H + +/* Mandatory Define here */ +#ifdef WANLIP_DRIVER + +enum xmtp2_ioctl_cmds { + SIOCG_XMTP2_CONF, + SIOCG_XMTP2_STATUS, +}; + +extern void *wp_register_xmtp2_prot (void *, + char *, + void *, + wplip_prot_reg_t *); + +extern int wp_unregister_xmtp2_prot (void *); + +extern void *wp_register_xmtp2_chan (void *if_ptr, + void *prot_ptr, + char *devname, + void *cfg_ptr, + unsigned char type); + +extern int wp_unregister_xmtp2_chan (void *chan_ptr); + +extern int wp_xmtp2_open (void *prot_ptr); +extern int wp_xmtp2_close (void *prot_ptr); +extern int wp_xmtp2_rx (void *prot_ptr, void *skb); +extern int wp_xmtp2_bh (void *prot_ptr); +extern int wp_xmtp2_tx (void *prot_ptr, void *skb, int type); +extern int wp_xmtp2_timer (void *prot_ptr, unsigned int *period, + unsigned int carrier_reliable); +extern int wp_xmtp2_pipemon (void *prot_ptr, int cmd, int addr, + unsigned char* data, unsigned int *len); + +#endif + + +/* Any public structures shared between LIP and + * Object Code */ + + + + +/* This code should go into wanpipe_cfg.h */ +typedef struct wan_xmtp2_if_conf +{ + /* IMPLEMENT USER CONFIG OPTIONS HERE */ + unsigned char data; + + +}wan_xmtp2_if_conf_t; + +#endif diff -Nur linux.org/include/linux/wanproc.h linux-2.6.17/include/linux/wanproc.h --- linux.org/include/linux/wanproc.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/linux/wanproc.h 2006-08-30 10:07:16.000000000 +0000 @@ -0,0 +1,246 @@ +/***************************************************************************** +* wanproc.h Definitions for the WAN PROC fs. +* +* Author: Alex Feldman +* +* Copyright: (c) 1995-2000 Sangoma Technologies Inc. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version +* 2 of the License, or (at your option) any later version. +* ============================================================================ +* Aug 20, 2001 Alex Feldman Initial version. +*/ + +#ifndef __WANPROC_H +# define __WANPROC_H + +# if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) +enum { + WANPIPE_PROCFS_CONFIG = 0x1, + WANPIPE_PROCFS_HWPROBE, + WANPIPE_PROCFS_STATUS, + WANPIPE_PROCFS_INTERFACES, + WANPIPE_PROCFS_DEV +}; +# endif + +# if defined(WAN_KERNEL) + +# define PROC_STATS_ALARM_FORMAT "%25s: %10s %25s: %10s\n" +# define PROC_STATS_PMON_FORMAT "%25s: %10lu %25s: %10lu\n" + +/* + * ****************************************************************** + * + * + * ****************************************************************** + */ +#define PROC_BUF_CONT 0 +#define PROC_BUF_EXIT 1 + +#if defined(LINUX_2_6) +# define PROC_ADD_DECL(m) +# define PROC_ADD_INIT(m,buf,offs,len) +# define PROC_ADD_LINE(m,frm,msg...) seq_printf(m,frm,##msg) +# define PROC_ADD_RET(m) return 0 +# define PROC_GET_DATA() m->private +#else +/* For BSDs and not Linux-2.6 */ +# define PROC_GET_DATA() (void*)start +# define PROC_ADD_DECL(m) static struct seq_file mfile; \ + struct seq_file *m=&mfile; +# define PROC_ADD_INIT(m,buf,offs,len) \ + if (offs == 0) m->stop_cnt = 0; \ + m->buf = buf; \ + m->size = len; \ + m->from = offs; \ + m->count = 0; \ + m->index = 0; +# define PROC_ADD_LINE(m,frm,msg...) \ + { if (proc_add_line(m,frm,##msg) == PROC_BUF_EXIT) \ + return m->count; \ + } +# define PROC_ADD_RET(m) \ + if (m->count >= 0) { \ + m->stop_cnt = m->from + m->count; \ + } \ + return m->count; +# define PROC_ADD_PREFIX(m,frm,msg...) \ + if (proc_add_prefix(m, frm, ##msg) == PROC_BUF_EXIT) \ + return m->count; +#endif + +/******************************************************************* +* TYPEDEF/STRUCTURE +********************************************************************/ + +/******************************************************************* +* FUNCTION PROTOTYPES +********************************************************************/ +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) +int config_get_info(char* buf, char** start, off_t offs, int len); +int status_get_info(char* buf, char** start, off_t offs, int len); +int probe_get_info(char* buf, char** start, off_t offs, int len); +int wandev_get_info(char* buf, char** start, off_t offs, int len); +int interfaces_get_info(char* buf, char** start, off_t offs, int len); +int wanproc_active_dev(char* buf, char** start, off_t offs, int len); +#endif +extern int proc_add_line(struct seq_file* m, char* frm, ...); + + + +/* + * ****************************************************************** + */ + +/* + ******************************************************************** + * X.25 + */ +/* + * SNMP X.25 defines + */ +#define SNMP_X25_DTE 1 +#define SNMP_X25_DCE 2 +#define SNMP_X25_DXE 3 + +#define SNMP_X25_MODULO8 1 +#define SNMP_X25_MODULO128 2 + +#define SNMP_X25_INCOMING 1 +#define SNMP_X25_OUTGOING 2 +#define SNMP_X25_PVC 3 + +/* x25CallParmAcceptReverseCharging */ +#define SNMP_X25_ARC_DEFAULT 1 +#define SNMP_X25_ARC_ACCEPT 2 +#define SNMP_X25_ARC_REFUSE 3 +#define SNMP_X25_ARC_NEVERACCEPT 4 + +/* x25CallParmProposeReverseCharging */ +#define SNMP_X25_PRC_DEFAULT 1 +#define SNMP_X25_PRC_REVERSE 2 +#define SNMP_X25_PRC_LOCAL 3 + +/* x25CallParmFastSelecet */ +#define SNMP_X25_FS_DEFAULT 1 +#define SNMP_X25_FS_NOTSPECIFIED 2 +#define SNMP_X25_FS_FASTSELECT 3 +#define SNMP_X25_FS_RESTRICTEDFASTRESP 4 +#define SNMP_X25_FS_NOFASTSELECT 5 +#define SNMP_X25_FS_NORESTRICTEDFASTSEL 6 + +/* x25CallParmInThruPutClassSize */ +/* x25CallParmOutThruPutClassSize */ +#define SNMP_X25_THRUCLASS_TCRES1 1 +#define SNMP_X25_THRUCLASS_TCRES2 2 +#define SNMP_X25_THRUCLASS_TC75 3 +#define SNMP_X25_THRUCLASS_TC150 4 +#define SNMP_X25_THRUCLASS_TC300 5 +#define SNMP_X25_THRUCLASS_TC600 6 +#define SNMP_X25_THRUCLASS_TC1200 7 +#define SNMP_X25_THRUCLASS_TC2400 8 +#define SNMP_X25_THRUCLASS_TC4800 9 +#define SNMP_X25_THRUCLASS_TC9600 10 +#define SNMP_X25_THRUCLASS_TC19200 11 +#define SNMP_X25_THRUCLASS_TC48000 12 +#define SNMP_X25_THRUCLASS_TC64000 13 +#define SNMP_X25_THRUCLASS_TCRES14 14 +#define SNMP_X25_THRUCLASS_TCRES15 15 +#define SNMP_X25_THRUCLASS_TCRES16 16 +#define SNMP_X25_THRUCLASS_TCNONE 17 +#define SNMP_X25_THRUCLASS_TCDEF 18 + +/* x25CallParmChargingInfo */ +#define SNMP_X25_CHARGINGINFO_DEF 1 +#define SNMP_X25_CHARGINGINFO_NOFACL 2 +#define SNMP_X25_CHARGINGINFO_NOCHRGINFO 3 +#define SNMP_X25_CHARGINGINFO_CHARGINFO 4 + +/* x25CallParmExptData */ +#define SNMP_X25_EXPTDATA_DEFULT 1 +#define SNMP_X25_EXPTDATA_NOEXPTDATA 2 +#define SNMP_X25_EXPTDATA_EXPTDATA 3 + + +/* + ******************************************************************** + * Frame Relay + */ +#define ADSL_STATION_DECODE(station)\ + (station == 0) ? "ETH_LLC" : \ + (station == 1) ? "ETH_VC" : \ + (station == 2) ? "CIP_LLC" : \ + (station == 3) ? "IP_VC" : \ + (station == 4) ? "PPP_LLC" : \ + (station == 5) ? "PPP_VC" : "N/A" + +/* + * SNMP defines + */ +#define SNMP_FR_UNICAST 1 +#define SNMP_FR_ONEWAY 2 +#define SNMP_FR_TWOWAY 3 +#define SNMP_FR_NWAY 4 + +#define SNMP_FR_STATIC 1 +#define SNMP_FR_DYNAMIC 2 + +#define SNMP_FR_INVALID 1 +#define SNMP_FR_ACTIVE 2 +#define SNMP_FR_INACTIVE 3 + +#define SNMP_FR_NOLMICONF 1 +#define SNMP_FR_LMIREV 2 +#define SNMP_FR_ANSIT1617D 3 +#define SNMP_FR_ANSIT1617B 4 +#define SNMP_FR_ITUT933A 5 +#define SNMP_FR_ANSIT1617D1994 6 + +#define SNMP_FR_Q921_ADDR 1 +#define SNMP_FR_Q922MARCH90 2 +#define SNMP_FR_Q922NOV90 3 +#define SNMP_FR_Q922 4 + +#define SNMP_FR_2BYTE_ADDR 2 +#define SNMP_FR_3BYTE_ADDR 3 +#define SNMP_FR_4BYTE_ADDR 4 + +#define SNMP_FR_NONBROADCAST 1 +#define SNMP_FR_BROADCAST 2 + +#define SNMP_FR_RUNNING 1 +#define SNMP_FR_FAULT 2 +#define SNMP_FR_INITIALIZING 3 + +#define SNMP_FR_ENABLED 1 +#define SNMP_FR_DISABLED 2 + +#define SNMP_FR_UNKNOWNERR 1 +#define SNMP_FR_RECEIVESHORT 2 +#define SNMP_FR_RECEIVELONG 3 +#define SNMP_FR_ILLEGALADDR 4 +#define SNMP_FR_UNKNOWNADDR 5 +#define SNMP_FR_DLCMIPROTOERR 6 +#define SNMP_FR_DLCMIUNKNOWNERR 7 +#define SNMP_FR_DLCMISEQERR 8 +#define SNMP_FR_DLCMIUNKNOWNRPT 9 +#define SNMP_FR_NOERRSINCERESET 10 + +#define SNMP_FR_ERRDATA_LEN 1600 + +#define SNMP_FR_SET_ERR(chan, type, data, len) {struct timeval tv; \ + do_gettimeofday(&tv); \ + chan->err_type = type; \ + memcpy(chan->err_data, data, len); \ + chan->err_time = tv.tv_sec; \ + chan->err_faults++;} + + + + +#endif /* WAN_KERNEL */ + +#endif /* __WANPROC_H */ diff -Nur linux.org/include/linux/wanrouter.h linux-2.6.17/include/linux/wanrouter.h --- linux.org/include/linux/wanrouter.h 2006-06-18 01:49:35.000000000 +0000 +++ linux-2.6.17/include/linux/wanrouter.h 2006-08-30 10:07:16.000000000 +0000 @@ -4,8 +4,9 @@ * Drivers and is completely hardware-independent. * * Author: Nenad Corbic +* Alex Feldman * Gideon Hack -* Additions: Arnaldo Melo +* Additions: Arnaldo Melo * * Copyright: (c) 1995-2000 Sangoma Technologies Inc. * @@ -14,13 +15,14 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * ============================================================================ +* May 25, 2001 Alex Feldman Added T1/E1 support (TE1). * Jul 21, 2000 Nenad Corbic Added WAN_FT1_READY State * Feb 24, 2000 Nenad Corbic Added support for socket based x25api * Jan 28, 2000 Nenad Corbic Added support for the ASYNC protocol. * Oct 04, 1999 Nenad Corbic Updated for 2.1.0 release * Jun 02, 1999 Gideon Hack Added support for the S514 adapter. -* May 23, 1999 Arnaldo Melo Added local_addr to wanif_conf_t -* WAN_DISCONNECTING state added +* May 23, 1999 Arnaldo Melo Added local_addr to wanif_conf_t +* WAN_DISCONNECTING state added * Jul 20, 1998 David Fong Added Inverse ARP options to 'wanif_conf_t' * Jun 12, 1998 David Fong Added Cisco HDLC support. * Dec 16, 1997 Jaspreet Singh Moved 'enable_IPX' and 'network_number' to @@ -44,18 +46,40 @@ * Jan 02, 1997 Gene Kozin Initial version (based on wanpipe.h). *****************************************************************************/ -#include /* Support for SMP Locking */ - #ifndef _ROUTER_H #define _ROUTER_H #define ROUTER_NAME "wanrouter" /* in case we ever change it */ -#define ROUTER_VERSION 1 /* version number */ -#define ROUTER_RELEASE 1 /* release (minor version) number */ #define ROUTER_IOCTL 'W' /* for IOCTL calls */ #define ROUTER_MAGIC 0x524D4157L /* signature: 'WANR' reversed */ +#define CHECK_ROUTER_MAGIC(magic) WAN_ASSERT(magic != ROUTER_MAGIC) + /* IOCTL codes for /proc/router/ entries (up to 255) */ +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) +# define ROUTER_SETUP _IOW(ROUTER_IOCTL, 1, wan_conf_t) /* configure device */ +# define ROUTER_DOWN _IOWR(ROUTER_IOCTL, 2, wan_conf_t)/* shut down device */ +# define ROUTER_STAT _IOW(ROUTER_IOCTL, 3, wan_conf_t) /* get device status */ +# define ROUTER_IFNEW _IOW(ROUTER_IOCTL, 4, wan_conf_t) /* add interface */ +# define ROUTER_IFDEL _IOW(ROUTER_IOCTL, 5, wan_conf_t) /* del interface */ +# define ROUTER_IFNEW_LIP _IOW(ROUTER_IOCTL, 6, wan_conf_t) /* add interface */ +# define ROUTER_IFDEL_LIP _IOW(ROUTER_IOCTL, 7, wan_conf_t) /* del interface */ +# define ROUTER_IFSTAT _IOW(ROUTER_IOCTL, 8, wan_conf_t) /* get interface status */ +# define ROUTER_DEBUGGING _IOW(ROUTER_IOCTL, 9, wan_conf_t)/* get interface status */ +# define ROUTER_VER _IOWR(ROUTER_IOCTL, 10, wan_conf_t) /* get router version */ +# define ROUTER_PROCFS _IOWR(ROUTER_IOCTL, 11, wan_conf_t) /* get procfs info */ +# define ROUTER_DEBUG_READ _IOWR(ROUTER_IOCTL, 12, wan_conf_t) /* get dbg_msg */ +# define ROUTER_USER _IOW(ROUTER_IOCTL, 16, u_int) /* driver specific calls */ +# define ROUTER_USER_MAX _IOW(ROUTER_IOCTL, 31, u_int) +# define SIOC_WANPIPE_PIPEMON _IOWR('i', 150, struct ifreq) /* get monitor statistics */ +# define SIOC_WANPIPE_DEVICE _IOWR('i', 151, struct ifreq) /* set generic device */ +# define SIOC_WAN_DEVEL_IOCTL _IOWR('i', 152, struct ifreq) /* get hwprobe string */ +# define SIOC_WANPIPE_DUMP _IOWR('i', 153, struct ifreq) /* get memdump string (GENERIC) */ +# define SIOC_AFT_CUSTOMER_ID _IOWR('i', 154, struct ifreq) /* get AFT customer ID */ +# define SIOC_WAN_EC_IOCTL _IOWR('i', 155, struct ifreq) /* Echo Canceller interface */ +# define SIOC_WAN_FE_IOCTL _IOWR('i', 156, struct ifreq) /* FE interface */ +#else + enum router_ioctls { ROUTER_SETUP = ROUTER_IOCTL<<8, /* configure device */ @@ -64,271 +88,58 @@ ROUTER_IFNEW, /* add interface */ ROUTER_IFDEL, /* delete interface */ ROUTER_IFSTAT, /* get interface status */ - ROUTER_USER = (ROUTER_IOCTL<<8)+16, /* driver-specific calls */ - ROUTER_USER_MAX = (ROUTER_IOCTL<<8)+31 + ROUTER_VER, /* get router version */ + ROUTER_DEBUGGING, /* get router version */ + ROUTER_DEBUG_READ, /* get router version */ + + ROUTER_IFNEW_LAPB, /* add new lapb interface */ + ROUTER_IFDEL_LAPB, /* delete a lapb interface */ + ROUTER_IFNEW_X25, /* add new x25 interface */ + ROUTER_IFDEL_X25, /* delete a x25 interface */ + ROUTER_IFNEW_DSP, /* add new dsp interface */ + ROUTER_IFDEL_DSP, /* delete a dsp interface */ + + ROUTER_IFNEW_LIP, + ROUTER_IFDEL_LIP, + + ROUTER_USER, /* driver-specific calls */ + ROUTER_USER_MAX = ROUTER_USER+31 }; + +/* Backward Compatibility for non sangoma drivers */ +#ifdef __KERNEL__ +# ifndef __LINUX__ +# define __LINUX__ +# endif + +# ifndef WAN_KERNEL +# define WAN_KERNEL +# endif +#endif + +#endif + /* identifiers for displaying proc file data for dual port adapters */ #define PROC_DATA_PORT_0 0x8000 /* the data is for port 0 */ #define PROC_DATA_PORT_1 0x8001 /* the data is for port 1 */ /* NLPID for packet encapsulation (ISO/IEC TR 9577) */ #define NLPID_IP 0xCC /* Internet Protocol Datagram */ +#define CISCO_IP 0x00 /* Internet Protocol Datagram - CISCO only */ #define NLPID_SNAP 0x80 /* IEEE Subnetwork Access Protocol */ #define NLPID_CLNP 0x81 /* ISO/IEC 8473 */ #define NLPID_ESIS 0x82 /* ISO/IEC 9542 */ #define NLPID_ISIS 0x83 /* ISO/IEC ISIS */ #define NLPID_Q933 0x08 /* CCITT Q.933 */ -/* Miscellaneous */ -#define WAN_IFNAME_SZ 15 /* max length of the interface name */ -#define WAN_DRVNAME_SZ 15 /* max length of the link driver name */ -#define WAN_ADDRESS_SZ 31 /* max length of the WAN media address */ -#define USED_BY_FIELD 8 /* max length of the used by field */ - -/* Defines for UDP PACKET TYPE */ -#define UDP_PTPIPE_TYPE 0x01 -#define UDP_FPIPE_TYPE 0x02 -#define UDP_CPIPE_TYPE 0x03 -#define UDP_DRVSTATS_TYPE 0x04 -#define UDP_INVALID_TYPE 0x05 - -/* Command return code */ -#define CMD_OK 0 /* normal firmware return code */ -#define CMD_TIMEOUT 0xFF /* firmware command timed out */ - -/* UDP Packet Management */ -#define UDP_PKT_FRM_STACK 0x00 -#define UDP_PKT_FRM_NETWORK 0x01 - -/* Maximum interrupt test counter */ -#define MAX_INTR_TEST_COUNTER 100 - -/* Critical Values for RACE conditions*/ -#define CRITICAL_IN_ISR 0xA1 -#define CRITICAL_INTR_HANDLED 0xB1 +#ifndef WAN_DRVNAME_SZ +#define WAN_DRVNAME_SZ 15 +#endif /****** Data Types **********************************************************/ /*---------------------------------------------------------------------------- - * X.25-specific link-level configuration. - */ -typedef struct wan_x25_conf -{ - unsigned lo_pvc; /* lowest permanent circuit number */ - unsigned hi_pvc; /* highest permanent circuit number */ - unsigned lo_svc; /* lowest switched circuit number */ - unsigned hi_svc; /* highest switched circuit number */ - unsigned hdlc_window; /* HDLC window size (1..7) */ - unsigned pkt_window; /* X.25 packet window size (1..7) */ - unsigned t1; /* HDLC timer T1, sec (1..30) */ - unsigned t2; /* HDLC timer T2, sec (0..29) */ - unsigned t4; /* HDLC supervisory frame timer = T4 * T1 */ - unsigned n2; /* HDLC retransmission limit (1..30) */ - unsigned t10_t20; /* X.25 RESTART timeout, sec (1..255) */ - unsigned t11_t21; /* X.25 CALL timeout, sec (1..255) */ - unsigned t12_t22; /* X.25 RESET timeout, sec (1..255) */ - unsigned t13_t23; /* X.25 CLEAR timeout, sec (1..255) */ - unsigned t16_t26; /* X.25 INTERRUPT timeout, sec (1..255) */ - unsigned t28; /* X.25 REGISTRATION timeout, sec (1..255) */ - unsigned r10_r20; /* RESTART retransmission limit (0..250) */ - unsigned r12_r22; /* RESET retransmission limit (0..250) */ - unsigned r13_r23; /* CLEAR retransmission limit (0..250) */ - unsigned ccitt_compat; /* compatibility mode: 1988/1984/1980 */ - unsigned x25_conf_opt; /* User defined x25 config optoins */ - unsigned char LAPB_hdlc_only; /* Run in HDLC only mode */ - unsigned char logging; /* Control connection logging */ - unsigned char oob_on_modem; /* Whether to send modem status to the user app */ -} wan_x25_conf_t; - -/*---------------------------------------------------------------------------- - * Frame relay specific link-level configuration. - */ -typedef struct wan_fr_conf -{ - unsigned signalling; /* local in-channel signalling type */ - unsigned t391; /* link integrity verification timer */ - unsigned t392; /* polling verification timer */ - unsigned n391; /* full status polling cycle counter */ - unsigned n392; /* error threshold counter */ - unsigned n393; /* monitored events counter */ - unsigned dlci_num; /* number of DLCs (access node) */ - unsigned dlci[100]; /* List of all DLCIs */ -} wan_fr_conf_t; - -/*---------------------------------------------------------------------------- - * PPP-specific link-level configuration. - */ -typedef struct wan_ppp_conf -{ - unsigned restart_tmr; /* restart timer */ - unsigned auth_rsrt_tmr; /* authentication timer */ - unsigned auth_wait_tmr; /* authentication timer */ - unsigned mdm_fail_tmr; /* modem failure timer */ - unsigned dtr_drop_tmr; /* DTR drop timer */ - unsigned connect_tmout; /* connection timeout */ - unsigned conf_retry; /* max. retry */ - unsigned term_retry; /* max. retry */ - unsigned fail_retry; /* max. retry */ - unsigned auth_retry; /* max. retry */ - unsigned auth_options; /* authentication opt. */ - unsigned ip_options; /* IP options */ - char authenticator; /* AUTHENTICATOR or not */ - char ip_mode; /* Static/Host/Peer */ -} wan_ppp_conf_t; - -/*---------------------------------------------------------------------------- - * CHDLC-specific link-level configuration. - */ -typedef struct wan_chdlc_conf -{ - unsigned char ignore_dcd; /* Protocol options: */ - unsigned char ignore_cts; /* Ignore these to determine */ - unsigned char ignore_keepalive; /* link status (Yes or No) */ - unsigned char hdlc_streaming; /* hdlc_streaming mode (Y/N) */ - unsigned char receive_only; /* no transmit buffering (Y/N) */ - unsigned keepalive_tx_tmr; /* transmit keepalive timer */ - unsigned keepalive_rx_tmr; /* receive keepalive timer */ - unsigned keepalive_err_margin; /* keepalive_error_tolerance */ - unsigned slarp_timer; /* SLARP request timer */ -} wan_chdlc_conf_t; - - -/*---------------------------------------------------------------------------- - * WAN device configuration. Passed to ROUTER_SETUP IOCTL. - */ -typedef struct wandev_conf -{ - unsigned magic; /* magic number (for verification) */ - unsigned config_id; /* configuration structure identifier */ - /****** hardware configuration ******/ - unsigned ioport; /* adapter I/O port base */ - unsigned long maddr; /* dual-port memory address */ - unsigned msize; /* dual-port memory size */ - int irq; /* interrupt request level */ - int dma; /* DMA request level */ - char S514_CPU_no[1]; /* S514 PCI adapter CPU number ('A' or 'B') */ - unsigned PCI_slot_no; /* S514 PCI adapter slot number */ - char auto_pci_cfg; /* S515 PCI automatic slot detection */ - char comm_port; /* Communication Port (PRI=0, SEC=1) */ - unsigned bps; /* data transfer rate */ - unsigned mtu; /* maximum transmit unit size */ - unsigned udp_port; /* UDP port for management */ - unsigned char ttl; /* Time To Live for UDP security */ - unsigned char ft1; /* FT1 Configurator Option */ - char interface; /* RS-232/V.35, etc. */ - char clocking; /* external/internal */ - char line_coding; /* NRZ/NRZI/FM0/FM1, etc. */ - char station; /* DTE/DCE, primary/secondary, etc. */ - char connection; /* permanent/switched/on-demand */ - char read_mode; /* read mode: Polling or interrupt */ - char receive_only; /* disable tx buffers */ - char tty; /* Create a fake tty device */ - unsigned tty_major; /* Major number for wanpipe tty device */ - unsigned tty_minor; /* Minor number for wanpipe tty device */ - unsigned tty_mode; /* TTY operation mode SYNC or ASYNC */ - char backup; /* Backup Mode */ - unsigned hw_opt[4]; /* other hardware options */ - unsigned reserved[4]; - /****** arbitrary data ***************/ - unsigned data_size; /* data buffer size */ - void* data; /* data buffer, e.g. firmware */ - union /****** protocol-specific ************/ - { - wan_x25_conf_t x25; /* X.25 configuration */ - wan_ppp_conf_t ppp; /* PPP configuration */ - wan_fr_conf_t fr; /* frame relay configuration */ - wan_chdlc_conf_t chdlc; /* Cisco HDLC configuration */ - } u; -} wandev_conf_t; - -/* 'config_id' definitions */ -#define WANCONFIG_X25 101 /* X.25 link */ -#define WANCONFIG_FR 102 /* frame relay link */ -#define WANCONFIG_PPP 103 /* synchronous PPP link */ -#define WANCONFIG_CHDLC 104 /* Cisco HDLC Link */ -#define WANCONFIG_BSC 105 /* BiSync Streaming */ -#define WANCONFIG_HDLC 106 /* HDLC Support */ -#define WANCONFIG_MPPP 107 /* Multi Port PPP over RAW CHDLC */ - -/* - * Configuration options defines. - */ -/* general options */ -#define WANOPT_OFF 0 -#define WANOPT_ON 1 -#define WANOPT_NO 0 -#define WANOPT_YES 1 - -/* intercace options */ -#define WANOPT_RS232 0 -#define WANOPT_V35 1 - -/* data encoding options */ -#define WANOPT_NRZ 0 -#define WANOPT_NRZI 1 -#define WANOPT_FM0 2 -#define WANOPT_FM1 3 - -/* link type options */ -#define WANOPT_POINTTOPOINT 0 /* RTS always active */ -#define WANOPT_MULTIDROP 1 /* RTS is active when transmitting */ - -/* clocking options */ -#define WANOPT_EXTERNAL 0 -#define WANOPT_INTERNAL 1 - -/* station options */ -#define WANOPT_DTE 0 -#define WANOPT_DCE 1 -#define WANOPT_CPE 0 -#define WANOPT_NODE 1 -#define WANOPT_SECONDARY 0 -#define WANOPT_PRIMARY 1 - -/* connection options */ -#define WANOPT_PERMANENT 0 /* DTR always active */ -#define WANOPT_SWITCHED 1 /* use DTR to setup link (dial-up) */ -#define WANOPT_ONDEMAND 2 /* activate DTR only before sending */ - -/* frame relay in-channel signalling */ -#define WANOPT_FR_ANSI 1 /* ANSI T1.617 Annex D */ -#define WANOPT_FR_Q933 2 /* ITU Q.933A */ -#define WANOPT_FR_LMI 3 /* LMI */ - -/* PPP IP Mode Options */ -#define WANOPT_PPP_STATIC 0 -#define WANOPT_PPP_HOST 1 -#define WANOPT_PPP_PEER 2 - -/* ASY Mode Options */ -#define WANOPT_ONE 1 -#define WANOPT_TWO 2 -#define WANOPT_ONE_AND_HALF 3 - -#define WANOPT_NONE 0 -#define WANOPT_ODD 1 -#define WANOPT_EVEN 2 - -/* CHDLC Protocol Options */ -/* DF Commmented out for now. - -#define WANOPT_CHDLC_NO_DCD IGNORE_DCD_FOR_LINK_STAT -#define WANOPT_CHDLC_NO_CTS IGNORE_CTS_FOR_LINK_STAT -#define WANOPT_CHDLC_NO_KEEPALIVE IGNORE_KPALV_FOR_LINK_STAT -*/ - -/* Port options */ -#define WANOPT_PRI 0 -#define WANOPT_SEC 1 -/* read mode */ -#define WANOPT_INTR 0 -#define WANOPT_POLL 1 - - -#define WANOPT_TTY_SYNC 0 -#define WANOPT_TTY_ASYNC 1 -/*---------------------------------------------------------------------------- * WAN Link Status Info (for ROUTER_STAT IOCTL). */ typedef struct wandev_stat @@ -361,24 +172,12 @@ unsigned reserved[16]; /* reserved for future use */ } wandev_stat_t; -/* 'state' defines */ -enum wan_states -{ - WAN_UNCONFIGURED, /* link/channel is not configured */ - WAN_DISCONNECTED, /* link/channel is disconnected */ - WAN_CONNECTING, /* connection is in progress */ - WAN_CONNECTED, /* link/channel is operational */ - WAN_LIMIT, /* for verification only */ - WAN_DUALPORT, /* for Dual Port cards */ - WAN_DISCONNECTING, - WAN_FT1_READY /* FT1 Configurator Ready */ -}; -enum { - WAN_LOCAL_IP, - WAN_POINTOPOINT_IP, - WAN_NETMASK_IP, - WAN_BROADCAST_IP +/* Front-End status */ +enum fe_status { + FE_UNITIALIZED = 0x00, + FE_DISCONNECTED, + FE_CONNECTED }; /* 'modem_status' masks */ @@ -387,80 +186,76 @@ #define WAN_MODEM_DTR 0x0010 /* DTR line active */ #define WAN_MODEM_RTS 0x0020 /* RTS line active */ -/*---------------------------------------------------------------------------- - * WAN interface (logical channel) configuration (for ROUTER_IFNEW IOCTL). - */ -typedef struct wanif_conf +/* modem status changes */ +#define WAN_DCD_HIGH 0x08 +#define WAN_CTS_HIGH 0x20 + +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) +typedef struct wan_conf { - unsigned magic; /* magic number */ - unsigned config_id; /* configuration identifier */ - char name[WAN_IFNAME_SZ+1]; /* interface name, ASCIIZ */ - char addr[WAN_ADDRESS_SZ+1]; /* media address, ASCIIZ */ - char usedby[USED_BY_FIELD]; /* used by API or WANPIPE */ - unsigned idle_timeout; /* sec, before disconnecting */ - unsigned hold_timeout; /* sec, before re-connecting */ - unsigned cir; /* Committed Information Rate fwd,bwd*/ - unsigned bc; /* Committed Burst Size fwd, bwd */ - unsigned be; /* Excess Burst Size fwd, bwd */ - unsigned char enable_IPX; /* Enable or Disable IPX */ - unsigned char inarp; /* Send Inverse ARP requests Y/N */ - unsigned inarp_interval; /* sec, between InARP requests */ - unsigned long network_number; /* Network Number for IPX */ - char mc; /* Multicast on or off */ - char local_addr[WAN_ADDRESS_SZ+1];/* local media address, ASCIIZ */ - unsigned char port; /* board port */ - unsigned char protocol; /* prococol used in this channel (TCPOX25 or X25) */ - char pap; /* PAP enabled or disabled */ - char chap; /* CHAP enabled or disabled */ - unsigned char userid[511]; /* List of User Id */ - unsigned char passwd[511]; /* List of passwords */ - unsigned char sysname[31]; /* Name of the system */ - unsigned char ignore_dcd; /* Protocol options: */ - unsigned char ignore_cts; /* Ignore these to determine */ - unsigned char ignore_keepalive; /* link status (Yes or No) */ - unsigned char hdlc_streaming; /* Hdlc streaming mode (Y/N) */ - unsigned keepalive_tx_tmr; /* transmit keepalive timer */ - unsigned keepalive_rx_tmr; /* receive keepalive timer */ - unsigned keepalive_err_margin; /* keepalive_error_tolerance */ - unsigned slarp_timer; /* SLARP request timer */ - unsigned char ttl; /* Time To Live for UDP security */ - char interface; /* RS-232/V.35, etc. */ - char clocking; /* external/internal */ - unsigned bps; /* data transfer rate */ - unsigned mtu; /* maximum transmit unit size */ - unsigned char if_down; /* brind down interface when disconnected */ - unsigned char gateway; /* Is this interface a gateway */ - unsigned char true_if_encoding; /* Set the dev->type to true board protocol */ - - unsigned char asy_data_trans; /* async API options */ - unsigned char rts_hs_for_receive; /* async Protocol options */ - unsigned char xon_xoff_hs_for_receive; - unsigned char xon_xoff_hs_for_transmit; - unsigned char dcd_hs_for_transmit; - unsigned char cts_hs_for_transmit; - unsigned char async_mode; - unsigned tx_bits_per_char; - unsigned rx_bits_per_char; - unsigned stop_bits; - unsigned char parity; - unsigned break_timer; - unsigned inter_char_timer; - unsigned rx_complete_length; - unsigned xon_char; - unsigned xoff_char; - unsigned char receive_only; /* no transmit buffering (Y/N) */ -} wanif_conf_t; + devname_t devname; + void* arg; +} wan_conf_t; +#endif + + + +#if defined(WAN_KERNEL) + +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) +# include +# include +# include +# ifdef CONFIG_PRODUCT_WANPIPE_TDM_VOICE +# include +# endif + +#else +//# include +# include +# include +# include +# include +//# include +# include +# include /* support for device drivers */ +# include /* proc filesystem pragmatics */ +# include /* in_aton(), in_ntoa() prototypes */ +//# include /* support for network drivers */ +# ifndef KERNEL_VERSION +# define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) +# endif + +# ifdef CONFIG_PRODUCT_WANPIPE_TDM_VOICE +# include +# endif + +#endif + + +#define REG_PROTOCOL_FUNC(str) wan_set_bit(0, (unsigned long*)&str.init) +#define UNREG_PROTOCOL_FUNC(str) wan_clear_bit(0, (unsigned long*)&str.init) +#define IS_PROTOCOL_FUNC(str) wan_test_bit(0, (unsigned long*)&str.init) + +#define IS_FUNC_CALL(str, func) \ + (IS_PROTOCOL_FUNC(str) && str.func) ? 1 : 0 -#ifdef __KERNEL__ /****** Kernel Interface ****************************************************/ -#include /* support for device drivers */ -#include /* proc filesystem pragmatics */ -#include /* support for network drivers */ + /*---------------------------------------------------------------------------- * WAN device data space. */ -struct wan_device { +struct wan_dev_le { + WAN_LIST_ENTRY(wan_dev_le) dev_link; + netdevice_t *dev; +}; +#define WAN_DEVLE2DEV(devle) (devle && devle->dev) ? devle->dev : NULL +WAN_LIST_HEAD(wan_dev_lhead, wan_dev_le); + + +typedef struct wan_device +{ unsigned magic; /* magic number */ char* name; /* -> WAN device name (ASCIIZ) */ void* private; /* -> driver private data */ @@ -469,8 +264,11 @@ unsigned ioport; /* adapter I/O port base #1 */ char S514_cpu_no[1]; /* PCI CPU Number */ unsigned char S514_slot_no; /* PCI Slot Number */ +#if 0 + //ALEX_TODAY maddr not really used unsigned long maddr; /* dual-port memory address */ unsigned msize; /* dual-port memory size */ +#endif int irq; /* interrupt request level */ int dma; /* DMA request level */ unsigned bps; /* data transfer rate */ @@ -488,53 +286,177 @@ char new_if_cnt; /* Number of interfaces per wanpipe */ char del_if_cnt; /* Number of times del_if() gets called */ unsigned char piggyback; /* Piggibacking a port */ +#if 0 + //ALEX_TODAY hw_opt[0] -> card->type unsigned hw_opt[4]; /* other hardware options */ +#endif /****** status and statistics *******/ char state; /* device state */ char api_status; /* device api status */ struct net_device_stats stats; /* interface statistics */ unsigned reserved[16]; /* reserved for future use */ unsigned long critical; /* critical section flag */ + /* FIXME: use wan_spinlock_t for All OS */ +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) + wan_spinlock_t lock; +#elif defined(__LINUX__) spinlock_t lock; /* Support for SMP Locking */ +#endif /****** device management methods ***/ int (*setup) (struct wan_device *wandev, wandev_conf_t *conf); - int (*shutdown) (struct wan_device *wandev); + int (*shutdown) (struct wan_device *wandev, wandev_conf_t* conf); int (*update) (struct wan_device *wandev); - int (*ioctl) (struct wan_device *wandev, unsigned cmd, - unsigned long arg); - int (*new_if)(struct wan_device *wandev, struct net_device *dev, - wanif_conf_t *conf); - int (*del_if)(struct wan_device *wandev, struct net_device *dev); - /****** maintained by the router ****/ - struct wan_device* next; /* -> next device */ - struct net_device* dev; /* list of network interfaces */ +#if defined(__LINUX__) + int (*ioctl) (struct wan_device *wandev, unsigned cmd, unsigned long arg); +#else + int (*ioctl) (struct wan_device *wandev, u_long cmd, caddr_t arg); +#endif + int (*new_if) (struct wan_device *wandev, netdevice_t *dev, wanif_conf_t *conf); + int (*del_if) (struct wan_device *wandev, netdevice_t *dev); + + /****** maintained by the router ****/ +#if 0 + struct wan_device* next; /* -> next device */ + netdevice_t* dev; /* list of network interfaces */ +#endif + WAN_LIST_ENTRY(wan_device) next; /* -> next device */ + struct wan_dev_lhead dev_head; unsigned ndev; /* number of interfaces */ + +#if defined(__LINUX__) struct proc_dir_entry *dent; /* proc filesystem entry */ + struct proc_dir_entry *link; /* proc filesystem entry per link */ + + // Proc fs functions + int (*get_config_info) (void*, struct seq_file* m, int *); + int (*get_status_info) (void*, struct seq_file* m, int *); + + get_info_t* get_dev_config_info; + get_info_t* get_if_info; + write_proc_t* set_dev_config; + write_proc_t* set_if_info; +#endif + int (*get_info)(void*, struct seq_file* m, int *); + void (*fe_enable_timer) (void* card_id); + void (*te_report_rbsbits) (void* card_id, int channel, unsigned char rbsbits); + void (*te_report_alarms) (void* card_id, unsigned long alarams); + void (*te_link_state) (void* card_id); + int (*te_signaling_config) (void* card_id, unsigned long); + int (*te_disable_signaling) (void* card_id, unsigned long); + int (*te_read_signaling_config) (void* card_id); + int (*report_dtmf) (void* card_id, int, unsigned char); + void (*ec_enable_timer) (void* card_id); + struct { + void (*rbsbits) (void* card_id, int, unsigned char); + void (*alarms) (void* card_id, unsigned long); + void (*dtmf) (void* card_id, wan_event_t*); + void (*hook) (void* card_id, wan_event_t*); + void (*ringtrip) (void* card_id, wan_event_t*); + } event_callback; + unsigned char ignore_front_end_status; + unsigned char line_idle; + unsigned char card_type; + atomic_t if_cnt; + atomic_t if_up_cnt; + wan_sdlc_conf_t sdlc_cfg; + wan_bscstrm_conf_t bscstrm_cfg; + int (*debugging) (struct wan_device *wandev); + int (*debug_read) (void*, void*); + int comm_port; + +#if defined(__LINUX__) + spinlock_t get_map_lock; + int (*get_map)(struct wan_device*,netdevice_t*,struct seq_file* m, int *); + + int (*bind_annexg) (netdevice_t *dev, netdevice_t *adev); + netdevice_t *(*un_bind_annexg) (struct wan_device *wandev,netdevice_t *adev); + void (*get_active_inactive)(struct wan_device*,netdevice_t*,void*); +#endif + +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(CONFIG_PRODUCT_WANPIPE_GENERIC) +#if 0 +/* Moved to common structure */ + int (*protocol_open) (netdevice_t*); + int (*protocol_close) (netdevice_t*); + int (*protocol_send) (netskb_t* skb, netdevice_t*); + struct net_device_stats* (*protocol_ifstats) (netdevice_t*); + int (*protocol_ioctl) (netdevice_t*, struct ifreq*, int); + void (*protocol_tx_timeout) (netdevice_t*); + int (*hdlc_xmit) (netskb_t*, netdevice_t* dev); +#endif + int (*wanpipe_ioctl) (netdevice_t*, struct ifreq*, int); +#endif + unsigned char macAddr[ETHER_ADDR_LEN]; + + sdla_fe_iface_t fe_iface; + sdla_fe_notify_iface_t fe_notify_iface; + + void *ec_dev; + unsigned long ec_enable_map; + unsigned long ec_map; + unsigned long ec_intmask; + int (*ec_enable)(void *pcard, int, int); + + unsigned char (*write_ec)(void*, unsigned short, unsigned char); + unsigned char (*read_ec)(void*, unsigned short); + int (*hwec_reset)(void* card_id, int); + int (*hwec_enable)(void* card_id, int, int); +} wan_device_t; + +WAN_LIST_HEAD(wan_devlist_, wan_device); + +struct wanpipe_fw_register_struct +{ + unsigned char init; + + int (*bind_api_to_svc)(char *devname, void *sk_id); + int (*bind_listen_to_link)(char *devname, void *sk_id, unsigned short protocol); + int (*unbind_listen_from_link)(void *sk_id,unsigned short protocol); }; /* Public functions available for device drivers */ -extern int register_wan_device(struct wan_device *wandev); +extern int register_wan_device(wan_device_t *wandev); extern int unregister_wan_device(char *name); -__be16 wanrouter_type_trans(struct sk_buff *skb, struct net_device *dev); -int wanrouter_encapsulate(struct sk_buff *skb, struct net_device *dev, - unsigned short type); +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) +extern char* in_ntoa(uint32_t in); +extern int wanpipe_lip_rx(void *chan, void *sk_id); +extern int wanpipe_lip_connect(void *chan, int ); +extern int wanpipe_lip_disconnect(void *chan, int); +extern int wanpipe_lip_kick(void *chan,int); +extern int wanpipe_lip_get_if_status(void *chan, void *m); +#elif defined(__LINUX__) +unsigned short wanrouter_type_trans(struct sk_buff *skb, netdevice_t *dev); +int wanrouter_encapsulate(struct sk_buff *skb, netdevice_t *dev,unsigned short type); + +extern int wanrouter_ioctl( struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); /* Proc interface functions. These must not be called by the drivers! */ extern int wanrouter_proc_init(void); extern void wanrouter_proc_cleanup(void); -extern int wanrouter_proc_add(struct wan_device *wandev); -extern int wanrouter_proc_delete(struct wan_device *wandev); -extern int wanrouter_ioctl( struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); - -extern void lock_adapter_irq(spinlock_t *lock, unsigned long *smp_flags); -extern void unlock_adapter_irq(spinlock_t *lock, unsigned long *smp_flags); - - - -/* Public Data */ -/* list of registered devices */ -extern struct wan_device *wanrouter_router_devlist; +extern int wanrouter_proc_add(wan_device_t *wandev); +extern int wanrouter_proc_delete(wan_device_t *wandev); +extern int wanrouter_proc_add_protocol(wan_device_t* wandev); +extern int wanrouter_proc_delete_protocol(wan_device_t* wandev); +extern int wanrouter_proc_add_interface(wan_device_t*,struct proc_dir_entry**, + char*,void*); +extern int wanrouter_proc_delete_interface(wan_device_t*, char*); + +extern void *sdla_get_hw_probe(void); +extern int wanrouter_proc_usage_check(void); +extern int wan_run_wanrouter(char* hwdevname, char *devname, char *action); + +extern int register_wanpipe_fw_protocol (struct wanpipe_fw_register_struct *wp_fw_reg); +extern void unregister_wanpipe_fw_protocol (void); + +extern void wan_skb_destructor (struct sk_buff *skb); +#endif + +void *wanpipe_ec_register(void*, int); +int wanpipe_ec_unregister(void*,void*); +int wanpipe_ec_isr(void*,void*); +int wanpipe_ec_poll(void*,void*); +int wanpipe_ec_event_ctrl(void*,void*,wan_event_ctrl_t*); #endif /* __KERNEL__ */ #endif /* _ROUTER_H */ diff -Nur linux.org/net/wanrouter/af_wanpipe_annexg_api.c linux-2.6.17/net/wanrouter/af_wanpipe_annexg_api.c --- linux.org/net/wanrouter/af_wanpipe_annexg_api.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/net/wanrouter/af_wanpipe_annexg_api.c 2006-08-30 10:07:16.000000000 +0000 @@ -0,0 +1,1700 @@ +/***************************************************************************** +* af_wanpipe_annexg_api.c +* +* WANPIPE(tm) Annexg Secure Socket Layer. +* +* Author: Nenad Corbic +* +* Copyright: (c) 2003 Sangoma Technologies Inc. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version +* 2 of the License, or (at your option) any later version. +* ============================================================================ +* Due Credit: +* Wanpipe socket layer is based on Packet and +* the X25 socket layers. The above sockets were +* used for the specific use of Sangoma Technoloiges +* API programs. +* Packet socket Authors: Ross Biro, Fred N. van Kempen and +* Alan Cox. +* X25 socket Author: Jonathan Naylor. +* ============================================================================ +* Apr 25, 2000 Nenad Corbic o Added the ability to send zero length packets. +* Mar 13, 2000 Nenad Corbic o Added a tx buffer check via ioctl call. +* Mar 06, 2000 Nenad Corbic o Fixed the corrupt sock lcn problem. +* Server and client applicaton can run +* simultaneously without conflicts. +* Feb 29, 2000 Nenad Corbic o Added support for PVC protocols, such as +* CHDLC, Frame Relay and HDLC API. +* Jan 17, 2000 Nenad Corbic o Initial version, based on AF_PACKET socket. +* X25API support only. +* +******************************************************************************/ + +#include +#include +#include +#include +#include + +#ifdef CONFIG_PRODUCT_WANPIPE_ANNEXG +#include "wanpipe_annexg_api.h" +#include "wanpipe_x25_kernel.h" +#include "wanpipe_dsp_kernel.h" +#endif + + +#if defined(LINUX_2_1) + #define dev_put(a) + #define __sock_put(a) + #define sock_hold(a) + #define DECLARE_WAITQUEUE(a,b) \ + struct wait_queue a = { b, NULL } +#endif + + +#define AF_DEBUG_MEM +#ifdef AF_DEBUG_MEM + + #define AF_SKB_DEC(x) atomic_sub(x,&af_skb_alloc) + #define AF_SKB_INC(x) atomic_add(x,&af_skb_alloc) + + #define ALLOC_SKB(skb,len) { skb = dev_alloc_skb(len); \ + if (skb != NULL) AF_SKB_INC(skb->truesize); } + #define KFREE_SKB(skb) { AF_SKB_DEC(skb->truesize); dev_kfree_skb_any(skb); } + + + #define AF_MEM_DEC(x) atomic_sub(x,&af_mem_alloc) + #define AF_MEM_INC(x) atomic_add(x,&af_mem_alloc) + + #define KMALLOC(ptr,len,flag) { ptr=kmalloc(len, flag); \ + if (ptr != NULL) AF_MEM_INC(len); } + #define KFREE(ptr) {AF_MEM_DEC(sizeof(*ptr)); kfree(ptr);} + +#else + #define KMALLOC(ptr,len,flag) ptr=kmalloc(len, flag) + #define KFREE(ptr) kfree(ptr) + + #define ALLOC_SKB(new_skb,len, dsp) new_skb = dev_alloc_skb(len) + #define KFREE_SKB(skb) dev_kfree_skb_any(skb) + + #define AF_SKB_DEC(x) + #define AF_SKB_INC(x) + #define AF_MEM_DEC(x) + #define AF_MEM_INC(x) +#endif + + + + +/* The code below is used to test memory leaks. It prints out + * a message every time kmalloc and kfree system calls get executed. + * If the calls match there is no leak :) + */ + +/***********FOR DEBUGGING PURPOSES********************************************* +#define KMEM_SAFETYZONE 8 + +static void * dbg_kmalloc(unsigned int size, int prio, int line) { + void * v = kmalloc(size,prio); + printk(KERN_INFO "line %d kmalloc(%d,%d) = %p\n",line,size,prio,v); + return v; +} +static void dbg_kfree(void * v, int line) { + printk(KERN_INFO "line %d kfree(%p)\n",line,v); + kfree(v); +} + +#define kmalloc(x,y) dbg_kmalloc(x,y,__LINE__) +#define kfree(x) dbg_kfree(x,__LINE__) +******************************************************************************/ + +/* List of all wanpipe sockets. */ +static struct sock * wanpipe_sklist = NULL; + +static rwlock_t wanpipe_sklist_lock = RW_LOCK_UNLOCKED; + +static atomic_t af_mem_alloc; +static atomic_t af_skb_alloc; + +static atomic_t wanpipe_socks_nr; +extern struct proto_ops wanpipe_ops; + +static struct sock *wanpipe_annexg_alloc_socket(void); +static void check_write_queue(struct sock *); + + +void wanpipe_annexg_kill_sock(struct sock *sock); + +#if 0 +void af_wan_sock_rfree(struct sk_buff *skb) +{ + struct sock *sk = skb->sk; + atomic_sub(skb->truesize, &sk->rmem_alloc); + wan_skb_destructor(skb); +} + +void wan_skb_set_owner_r(struct sk_buff *skb, struct sock *sk) +{ + skb->sk = sk; + skb->destructor = af_wan_sock_rfree; + atomic_add(skb->truesize, &sk->rmem_alloc); +} +#endif + +static inline void af_skb_queue_purge(struct sk_buff_head *list) +{ + struct sk_buff *skb; + while ((skb=skb_dequeue(list))!=NULL){ + KFREE_SKB(skb); + } +} + + +/*============================================================ + * wanpipe_annexg_ioctl + * + * Execute a user commands, and set socket options. + * + * FIXME: More thought should go into this function. + * + *===========================================================*/ + +int wanpipe_annexg_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) +{ + struct sock *sk = sock->sk; + int err; + int pid; + + if (!sk->bound_dev_if) + return -EINVAL; + + switch(cmd) + { + case FIOSETOWN: + case SIOCSPGRP: + err = get_user(pid, (int *) arg); + if (err) + return err; + if (current->pid != pid && current->pgrp != -pid && + !capable(CAP_NET_ADMIN)) + return -EPERM; + sk->proc = pid; + return(0); + + case FIOGETOWN: + case SIOCGPGRP: + return put_user(sk->proc, (int *)arg); + + case SIOCGSTAMP: + if(sk->stamp.tv_sec==0) + return -ENOENT; + err = -EFAULT; + if (!copy_to_user((void *)arg, &sk->stamp, sizeof(struct timeval))) + err = 0; + return err; + + case SIOC_WANPIPE_CHECK_TX: + if (atomic_read(&sk->wmem_alloc)) + return 1; + + goto dev_private_ioctl; + + case SIOC_WANPIPE_SOCK_STATE: + + if (sk->state == WANSOCK_CONNECTED) + return 0; + + return 1; + + case SIOC_WANPIPE_SET_NONBLOCK: + + if (sk->state != WANSOCK_DISCONNECTED) + return -EINVAL; + + sock->file->f_flags |= O_NONBLOCK; + return 0; + + case SIOCGIFFLAGS: +#ifndef CONFIG_INET + case SIOCSIFFLAGS: +#endif + case SIOCGIFCONF: + case SIOCGIFMETRIC: + case SIOCSIFMETRIC: + case SIOCGIFMEM: + case SIOCSIFMEM: + case SIOCGIFMTU: + case SIOCSIFMTU: + case SIOCSIFLINK: + case SIOCGIFHWADDR: + case SIOCSIFHWADDR: + case SIOCSIFMAP: + case SIOCGIFMAP: + case SIOCSIFSLAVE: + case SIOCGIFSLAVE: + case SIOCGIFINDEX: + case SIOCGIFNAME: + case SIOCGIFCOUNT: + case SIOCSIFHWBROADCAST: + return(dev_ioctl(cmd,(void *) arg)); + +#ifdef CONFIG_INET + case SIOCADDRT: + case SIOCDELRT: + case SIOCDARP: + case SIOCGARP: + case SIOCSARP: + case SIOCDRARP: + case SIOCGRARP: + case SIOCSRARP: + case SIOCGIFADDR: + case SIOCSIFADDR: + case SIOCGIFBRDADDR: + case SIOCSIFBRDADDR: + case SIOCGIFNETMASK: + case SIOCSIFNETMASK: + case SIOCGIFDSTADDR: + case SIOCSIFDSTADDR: + case SIOCSIFFLAGS: + case SIOCADDDLCI: + case SIOCDELDLCI: + return inet_dgram_ops.ioctl(sock, cmd, arg); +#endif + + default: + if ((cmd >= SIOCDEVPRIVATE) && + (cmd <= (SIOCDEVPRIVATE + 35))){ + netdevice_t *dev; + struct ifreq ifr; +dev_private_ioctl: + dev = (struct net_device *)sk->user_data; + if (!dev) + return -ENODEV; + + if (!dev->do_ioctl) + return -ENODEV; + + ifr.ifr_data = (void*)arg; + + return dev->do_ioctl(dev,&ifr,cmd); + } + return -EOPNOTSUPP; + + } + /*NOTREACHED*/ +} + + + +/*============================================================ + * wanpipe_annexg_make_new + * + * Create a new sock, and allocate a wanpipe private + * structure to it. Also, copy the important data + * from the original sock to the new sock. + * + * This function is used by wanpipe_listen_rcv() listen + * bottom half handler. A copy of the listening sock + * is created using this function. + * + *===========================================================*/ + +static struct sock *wanpipe_annexg_make_new(struct sock *osk) +{ + struct sock *sk; + + if (osk->type != SOCK_RAW) + return NULL; + + if ((sk = wanpipe_annexg_alloc_socket()) == NULL) + return NULL; + + sk->family = osk->family; + sk->type = osk->type; + sk->socket = osk->socket; + sk->priority = osk->priority; + sk->protocol = osk->protocol; + sk->num = osk->num; + sk->rcvbuf = osk->rcvbuf; + sk->sndbuf = osk->sndbuf; + sk->debug = osk->debug; + sk->state = WANSOCK_CONNECTING; + sk->sleep = osk->sleep; + + return sk; +} + + + +/*============================================================ + * wanpipe_annexg_listen_rcv + * + * Wanpipe LISTEN socket bottom half handler. This function + * is called by the WANPIPE device drivers to queue an + * incomming call into the socket listening queue. + * Once the packet is queued, the waiting accept() process + * is woken up. + * + * During socket bind, this function is bounded into + * WANPIPE driver private. + * + * IMPORTANT NOTE: + * The accept call() is waiting for an skb packet + * which contains a pointer to a device structure. + * + * When we do a bind to a device structre, we + * bind a newly created socket into "chan->sk". Thus, + * when accept receives the skb packet, it will know + * from which dev it came form, and in turn it will know + * the address of the new sock. + * + * NOTE: This function gets called from driver ISR. + *===========================================================*/ + +static int wanpipe_annexg_listen_rcv (struct sk_buff *skb, struct sock *sk) +{ + + struct wan_sockaddr_ll *sll; + struct sock *newsk; + netdevice_t *dev; + x25api_hdr_t *x25_api_hdr; + struct ifreq ifr; + unsigned long flags; + + if (!sk){ + printk(KERN_INFO "Wanpipe listen recv error! No skid!\n"); + return 0; + } + + /* If we receive a NULL skb pointer, it means that the + * lower layer is dead. Change state and wakeup any waiting + * processes. */ + if (!skb){ + sk->state = WANSOCK_BIND_LISTEN; + sk->data_ready(sk,0); + return 0; + } + + if (sk->state != WANSOCK_LISTEN){ + printk(KERN_INFO "wansock_annexg: Listen rcv in disconnected state!\n"); + sk->data_ready(sk,0); + return -EINVAL; + } + + /* Check if the receive buffer will hold the incoming + * call request */ + if (atomic_read(&sk->rmem_alloc) + skb->truesize >= + (unsigned)sk->rcvbuf){ + + return -ENOMEM; + } + + + sll = (struct wan_sockaddr_ll*)skb->cb; + + dev = skb->dev; + if (!dev){ + printk(KERN_INFO "wansock_annexg: LISTEN ERROR, No Free Device\n"); + return -ENODEV; + } + + /* Allocate a new sock, which accept will bind + * and pass up to the user + */ + if ((newsk = wanpipe_annexg_make_new(sk)) == NULL){ + return -ENOMEM; + } + + /* Bind the new socket into the lower layer. The lower + * layer will increment the sock reference count. */ + ifr.ifr_data = (void*)newsk; + if (!dev->do_ioctl || dev->do_ioctl(dev,&ifr,SIOC_ANNEXG_BIND_SK) != 0){ + wanpipe_annexg_kill_sock(newsk); + return -ENODEV; + } + + newsk->zapped=1; + newsk->bound_dev_if = dev->ifindex; + dev_hold(dev); + newsk->user_data = dev; + + write_lock_irqsave(&wanpipe_sklist_lock,flags); + newsk->next = wanpipe_sklist; + wanpipe_sklist = newsk; + sock_hold(newsk); + write_unlock_irqrestore(&wanpipe_sklist_lock,flags); + + /* Insert the sock into the main wanpipe + * sock list. + */ + atomic_inc(&wanpipe_socks_nr); + + /* Register the lcn on which incoming call came + * from. Thus, if we have to clear it, we know + * whic lcn to clear + */ + + //FIXME Obtain the LCN from the SKB buffer + x25_api_hdr = (x25api_hdr_t*)skb->data; + + newsk->num = skb->protocol; + newsk->state = WANSOCK_CONNECTING; + + /* Fill in the standard sock address info */ + + sll->sll_family = AF_ANNEXG_WANPIPE; + sll->sll_hatype = dev->type; + sll->sll_protocol = newsk->num; + sll->sll_pkttype = skb->pkt_type; + sll->sll_ifindex = dev->ifindex; + sll->sll_halen = 0; + + sk->ack_backlog++; + + /* We also store the new sock pointer in side the + * skb buffer, just incase the lower layer disapears, + * or gets unconfigured */ + sock_hold(newsk); + *(unsigned long *)&skb->data[0]=(unsigned long)newsk; + + dev_put(skb->dev); + skb->dev=NULL; + + AF_SKB_INC(skb->truesize); + + /* We must do this manually, since the sock_queue_rcv_skb() + * function sets the skb->dev to NULL. However, we use + * the dev field in the accept function.*/ + + skb_set_owner_r(skb, sk); + sk->data_ready(sk,skb->len); + skb_queue_tail(&sk->receive_queue, skb); + + return 0; +} + + +/*====================================================================== + * wanpipe_annexg_listen + * + * X25API Specific function. Set a socket into LISTENING MODE. + *=====================================================================*/ + + +int wanpipe_annexg_listen(struct socket *sock, int backlog) +{ + struct sock *sk = sock->sk; + + /* This is x25 specific area if protocol doesn't + * match, return error */ + if (sk->num != htons(ETH_P_X25) && sk->num != htons(DSP_PROT)) + return -EINVAL; + + if (sk->state == WANSOCK_BIND_LISTEN) { + + sk->max_ack_backlog = backlog; + sk->state = WANSOCK_LISTEN; + return 0; + }else{ + printk(KERN_INFO "wansock_annexg: Listening sock was not binded\n"); + } + + return -EINVAL; +} + + + + +/*====================================================================== + * wanpipe_annexg_accept + * + * ACCEPT() System call. X25API Specific function. + * For each incoming call, create a new socket and + * return it to the user. + *=====================================================================*/ + +int wanpipe_annexg_accept(struct socket *sock, struct socket *newsock, int flags) +{ + struct sock *sk; + struct sock *newsk=NULL, *newsk_frmskb=NULL; + struct sk_buff *skb; + DECLARE_WAITQUEUE(wait, current); + int err=-EINVAL; + struct ifreq ifr; + + if (newsock->sk != NULL){ + printk(KERN_INFO "wansock_annexg: Accept is Releaseing an unused sock !\n"); + wanpipe_annexg_kill_sock(newsock->sk); + newsock->sk=NULL; + } + + if ((sk = sock->sk) == NULL) + return -ENOTSOCK; + + if (sk->type != SOCK_RAW) + return -EOPNOTSUPP; + + if (sk->state != WANSOCK_LISTEN) + return -ENETDOWN; + + if (sk->num != htons(ETH_P_X25) &&sk->num != htons(DSP_PROT)) + return -EPROTOTYPE; + + add_wait_queue(sk->sleep,&wait); + current->state = TASK_INTERRUPTIBLE; + for (;;){ + skb = skb_dequeue(&sk->receive_queue); + if (skb){ + err=0; + break; + } + + if (sk->state != WANSOCK_LISTEN){ + err = -ENETDOWN; + break; + } + + if (signal_pending(current)) { + err = -ERESTARTSYS; + break; + } + schedule(); + } + current->state = TASK_RUNNING; + remove_wait_queue(sk->sleep,&wait); + + if (err != 0) + return err; + + ifr.ifr_data=NULL; + + newsk=(struct sock*)*(unsigned long *)&skb->data[0]; + if (newsk){ + + struct net_device *dev; + + /* Decrement the usage count of newsk, since + * we go the pointer for skb */ + __sock_put(newsk); + + if (newsk->zapped && (dev = (struct net_device *)newsk->user_data)){ + if (dev && dev->do_ioctl){ + struct sock* dev_sk; + dev->do_ioctl(dev,&ifr,SIOC_ANNEXG_GET_SK); + + if ((dev_sk=(struct sock*)ifr.ifr_data)!=NULL){ + __sock_put(dev_sk); + + if (dev_sk == newsk){ + /* Got the right device with correct + * sk_id */ + goto accept_newsk_ok; + }else{ + /* This should never happen */ + printk(KERN_INFO "wansock_annexg: Accept killing newsk, layer ptr mismatch!\n"); + } + }else{ + printk(KERN_INFO "wansock_annexg: Accept killing newsk, get sk failed!\n"); + } + + ifr.ifr_data=(void*)newsk; + if (dev->do_ioctl(dev,&ifr,SIOC_ANNEXG_UNBIND_SK)==0){ + dev->do_ioctl(dev,NULL,SIOC_ANNEXG_CLEAR_CALL); + } + }else{ + printk(KERN_INFO "wansock_annexg: Accept killing newsk, lower layer down!\n"); + } + }else{ + /* This can happen if the device goes down, before we get + * the chance to accept the call */ + printk(KERN_INFO "wansock_annexg: Accept killing newsk, newsk not zapped!\n"); + } + + newsk->dead=1; + wanpipe_annexg_kill_sock(newsk); + + KFREE_SKB(skb); + return -EINVAL; + }else{ + KFREE_SKB(skb); + return -ENODEV; + } + +accept_newsk_ok: + newsk->pair = NULL; + newsk->socket = newsock; + newsk->sleep = &newsock->wait; + + /* Now attach up the new socket */ + sk->ack_backlog--; + newsock->sk = newsk; + + if (newsk_frmskb){ + __sock_put(newsk_frmskb); + newsk_frmskb=NULL; + } + KFREE_SKB(skb); + return 0; +} + + + + +/*============================================================ + * wanpipe_annexg_api_sock_rcv + * + * Wanpipe socket bottom half handler. This function + * is called by the WANPIPE device drivers to queue a + * incomming packet into the socket receive queue. + * Once the packet is queued, all processes waiting to + * read are woken up. + * + * During socket bind, this function is bounded into + * WANPIPE driver private. + *===========================================================*/ + +static int wanpipe_annexg_api_sock_rcv(struct sk_buff *skb, netdevice_t *dev, struct sock *sk) +{ + struct wan_sockaddr_ll *sll = (struct wan_sockaddr_ll*)skb->cb; + /* + * When we registered the protocol we saved the socket in the data + * field for just this event. + */ + + if (!sk->zapped){ + return -EINVAL; + } + + sll->sll_family = AF_ANNEXG_WANPIPE; + sll->sll_hatype = dev->type; + sll->sll_protocol = skb->protocol; + sll->sll_pkttype = skb->pkt_type; + sll->sll_ifindex = dev->ifindex; + sll->sll_halen = 0; + + if (dev->hard_header_parse) + sll->sll_halen = dev->hard_header_parse(skb, sll->sll_addr); + + /* + * WAN_PACKET_DATA : Data which should be passed up the receive queue. + * WAN_PACKET_ASYC : Asynchronous data like place call, which should + * be passed up the listening sock. + * WAN_PACKET_ERR : Asynchronous data like clear call or restart + * which should go into an error queue. + */ + + AF_SKB_INC(skb->truesize); + switch (skb->pkt_type){ + + case WAN_PACKET_DATA: + if (sock_queue_rcv_skb(sk,skb)<0){ + AF_SKB_DEC(skb->truesize); + return -ENOMEM; + } + break; + case WAN_PACKET_CMD: + /* Bug fix: update Mar6. + * Do not set the sock lcn number here, since + * cmd is not guaranteed to be executed on the + * board, thus Lcn could be wrong */ + sk->data_ready(sk,skb->len); + KFREE_SKB(skb); + break; + case WAN_PACKET_ERR: + if (sock_queue_err_skb(sk,skb)<0){ + AF_SKB_DEC(skb->truesize); + return -ENOMEM; + } + break; + default: + printk(KERN_INFO "wansock_annexg: BH Illegal Packet Type Dropping\n"); + KFREE_SKB(skb); + break; + } + + return 0; +} + +/*============================================================ + * wanpipe_annexg_alloc_socket + * + * Allocate memory for the a new sock, and sock + * private data. + * + * Increment the module use count. + * + *===========================================================*/ + +static struct sock *wanpipe_annexg_alloc_socket(void) +{ + struct sock *sk; + + if ((sk = sk_alloc(PF_WANPIPE, GFP_ATOMIC, 1)) == NULL) + return NULL; + + AF_MEM_INC(sizeof(struct sock)); + + MOD_INC_USE_COUNT; + sock_init_data(NULL, sk); + return sk; +} + + +/*============================================================ + * wanpipe_annexg_sendmsg + * + * This function implements a sendto() system call, + * for AF_WANPIPE socket family. + * During socket bind() sk->bound_dev_if is initialized + * to a correct network device. This number is used + * to find a network device to which the packet should + * be passed to. + * + * Each packet is queued into sk->write_queue and + * delayed transmit bottom half handler is marked for + * execution. + * + * A socket must be in WANSOCK_CONNECTED state before + * a packet is queued into sk->write_queue. + *===========================================================*/ + +int wanpipe_annexg_sendmsg(struct socket *sock, struct msghdr *msg, int len, + struct scm_cookie *scm) +{ + struct sock *sk = sock->sk; + struct wan_sockaddr_ll *saddr=(struct wan_sockaddr_ll *)msg->msg_name; + struct sk_buff *skb; + netdevice_t *dev; + unsigned short proto; + unsigned char *addr; + int ifindex, err=-EINVAL, reserve = 0; + + + if (!sk->zapped) + return -ENETDOWN; + + if (sk->state != WANSOCK_CONNECTED) + return -ENOTCONN; + + if (msg->msg_flags&~MSG_DONTWAIT) + return(-EINVAL); + + /* it was <=, now one can send + * zero length packets */ + if (sk->protocol == htons(ETH_P_X25) && (len < sizeof(x25api_hdr_t))) + return -EINVAL; + if (sk->protocol == htons(DSP_PROT) && (len < sizeof(dspapi_hdr_t))) + return -EINVAL; + + if (saddr == NULL) { + ifindex = sk->bound_dev_if; + proto = sk->num; + addr = NULL; + + }else{ + if (msg->msg_namelen < sizeof(struct wan_sockaddr_ll)){ + return -EINVAL; + } + + ifindex = sk->bound_dev_if; + proto = saddr->sll_protocol; + addr = saddr->sll_addr; + } + + dev = (struct net_device *)sk->user_data; + if (dev == NULL){ + printk(KERN_INFO "wansock_annexg: Send failed, dev index: %i\n",ifindex); + return -ENXIO; + } + + if (netif_queue_stopped(dev)) + return -EBUSY; + + if (sock->type == SOCK_RAW) + reserve = dev->hard_header_len; + + if (len > dev->mtu+reserve){ + return -EMSGSIZE; + } + + #ifndef LINUX_2_4 + dev_lock_list(); + #endif + + ALLOC_SKB(skb,len+dev->hard_header_len+15); + if (skb==NULL){ + goto out_unlock; + } + + skb_reserve(skb, (dev->hard_header_len+15)&~15); + skb->nh.raw = skb->data; + + /* Returns -EFAULT on error */ + err = memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len); + if (err){ + goto out_free; + } + + if (dev->hard_header) { + int res; + err = -EINVAL; + res = dev->hard_header(skb, dev, ntohs(proto), addr, NULL, len); + if (res<0){ + goto out_free; + } + } + + skb->protocol = proto; + skb->priority = sk->priority; + skb->pkt_type = WAN_PACKET_DATA; + + err = -ENETDOWN; + if (!(dev->flags & IFF_UP)) + goto out_free; + + #ifndef LINUX_2_4 + dev_unlock_list(); + #endif + + AF_SKB_DEC(skb->truesize); + if (!dev->hard_start_xmit(skb,dev)){ + return(len); + }else{ + err = -EBUSY; + } + AF_SKB_INC(skb->truesize); + +out_free: + KFREE_SKB(skb); +out_unlock: +#ifndef LINUX_2_4 + dev_unlock_list(); +#endif + return err; +} + +/*============================================================ + * wanpipe_annexg_kill_sock + * + * Used by wanpipe_release, to delay release of + * the socket. + *===========================================================*/ +void wanpipe_annexg_kill_sock (struct sock *sk) +{ + + struct sock **skp; + unsigned long flags; + + if (!sk) + return; + + sk->state = WANSOCK_DISCONNECTED; + sk->zapped=0; + sk->bound_dev_if=0; + if (sk->user_data){ + dev_put((struct net_device*)sk->user_data); + } + sk->user_data=NULL; + + /* This functin can be called from interrupt. We must use + * appropriate locks */ + + write_lock_irqsave(&wanpipe_sklist_lock,flags); + for (skp = &wanpipe_sklist; *skp; skp = &(*skp)->next) { + if (*skp == sk) { + *skp = sk->next; + __sock_put(sk); + break; + } + } + write_unlock_irqrestore(&wanpipe_sklist_lock,flags); + + sk->socket = NULL; + + /* Purge queues */ + af_skb_queue_purge(&sk->receive_queue); + af_skb_queue_purge(&sk->error_queue); + + #ifdef LINUX_2_4 + if (atomic_read(&sk->refcnt) != 1){ + DEBUG_TEST("wansock_annexg: Error, wrong reference count: %i ! :Kill.\n", + atomic_read(&sk->refcnt)); + atomic_set(&sk->refcnt,1); + } + sock_put(sk); + #else + sk_free(sk); + #endif + AF_MEM_DEC(sizeof(struct sock)); + atomic_dec(&wanpipe_socks_nr); + MOD_DEC_USE_COUNT; + return; +} + + +static void release_queued_pending_sockets(struct sock *sk) +{ + netdevice_t *dev; + struct sk_buff *skb; + struct sock *deadsk; + + while ((skb=skb_dequeue(&sk->receive_queue))!=NULL){ + deadsk=(struct sock *)*(unsigned long*)&skb->data[0]; + if (!deadsk){ + KFREE_SKB(skb); + continue; + } + + deadsk->dead=1; + printk (KERN_INFO "wansock_annexg: Release: found dead sock!\n"); + dev = (struct net_device *)deadsk->user_data; + if (dev && dev->do_ioctl){ + struct ifreq ifr; + ifr.ifr_data=(void*)sk; + if (dev->do_ioctl(dev,&ifr,SIOC_ANNEXG_UNBIND_SK)==0){ + dev->do_ioctl(dev,NULL,SIOC_ANNEXG_CLEAR_CALL); + } + } + + /* Decrement the sock refcnt, since we took + * the pointer out of the skb buffer */ + __sock_put(deadsk); + wanpipe_annexg_kill_sock(deadsk); + KFREE_SKB(skb); + } +} + + +/*============================================================ + * wanpipe_annexg_release + * + * Close a PACKET socket. This is fairly simple. We + * immediately go to 'closed' state and remove our + * protocol entry in the device list. + *===========================================================*/ + +#ifdef LINUX_2_4 +int wanpipe_annexg_release(struct socket *sock) +#else +int wanpipe_annexg_release(struct socket *sock, struct socket *peersock) +#endif +{ + +#ifndef LINUX_2_4 + struct sk_buff *skb; +#endif + struct sock *sk = sock->sk; + struct sock **skp; + unsigned long flags; + + if (!sk) + return 0; + + check_write_queue(sk); + + /* Kill the tx timer, if we don't kill it now, the timer + * will run after we kill the sock. Timer code will + * try to access the sock which has been killed and cause + * kernel panic */ + + /* + * Unhook packet receive handler. + */ + + if (sk->state == WANSOCK_LISTEN || sk->state == WANSOCK_BIND_LISTEN){ + unbind_api_listen_from_protocol (sk->num,sk); + release_queued_pending_sockets(sk); + + }else if ((sk->num == htons(ETH_P_X25) || sk->num == htons(DSP_PROT))&& sk->zapped){ + netdevice_t *dev = (struct net_device *)sk->user_data; + if (dev){ + if(dev->do_ioctl){ + struct ifreq ifr; + ifr.ifr_data=(void*)sk; + if (dev->do_ioctl(dev,&ifr,SIOC_ANNEXG_UNBIND_SK)==0){ + dev->do_ioctl(dev,NULL,SIOC_ANNEXG_CLEAR_CALL); + } + } + } + } + + sk->state = WANSOCK_DISCONNECTED; + sk->zapped=0; + sk->bound_dev_if=0; + if (sk->user_data){ + dev_put((struct net_device*)sk->user_data); + } + sk->user_data=NULL; + + //FIXME with spinlock_irqsave + write_lock_irqsave(&wanpipe_sklist_lock,flags); + for (skp = &wanpipe_sklist; *skp; skp = &(*skp)->next) { + if (*skp == sk) { + *skp = sk->next; + __sock_put(sk); + break; + } + } + write_unlock_irqrestore(&wanpipe_sklist_lock,flags); + + + + /* + * Now the socket is dead. No more input will appear. + */ + + sk->state_change(sk); /* It is useless. Just for sanity. */ + + sock->sk = NULL; + sk->socket = NULL; + sk->dead = 1; + + /* Purge queues */ + af_skb_queue_purge(&sk->receive_queue); + af_skb_queue_purge(&sk->error_queue); + + #ifdef LINUX_2_4 + if (atomic_read(&sk->refcnt) != 1){ + DEBUG_TEST("wansock_annexg: Error, wrong reference count: %i !:release.\n", + atomic_read(&sk->refcnt)); + atomic_set(&sk->refcnt,1); + } + sock_put(sk); + #else + sk_free(sk); + #endif + AF_MEM_DEC(sizeof(struct sock)); + atomic_dec(&wanpipe_socks_nr); + + MOD_DEC_USE_COUNT; + + return 0; +} + +/*============================================================ + * check_write_queue + * + * During sock shutdown, if the sock state is + * WANSOCK_CONNECTED and there is transmit data + * pending. Wait until data is released + * before proceeding. + *===========================================================*/ + +static void check_write_queue(struct sock *sk) +{ + + if (sk->state != WANSOCK_CONNECTED) + return; + + if (!atomic_read(&sk->wmem_alloc)) + return; + + printk(KERN_INFO "wansock_annexg: MAJOR ERROR, Data lost on sock release !!!\n"); + +} + + +/*============================================================ + * wanpipe_annexg_bind + * + * BIND() System call, which is bound to the AF_WANPIPE + * operations structure. It checks for correct wanpipe + * card name, and cross references interface names with + * the card names. Thus, interface name must belong to + * the actual card. + *===========================================================*/ + + +int wanpipe_annexg_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) +{ + struct wan_sockaddr_ll *sll = (struct wan_sockaddr_ll*)uaddr; + struct sock *sk=sock->sk; + netdevice_t *dev = NULL; + char name[15]; + int err=-EINVAL; + + /* + * Check legality + */ + + if (addr_len < sizeof(struct wan_sockaddr_ll)){ + printk(KERN_INFO "wansock_annexg: Address length error\n"); + return -EINVAL; + } + if (sll->sll_family != AF_ANNEXG_WANPIPE){ + printk(KERN_INFO "wansock_annexg: Illegal family name specified.\n"); + return -EINVAL; + } + + sk->num = sll->sll_protocol ? sll->sll_protocol : sk->num; + + if (!strcmp(sll->sll_device,"svc_connect") || + !strcmp(sll->sll_device,"dsp_connect")){ + + strncpy(name,sll->sll_card,14); + name[14]=0; + + /* Obtain the master device, in case of Annexg this + * device would be a lapb network interface, note + * the usage count on dev will be incremented, once + * we are finshed with the device we should run + * dev_put() to release it */ +#ifdef LINUX_2_4 + dev = dev_get_by_name(name); +#else + dev = dev_get(name); +#endif + if (dev == NULL){ + printk(KERN_INFO "wansock_annexg: Failed to get Dev from name: %s,\n", + name); + return -ENODEV; + } + + if (!(dev->flags&IFF_UP)){ + printk(KERN_INFO "wansock_annexg: Bind device %s is down!\n", + name); + dev_put(dev); + return -ENODEV; + } + + sk->bound_dev_if = bind_api_to_protocol(dev,sk->num,(void*)sk); + + /* We are finished with the lapb master device, we + * need it to find a free svc or dsp device but now + * we can release it */ + dev_put(dev); + + if (sk->bound_dev_if < 0){ + sk->bound_dev_if=0; + err=-EINVAL; + }else{ + sk->state = WANSOCK_DISCONNECTED; + sk->user_data=dev_get_by_index(sk->bound_dev_if); + if (sk->user_data){ + err=0; + }else{ + /* This should never ever happen !*/ + err=-EINVAL; + } + } + + }else if (!strcmp(sll->sll_device,"svc_listen") || + !strcmp(sll->sll_device,"dsp_listen")){ + + strncpy(name,sll->sll_card,14); + name[14]=0; + + /* Obtain the master device, in case of Annexg this + * device would be a lapb network interface, note + * the usage count on dev will be incremented, once + * we are finshed with the device we should run + * dev_put() to release it */ + +#ifdef LINUX_2_4 + dev = dev_get_by_name(name); +#else + dev = dev_get(name); +#endif + if (dev == NULL){ + printk(KERN_INFO "wansock_annexg: Failed to get Dev from name: %s,\n", + name); + return -ENODEV; + } + + if (!(dev->flags&IFF_UP)){ + printk(KERN_INFO "wansock_annexg: Bind device %s is down!\n", + name); + dev_put(dev); + return -ENODEV; + } + + err = bind_api_listen_to_protocol(dev,sk->num,sk); + if (!err){ + sk->state = WANSOCK_BIND_LISTEN; + } + + +// printk(KERN_INFO "wansock_annexg: Bind device %s !\n", +// name); + + dev_put(dev); + }else{ + struct ifreq ifr; + strncpy(name,sll->sll_device,14); + name[14]=0; + +#ifdef LINUX_2_4 + dev = dev_get_by_name(name); +#else + dev = dev_get(name); +#endif + if (dev == NULL){ + printk(KERN_INFO "wansock_annexg: Failed to get Dev from name: %s,\n", + name); + return -ENODEV; + } + + if (!(dev->flags&IFF_UP)){ + printk(KERN_INFO "wansock_annexg: Bind device %s is down!\n", + name); + dev_put(dev); + return -ENODEV; + } + + ifr.ifr_data = (void*)sk; + err=-ENODEV; + + if (dev->do_ioctl) + err=dev->do_ioctl(dev,&ifr,SIOC_ANNEXG_BIND_SK); + + if (!err){ + sk->bound_dev_if = dev->ifindex; + sk->user_data = dev; + sk->state = WANSOCK_DISCONNECTED; + } + } + + if (!err){ + sk->zapped=1; + } + +// printk(KERN_INFO "11-11 Bind Socket Prot %i, X25=%i Zapped %i, Bind Dev %i Sock %u!\n", +// sk->num,htons(ETH_P_X25),sk->zapped,sk->bound_dev_if,(u32)sk); + + return err; +} + +/*============================================================ + * wanpipe_annexg_create + * + * SOCKET() System call. It allocates a sock structure + * and adds the socket to the wanpipe_sk_list. + * Crates AF_WANPIPE socket. + *===========================================================*/ + +int wanpipe_annexg_create(struct socket *sock, int protocol) +{ + struct sock *sk; + unsigned long flags; + + if (sock->type != SOCK_RAW) + return -ESOCKTNOSUPPORT; + + sock->state = SS_UNCONNECTED; + + if ((sk = wanpipe_annexg_alloc_socket()) == NULL){ + return -ENOMEM; + } + + sk->reuse = 1; + sock->ops = &wanpipe_ops; + sock_init_data(sock,sk); + + sk->zapped=0; + sk->family = AF_ANNEXG_WANPIPE; + sk->num = protocol; + sk->state = WANSOCK_UNCONFIGURED; + sk->ack_backlog = 0; + sk->bound_dev_if=0; + sk->user_data=NULL; + + atomic_inc(&wanpipe_socks_nr); + + /* We must disable interrupts because the ISR + * can also change the list */ + + write_lock_irqsave(&wanpipe_sklist_lock,flags); + sk->next = wanpipe_sklist; + wanpipe_sklist = sk; + sock_hold(sk); + write_unlock_irqrestore(&wanpipe_sklist_lock,flags); + + return(0); +} + + +/*============================================================ + * wanpipe_annexg_recvmsg + * + * Pull a packet from our receive queue and hand it + * to the user. If necessary we block. + *===========================================================*/ + +int wanpipe_annexg_recvmsg(struct socket *sock, struct msghdr *msg, int len, + int flags, struct scm_cookie *scm) +{ + struct sock *sk = sock->sk; + struct sk_buff *skb; + int copied, err=-ENOBUFS; + struct net_device *dev=NULL; + + /* + * If the address length field is there to be filled in, we fill + * it in now. + */ + + msg->msg_namelen = sizeof(struct wan_sockaddr_ll); + + /* + * Call the generic datagram receiver. This handles all sorts + * of horrible races and re-entrancy so we can forget about it + * in the protocol layers. + * + * Now it will return ENETDOWN, if device have just gone down, + * but then it will block. + */ + + if (flags & MSG_OOB){ + skb=skb_dequeue(&sk->error_queue); + }else{ + skb=skb_recv_datagram(sk,flags,1,&err); + } + /* + * An error occurred so return it. Because skb_recv_datagram() + * handles the blocking we don't see and worry about blocking + * retries. + */ + + if(skb==NULL) + goto out; + + + dev = (struct net_device *)sk->user_data; + if (dev){ + if (dev->do_ioctl){ + dev->do_ioctl(dev,NULL,SIOC_ANNEXG_KICK); + } + } + + /* + * You lose any data beyond the buffer you gave. If it worries a + * user program they can ask the device for its MTU anyway. + */ + + copied = skb->len; + if (copied > len) + { + copied=len; + msg->msg_flags|=MSG_TRUNC; + } + + /* We can't use skb_copy_datagram here */ + err = memcpy_toiovec(msg->msg_iov, skb->data, copied); + if (err) + goto out_free; + +#ifdef LINUX_2_1 + sk->stamp=skb->stamp; +#else + sock_recv_timestamp(msg, sk, skb); +#endif + + if (msg->msg_name) + memcpy(msg->msg_name, skb->cb, msg->msg_namelen); + + /* + * Free or return the buffer as appropriate. Again this + * hides all the races and re-entrancy issues from us. + */ + err = (flags&MSG_TRUNC) ? skb->len : copied; + +out_free: + AF_SKB_DEC(skb->truesize); + skb_free_datagram(sk, skb); +out: + return err; +} + +/*============================================================ + * wanpipe_annexg_getname + * + * I don't know what to do with this yet. + * User can use this function to get sock address + * information. Not very useful for Sangoma's purposes. + *===========================================================*/ + + +int wanpipe_annexg_getname(struct socket *sock, struct sockaddr *uaddr, + int *uaddr_len, int peer) +{ + netdevice_t *dev; + struct sock *sk = sock->sk; + struct wan_sockaddr_ll *sll = (struct wan_sockaddr_ll*)uaddr; + + sll->sll_family = AF_ANNEXG_WANPIPE; + sll->sll_ifindex = sk->bound_dev_if; + sll->sll_protocol = sk->num; + dev = (struct net_device *)sk->user_data; + if (dev) { + sll->sll_hatype = dev->type; + sll->sll_halen = dev->addr_len; + memcpy(sll->sll_addr, dev->dev_addr, dev->addr_len); + } else { + sll->sll_hatype = 0; /* Bad: we have no ARPHRD_UNSPEC */ + sll->sll_halen = 0; + } + *uaddr_len = sizeof(*sll); + + return 0; +} + +/*============================================================ + * wanpipe_notifier + * + * If driver turns off network interface, this function + * will be envoked. Currently I treate it as a + * call disconnect. More thought should go into this + * function. + * + * FIXME: More thought should go into this function. + * + *===========================================================*/ + +int wanpipe_annexg_notifier(struct notifier_block *this, unsigned long msg, void *data) +{ + struct sock *sk; + netdevice_t *dev = (netdevice_t*)data; + + if (dev==NULL) + return NOTIFY_DONE; + + for (sk = wanpipe_sklist; sk; sk = sk->next) { + + switch (msg) { + case NETDEV_DOWN: + case NETDEV_UNREGISTER: + if (dev->ifindex == sk->bound_dev_if) { + netdevice_t *dev = (struct net_device *)sk->user_data; + printk(KERN_INFO "wansock_annexg: Device down %s\n",dev->name); + + if (sk->state != WANSOCK_LISTEN && + sk->state != WANSOCK_BIND_LISTEN){ + sk->state = WANSOCK_DISCONNECTED; + } + sk->bound_dev_if = 0; + sk->zapped=0; + if (sk->user_data){ + dev_put((struct net_device *)sk->user_data); + } + sk->user_data=NULL; + } + break; + } + } + + return NOTIFY_DONE; +} + +/*====================================================================== + * wanpipe_annexg_poll + * + * Datagram poll: Again totally generic. This also handles + * sequenced packet sockets providing the socket receive queue + * is only ever holding data ready to receive. + * + * Note: when you _don't_ use this routine for this protocol, + * and you use a different write policy from sock_writeable() + * then please supply your own write_space callback. + *=====================================================================*/ + +int wanpipe_annexg_poll(struct file * file, struct socket *sock, poll_table *wait) +{ + struct sock *sk = sock->sk; + unsigned int mask; + struct net_device *dev=NULL; + + if (!sk) + return 0; + + poll_wait(file, sk->sleep, wait); + mask = 0; + + /* exceptional events? */ + if (sk->err || !skb_queue_empty(&sk->error_queue)){ + mask |= POLLPRI; + return mask; + } + if (sk->shutdown & RCV_SHUTDOWN) + mask |= POLLHUP; + + /* readable? */ + if (!skb_queue_empty(&sk->receive_queue)){ + mask |= POLLIN | POLLRDNORM; + } + + /* connection hasn't started yet */ + if (sk->state == WANSOCK_CONNECTING || sk->state == WANSOCK_LISTEN){ + return mask; + } + + if (sk->state != WANSOCK_CONNECTED){ + mask = POLLPRI; + return mask; + } + + if ((dev = (struct net_device *)sk->user_data) == NULL){ + printk(KERN_INFO "wansock_annexg: No Device found in POLL!\n"); + return mask; + } + + if (!(dev->flags & IFF_UP)) + return mask; + + if (!netif_queue_stopped(dev)){ + mask |= POLLOUT | POLLWRNORM | POLLWRBAND; + }else{ + #ifdef LINUX_2_4 + set_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags); + #else + sk->socket->flags |= SO_NOSPACE; + #endif + } + + return mask; +} + +static int wanpipe_annexg_api_connected(struct net_device *dev, struct sock *sk) +{ + if (sk == NULL || dev == NULL) + return -EINVAL; + + if (!sk->zapped) + return -EINVAL; + + sk->state = WANSOCK_CONNECTED; + sk->data_ready(sk,0); + return 0; +} + +static int wanpipe_annexg_api_disconnected(struct net_device *dev, struct sock *sk) +{ + if (sk == NULL || dev == NULL) + return -EINVAL; + + if (!sk->zapped) + return -EINVAL; + + sk->state = WANSOCK_DISCONNECTED; + + if (sk->user_data){ + dev_put((struct net_device *)sk->user_data); + } + sk->bound_dev_if=0; + sk->user_data=NULL; + sk->zapped=0; + sk->data_ready(sk,0); + return 0; +} + + +/*====================================================================== + * wanpipe_annexg_connect + * + * CONNECT() System Call. X25API specific function + * Check the state of the sock, and execute PLACE_CALL command. + * Connect can ether block or return without waiting for connection, + * if specified by user. + *=====================================================================*/ + +int wanpipe_annexg_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len, int flags) +{ + struct sock *sk = sock->sk; + struct wan_sockaddr_ll *addr = (struct wan_sockaddr_ll*)uaddr; + netdevice_t *dev; + + if (!sk->zapped){ /* Must bind first - autobinding does not work */ + return -EINVAL; + } + + if (sk->num != htons(ETH_P_X25) && sk->num != htons(DSP_PROT)){ + return -EINVAL; + } + + if (sk->state == WANSOCK_CONNECTED){ + return EISCONN; /* No reconnect on a seqpacket socket */ + } + + if (sk->state != WANSOCK_DISCONNECTED){ + printk(KERN_INFO "wansock_annexg: Trying to connect on channel NON DISCONNECT\n"); + return -ECONNREFUSED; + } + + sk->state = WANSOCK_DISCONNECTED; + sock->state = SS_UNCONNECTED; + + if (addr_len != sizeof(struct wan_sockaddr_ll)){ + return -EINVAL; + } + + if (addr->sll_family != AF_ANNEXG_WANPIPE){ + return -EINVAL; + } + + if ((dev = (struct net_device *)sk->user_data) == NULL){ + printk(KERN_INFO "Sock user data is null\n"); + return -ENETUNREACH; + } + + if (!dev->do_ioctl) + return -ENETUNREACH; + + sock->state = SS_CONNECTING; + sk->state = WANSOCK_CONNECTING; + + if (dev->do_ioctl(dev,NULL,SIOC_ANNEXG_PLACE_CALL)){ + sk->state = WANSOCK_DISCONNECTED; + sock->state = SS_UNCONNECTED; + return -ECONNREFUSED; + } + + return 0; +} + +static int sk_buf_check (struct sock *sk, int len) +{ + if (!sk->zapped) + return -EINVAL; + + if (atomic_read(&sk->rmem_alloc) + len >= (unsigned)sk->rcvbuf) + return -ENOMEM; + + return 0; +} + +static int sk_poll_wake (struct sock *sk) +{ + if (!sk->zapped) + return -EINVAL; + + sk->data_ready(sk,0); + return 0; +} + + +void unregister_annexg_api(void) +{ + printk(KERN_INFO "wansock_annexg: Unregistering Wanpipe Annexg API Socket \n"); + unregister_wanpipe_api_socket(); + return; +} + + +int register_annexg_api(void) +{ + struct wanpipe_api_register_struct wan_api_reg; + + printk(KERN_INFO "wansock_annexg: Registering Wanpipe Annexg API Socket \n"); + + wan_api_reg.wanpipe_api_sock_rcv = wanpipe_annexg_api_sock_rcv; + wan_api_reg.wanpipe_api_connected = wanpipe_annexg_api_connected; + wan_api_reg.wanpipe_api_disconnected = wanpipe_annexg_api_disconnected; + wan_api_reg.wanpipe_listen_rcv = wanpipe_annexg_listen_rcv; + wan_api_reg.sk_buf_check = sk_buf_check; + wan_api_reg.sk_poll_wake = sk_poll_wake; + + return register_wanpipe_api_socket(&wan_api_reg); +} + diff -Nur linux.org/net/wanrouter/af_wanpipe.c linux-2.6.17/net/wanrouter/af_wanpipe.c --- linux.org/net/wanrouter/af_wanpipe.c 2006-06-18 01:49:35.000000000 +0000 +++ linux-2.6.17/net/wanrouter/af_wanpipe.c 2006-08-30 10:07:16.000000000 +0000 @@ -1,9 +1,11 @@ /***************************************************************************** -* af_wanpipe.c WANPIPE(tm) Secure Socket Layer. +* af_wanpipe.c +* +* WANPIPE(tm) Annexg Secure Socket Layer. * * Author: Nenad Corbic * -* Copyright: (c) 2000 Sangoma Technologies Inc. +* Copyright: (c) 2003 Sangoma Technologies Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -19,7 +21,6 @@ * Alan Cox. * X25 socket Author: Jonathan Naylor. * ============================================================================ -* Mar 15, 2002 Arnaldo C. Melo o Use wp_sk()->num, as it isnt anymore in sock * Apr 25, 2000 Nenad Corbic o Added the ability to send zero length packets. * Mar 13, 2000 Nenad Corbic o Added a tx buffer check via ioctl call. * Mar 06, 2000 Nenad Corbic o Fixed the corrupt sock lcn problem. @@ -32,106 +33,68 @@ * ******************************************************************************/ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include + #include -#include -#include #include - -#ifdef CONFIG_INET -#include +#include +#include +#include + +#if defined(LINUX_2_1) + #define dev_put(a) + #define __sock_put(a) + #define sock_hold(a) + #define DECLARE_WAITQUEUE(a,b) \ + struct wait_queue a = { b, NULL } #endif -#define SLOW_BACKOFF 0.1*HZ -#define FAST_BACKOFF 0.01*HZ -//#define PRINT_DEBUG -#ifdef PRINT_DEBUG - #define DBG_PRINTK(format, a...) printk(format, ## a) -#else - #define DBG_PRINTK(format, a...) -#endif +#define AF_DEBUG_MEM +#ifdef AF_DEBUG_MEM + #define AF_SKB_DEC(x) atomic_sub(x,&af_skb_alloc) + #define AF_SKB_INC(x) atomic_add(x,&af_skb_alloc) -/* SECURE SOCKET IMPLEMENTATION - * - * TRANSMIT: - * - * When the user sends a packet via send() system call - * the wanpipe_sendmsg() function is executed. - * - * Each packet is enqueud into sk->sk_write_queue transmit - * queue. When the packet is enqueued, a delayed transmit - * timer is triggerd which acts as a Bottom Half hander. - * - * wanpipe_delay_transmit() function (BH), dequeues packets - * from the sk->sk_write_queue transmit queue and sends it - * to the deriver via dev->hard_start_xmit(skb, dev) function. - * Note, this function is actual a function pointer of if_send() - * routine in the wanpipe driver. - * - * X25API GUARANTEED DELIVERY: - * - * In order to provide 100% guaranteed packet delivery, - * an atomic 'packet_sent' counter is implemented. Counter - * is incremented for each packet enqueued - * into sk->sk_write_queue. Counter is decremented each - * time wanpipe_delayed_transmit() function successfuly - * passes the packet to the driver. Before each send(), a poll - * routine checks the sock resources The maximum value of - * packet sent counter is 1, thus if one packet is queued, the - * application will block until that packet is passed to the - * driver. - * - * RECEIVE: - * - * Wanpipe device drivers call the socket bottom half - * function, wanpipe_rcv() to queue the incoming packets - * into an AF_WANPIPE socket queue. Based on wanpipe_rcv() - * return code, the driver knows whether the packet was - * successfully queued. If the socket queue is full, - * protocol flow control is used by the driver, if any, - * to slow down the traffic until the sock queue is free. - * - * Every time a packet arrives into a socket queue the - * socket wakes up processes which are waiting to receive - * data. - * - * If the socket queue is full, the driver sets a block - * bit which signals the socket to kick the wanpipe driver - * bottom half hander when the socket queue is partialy - * empty. wanpipe_recvmsg() function performs this action. - * - * In case of x25api, packets will never be dropped, since - * flow control is available. - * - * In case of streaming protocols like CHDLC, packets will - * be dropped but the statistics will be generated. - */ + #define ALLOC_SKB(skb,len) { skb = dev_alloc_skb(len); \ + if (skb != NULL) AF_SKB_INC(skb->truesize); } + #define KFREE_SKB(skb) { AF_SKB_DEC(skb->truesize); dev_kfree_skb_any(skb); } + + + #define AF_MEM_DEC(x) atomic_sub(x,&af_mem_alloc) + #define AF_MEM_INC(x) atomic_add(x,&af_mem_alloc) + + #define KMALLOC(ptr,len,flag) { ptr=kmalloc(len, flag); \ + if (ptr != NULL) AF_MEM_INC(len); } + #define KFREE(ptr) {AF_MEM_DEC(sizeof(*ptr)); kfree(ptr);} + +#else + #define KMALLOC(ptr,len,flag) ptr=kmalloc(len, flag) + #define KFREE(ptr) kfree(ptr) + + #define ALLOC_SKB(new_skb,len, dsp) new_skb = dev_alloc_skb(len) + #define KFREE_SKB(skb) dev_kfree_skb_any(skb) + + #define AF_SKB_DEC(x) + #define AF_SKB_INC(x) + #define AF_MEM_DEC(x) + #define AF_MEM_INC(x) +#endif + +#define WP_API_HDR_SZ 16 +#ifdef CONFIG_PRODUCT_WANPIPE_SOCK_DATASCOPE +extern void wanpipe_unbind_sk_from_parent(struct sock *sk); +extern int wanpipe_bind_sk_to_parent(struct sock *sk, netdevice_t *dev, struct wan_sockaddr_ll *sll); +extern int wanpipe_sk_parent_rx(struct sock *parent_sk, struct sk_buff *skb); +#endif + + /* The code below is used to test memory leaks. It prints out * a message every time kmalloc and kfree system calls get executed. * If the calls match there is no leak :) @@ -154,151 +117,241 @@ #define kfree(x) dbg_kfree(x,__LINE__) ******************************************************************************/ - /* List of all wanpipe sockets. */ + +#ifdef LINUX_2_6 HLIST_HEAD(wanpipe_sklist); -static DEFINE_RWLOCK(wanpipe_sklist_lock); + +#ifdef AF_WANPIPE_2612_UPDATE +static struct proto packet_proto = { + .name = "AF_WANPIPE", + .owner = THIS_MODULE, + .obj_size = sizeof(struct sock), +}; +#endif + +#else +static struct sock * wanpipe_sklist = NULL; +#endif + +static rwlock_t wanpipe_sklist_lock = RW_LOCK_UNLOCKED; + +static atomic_t af_mem_alloc; +static atomic_t af_skb_alloc; atomic_t wanpipe_socks_nr; -static unsigned long wanpipe_tx_critical; +extern struct proto_ops wanpipe_ops; + +static struct sock *wanpipe_alloc_socket(void); +static void check_write_queue(struct sock *); + + +void wanpipe_kill_sock(struct sock *sock); #if 0 -/* Private wanpipe socket structures. */ -struct wanpipe_opt +void af_wan_sock_rfree(struct sk_buff *skb) { - void *mbox; /* Mail box */ - void *card; /* Card bouded to */ - struct net_device *dev; /* Bounded device */ - unsigned short lcn; /* Binded LCN */ - unsigned char svc; /* 0=pvc, 1=svc */ - unsigned char timer; /* flag for delayed transmit*/ - struct timer_list tx_timer; - unsigned poll_cnt; - unsigned char force; /* Used to force sock release */ - atomic_t packet_sent; -}; + struct sock *sk = skb->sk; + atomic_sub(skb->truesize, &sk->sk_rmem_alloc); + wan_skb_destructor(skb); +} + +void wan_skb_set_owner_r(struct sk_buff *skb, struct sock *sk) +{ + skb->sk = sk; + skb->destructor = af_wan_sock_rfree; + atomic_add(skb->truesize, &sk->sk_rmem_alloc); +} #endif -static int sk_count; -extern const struct proto_ops wanpipe_ops; -static unsigned long find_free_critical; - -static void wanpipe_unlink_driver(struct sock *sk); -static void wanpipe_link_driver(struct net_device *dev, struct sock *sk); -static void wanpipe_wakeup_driver(struct sock *sk); -static int execute_command(struct sock *, unsigned char, unsigned int); -static int check_dev(struct net_device *dev, sdla_t *card); -struct net_device *wanpipe_find_free_dev(sdla_t *card); -static void wanpipe_unlink_card (struct sock *); -static int wanpipe_link_card (struct sock *); -static struct sock *wanpipe_make_new(struct sock *); -static struct sock *wanpipe_alloc_socket(void); -static inline int get_atomic_device(struct net_device *dev); -static int wanpipe_exec_cmd(struct sock *, int, unsigned int); -static int get_ioctl_cmd (struct sock *, void *); -static int set_ioctl_cmd (struct sock *, void *); -static void release_device(struct net_device *dev); -static void wanpipe_kill_sock_timer (unsigned long data); -static void wanpipe_kill_sock_irq (struct sock *); -static void wanpipe_kill_sock_accept (struct sock *); -static int wanpipe_do_bind(struct sock *sk, struct net_device *dev, - int protocol); -struct sock * get_newsk_from_skb (struct sk_buff *); -static int wanpipe_debug (struct sock *, void *); -static void wanpipe_delayed_transmit (unsigned long data); -static void release_driver(struct sock *); -static void start_cleanup_timer (struct sock *); -static void check_write_queue(struct sock *); -static int check_driver_busy (struct sock *); +static inline void af_skb_queue_purge(struct sk_buff_head *list) +{ + struct sk_buff *skb; + while ((skb=skb_dequeue(list))!=NULL){ + KFREE_SKB(skb); + } +} + /*============================================================ - * wanpipe_rcv + * wanpipe_ioctl + * + * Execute a user commands, and set socket options. * - * Wanpipe socket bottom half handler. This function - * is called by the WANPIPE device drivers to queue a - * incoming packet into the socket receive queue. - * Once the packet is queued, all processes waiting to - * read are woken up. + * FIXME: More thought should go into this function. * - * During socket bind, this function is bounded into - * WANPIPE driver private. *===========================================================*/ -static int wanpipe_rcv(struct sk_buff *skb, struct net_device *dev, - struct sock *sk) +static int wanpipe_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) { - struct wan_sockaddr_ll *sll = (struct wan_sockaddr_ll*)skb->cb; - wanpipe_common_t *chan = dev->priv; - /* - * When we registered the protocol we saved the socket in the data - * field for just this event. - */ + struct sock *sk = sock->sk; - skb->dev = dev; + WAN_ASSERT_EINVAL(!SK_PRIV(sk)); - sll->sll_family = AF_WANPIPE; - sll->sll_hatype = dev->type; - sll->sll_protocol = skb->protocol; - sll->sll_pkttype = skb->pkt_type; - sll->sll_ifindex = dev->ifindex; - sll->sll_halen = 0; + switch(cmd) + { + case SIOC_WANPIPE_CHECK_TX: + if (atomic_read(&sk->sk_wmem_alloc)) + return 1; - if (dev->hard_header_parse) - sll->sll_halen = dev->hard_header_parse(skb, sll->sll_addr); + goto dev_private_ioctl; - /* - * WAN_PACKET_DATA : Data which should be passed up the receive queue. - * WAN_PACKET_ASYC : Asynchronous data like place call, which should - * be passed up the listening sock. - * WAN_PACKET_ERR : Asynchronous data like clear call or restart - * which should go into an error queue. - */ - switch (skb->pkt_type){ + case SIOC_WANPIPE_SOCK_STATE: - case WAN_PACKET_DATA: - if (sock_queue_rcv_skb(sk,skb)<0){ - return -ENOMEM; + if (sk->sk_state == WANSOCK_CONNECTED){ + return 0; + }else if (sk->sk_state == WANSOCK_DISCONNECTED){ + return 1; + }else{ + return 2; } - break; - case WAN_PACKET_CMD: - sk->sk_state = chan->state; - /* Bug fix: update Mar6. - * Do not set the sock lcn number here, since - * cmd is not guaranteed to be executed on the - * board, thus Lcn could be wrong */ - sk->sk_data_ready(sk, skb->len); - kfree_skb(skb); - break; - case WAN_PACKET_ERR: - sk->sk_state = chan->state; - if (sock_queue_err_skb(sk,skb)<0){ - return -ENOMEM; + + case SIOC_WANPIPE_SOCK_FLUSH_BUFS: + { + netskb_t *skb; + int err; + while ((skb=skb_dequeue(&sk->sk_error_queue)) != NULL){ + AF_SKB_DEC(skb->truesize); + skb_free_datagram(sk, skb); + } + while ((skb=skb_recv_datagram(sk,0,1,&err)) != NULL){ + AF_SKB_DEC(skb->truesize); + skb_free_datagram(sk, skb); + } } - break; + return 0; + + case SIOC_WANPIPE_SET_NONBLOCK: + + if (sk->sk_state != WANSOCK_DISCONNECTED) + return -EINVAL; + + sock->file->f_flags |= O_NONBLOCK; + return 0; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15) + case SIOCGIFFLAGS: +#ifndef CONFIG_INET + case SIOCSIFFLAGS: +#endif + case SIOCGIFCONF: + case SIOCGIFMETRIC: + case SIOCSIFMETRIC: + case SIOCGIFMEM: + case SIOCSIFMEM: + case SIOCGIFMTU: + case SIOCSIFMTU: + case SIOCSIFLINK: + case SIOCGIFHWADDR: + case SIOCSIFHWADDR: + case SIOCSIFMAP: + case SIOCGIFMAP: + case SIOCSIFSLAVE: + case SIOCGIFSLAVE: + case SIOCGIFINDEX: + case SIOCGIFNAME: + case SIOCGIFCOUNT: + case SIOCSIFHWBROADCAST: + return(dev_ioctl(cmd,(void *) arg)); +#endif + +#ifdef CONFIG_INET + case SIOCADDRT: + case SIOCDELRT: + case SIOCDARP: + case SIOCGARP: + case SIOCSARP: + case SIOCDRARP: + case SIOCGRARP: + case SIOCSRARP: + case SIOCGIFADDR: + case SIOCSIFADDR: + case SIOCGIFBRDADDR: + case SIOCSIFBRDADDR: + case SIOCGIFNETMASK: + case SIOCSIFNETMASK: + case SIOCGIFDSTADDR: + case SIOCSIFDSTADDR: + case SIOCSIFFLAGS: + case SIOCADDDLCI: + case SIOCDELDLCI: + return inet_dgram_ops.ioctl(sock, cmd, arg); +#endif + default: - printk(KERN_INFO "wansock: BH Illegal Packet Type Dropping\n"); - kfree_skb(skb); - break; + if ((cmd >= SIOCDEVPRIVATE) && + (cmd <= (SIOCDEVPRIVATE + 50))){ + netdevice_t *dev; + struct ifreq ifr; +dev_private_ioctl: + + dev = (struct net_device *)SK_PRIV(sk)->dev; + if (!dev) + return -ENODEV; + + if (!dev->do_ioctl) + return -ENODEV; + + ifr.ifr_data = (void*)arg; + + return dev->do_ioctl(dev,&ifr,cmd); + } + + DEBUG_EVENT("%s: Ioctl call not supported DevPriv %i Cmd %i \n", + __FUNCTION__,SIOCDEVPRIVATE,cmd); + return -EOPNOTSUPP; + } + /*NOTREACHED*/ +} -//?????????????????????? -// if (sk->sk_state == WANSOCK_DISCONNECTED){ -// if (sk->sk_zapped) { -// //printk(KERN_INFO "wansock: Disconnected, killing early\n"); -// wanpipe_unlink_driver(sk); -// sk->sk_bound_dev_if = 0; -// } -// } - return 0; + +/*============================================================ + * wanpipe_make_new + * + * Create a new sock, and allocate a wanpipe private + * structure to it. Also, copy the important data + * from the original sock to the new sock. + * + * This function is used by wanpipe_listen_rcv() listen + * bottom half handler. A copy of the listening sock + * is created using this function. + * + *===========================================================*/ + +struct sock *wanpipe_make_new(struct sock *osk) +{ + struct sock *sk; + + if (osk->sk_type != SOCK_RAW) + return NULL; + + if ((sk = wanpipe_alloc_socket()) == NULL) + return NULL; + + sk->sk_family = osk->sk_family; + sk->sk_type = osk->sk_type; + sk->sk_socket = osk->sk_socket; + sk->sk_priority = osk->sk_priority; + SK_PRIV(sk)->num = SK_PRIV(osk)->num; + sk->sk_rcvbuf = osk->sk_rcvbuf; + sk->sk_sndbuf = osk->sk_sndbuf; + sk->sk_debug = osk->sk_debug; + sk->sk_state = WANSOCK_CONNECTING; + sk->sk_sleep = osk->sk_sleep; + + return sk; } + + /*============================================================ * wanpipe_listen_rcv * * Wanpipe LISTEN socket bottom half handler. This function * is called by the WANPIPE device drivers to queue an - * incoming call into the socket listening queue. + * incomming call into the socket listening queue. * Once the packet is queued, the waiting accept() process * is woken up. * @@ -320,184 +373,418 @@ static int wanpipe_listen_rcv (struct sk_buff *skb, struct sock *sk) { - wanpipe_opt *wp = wp_sk(sk), *newwp; - struct wan_sockaddr_ll *sll = (struct wan_sockaddr_ll*)skb->cb; + + struct wan_sockaddr_ll *sll; struct sock *newsk; - struct net_device *dev; - sdla_t *card; - mbox_cmd_t *mbox_ptr; - wanpipe_common_t *chan; + netdevice_t *dev; + //x25api_hdr_t *x25_api_hdr; + struct ifreq ifr; + unsigned long flags; - /* Find a free device, if none found, all svc's are busy - */ + if (!sk){ + printk(KERN_INFO "Wanpipe listen recv error! No skid!\n"); + return 0; + } + + /* If we receive a NULL skb pointer, it means that the + * lower layer is dead. Change state and wakeup any waiting + * processes. */ + if (!skb){ + sk->sk_state = WANSOCK_BIND_LISTEN; + sk->sk_data_ready(sk,0); + return 0; + } - card = (sdla_t*)wp->card; - if (!card){ - printk(KERN_INFO "wansock: LISTEN ERROR, No Card\n"); - return -ENODEV; + if (sk->sk_state != WANSOCK_LISTEN){ + printk(KERN_INFO "af_wanpipe: Listen rcv in disconnected state!\n"); + sk->sk_data_ready(sk,0); + return -EINVAL; } + + /* Check if the receive buffer will hold the incoming + * call request */ + if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >= + (unsigned)sk->sk_rcvbuf){ + + return -ENOMEM; + } + + + sll = (struct wan_sockaddr_ll*)skb->cb; - dev = wanpipe_find_free_dev(card); + dev = skb->dev; if (!dev){ - printk(KERN_INFO "wansock: LISTEN ERROR, No Free Device\n"); + printk(KERN_INFO "af_wanpipe: LISTEN ERROR, No Free Device\n"); return -ENODEV; } - chan=dev->priv; - chan->state = WANSOCK_CONNECTING; - /* Allocate a new sock, which accept will bind * and pass up to the user */ if ((newsk = wanpipe_make_new(sk)) == NULL){ - release_device(dev); return -ENOMEM; } + /* Bind the new socket into the lower layer. The lower + * layer will increment the sock reference count. */ + ifr.ifr_data = (void*)newsk; + if (!dev->do_ioctl || dev->do_ioctl(dev,&ifr,SIOC_ANNEXG_BIND_SK) != 0){ + wanpipe_kill_sock(newsk); + return -ENODEV; + } - /* Initialize the new sock structure - */ + wansk_set_zapped(newsk); newsk->sk_bound_dev_if = dev->ifindex; - newwp = wp_sk(newsk); - newwp->card = wp->card; + dev_hold(dev); + SK_PRIV(newsk)->dev = dev; + + write_lock_irqsave(&wanpipe_sklist_lock,flags); +#ifdef LINUX_2_6 + sk_add_node(newsk, &wanpipe_sklist); +#else + newsk->next = wanpipe_sklist; + wanpipe_sklist = newsk; + sock_hold(newsk); +#endif + write_unlock_irqrestore(&wanpipe_sklist_lock,flags); /* Insert the sock into the main wanpipe * sock list. */ atomic_inc(&wanpipe_socks_nr); - /* Allocate and fill in the new Mail Box. Then - * bind the mail box to the sock. It will be - * used by the ioctl call to read call information - * and to execute commands. - */ - if ((mbox_ptr = kmalloc(sizeof(mbox_cmd_t), GFP_ATOMIC)) == NULL) { - wanpipe_kill_sock_irq (newsk); - release_device(dev); - return -ENOMEM; - } - memset(mbox_ptr, 0, sizeof(mbox_cmd_t)); - memcpy(mbox_ptr,skb->data,skb->len); - /* Register the lcn on which incoming call came * from. Thus, if we have to clear it, we know - * which lcn to clear + * whic lcn to clear */ - newwp->lcn = mbox_ptr->cmd.lcn; - newwp->mbox = (void *)mbox_ptr; - - DBG_PRINTK(KERN_INFO "NEWSOCK : Device %s, bind to lcn %i\n", - dev->name,mbox_ptr->cmd.lcn); - - chan->lcn = mbox_ptr->cmd.lcn; - card->u.x.svc_to_dev_map[(chan->lcn%MAX_X25_LCN)] = dev; - - sock_reset_flag(newsk, SOCK_ZAPPED); - newwp->num = htons(X25_PROT); - - if (wanpipe_do_bind(newsk, dev, newwp->num)) { - wanpipe_kill_sock_irq (newsk); - release_device(dev); - return -EINVAL; - } + //FIXME Obtain the LCN from the SKB buffer + //x25_api_hdr = (x25api_hdr_t*)skb->data; + + SK_PRIV(newsk)->num = skb->protocol; newsk->sk_state = WANSOCK_CONNECTING; - /* Fill in the standard sock address info */ - sll->sll_family = AF_WANPIPE; + sll->sll_family = sk->sk_family; sll->sll_hatype = dev->type; - sll->sll_protocol = skb->protocol; + sll->sll_protocol = SK_PRIV(newsk)->num; sll->sll_pkttype = skb->pkt_type; sll->sll_ifindex = dev->ifindex; sll->sll_halen = 0; - skb->dev = dev; sk->sk_ack_backlog++; + /* We also store the new sock pointer in side the + * skb buffer, just incase the lower layer disapears, + * or gets unconfigured */ + sock_hold(newsk); + *(unsigned long *)&skb->data[0]=(unsigned long)newsk; + + dev_put(skb->dev); + skb->dev=NULL; + + AF_SKB_INC(skb->truesize); + /* We must do this manually, since the sock_queue_rcv_skb() * function sets the skb->dev to NULL. However, we use * the dev field in the accept function.*/ - if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >= - (unsigned)sk->sk_rcvbuf) { - - wanpipe_unlink_driver(newsk); - wanpipe_kill_sock_irq (newsk); - --sk->sk_ack_backlog; - return -ENOMEM; - } skb_set_owner_r(skb, sk); + sk->sk_data_ready(sk,skb->len); skb_queue_tail(&sk->sk_receive_queue, skb); - sk->sk_data_ready(sk, skb->len); return 0; } - -/*============================================================ - * wanpipe_make_new - * - * Create a new sock, and allocate a wanpipe private - * structure to it. Also, copy the important data - * from the original sock to the new sock. - * - * This function is used by wanpipe_listen_rcv() listen - * bottom half handler. A copy of the listening sock - * is created using this function. +/*====================================================================== + * wanpipe_listen * - *===========================================================*/ + * X25API Specific function. Set a socket into LISTENING MODE. + *=====================================================================*/ + -static struct sock *wanpipe_make_new(struct sock *osk) +static int wanpipe_listen(struct socket *sock, int backlog) { - struct sock *sk; + struct sock *sk = sock->sk; - if (osk->sk_type != SOCK_RAW) - return NULL; + /* This is x25 specific area if protocol doesn't + * match, return error */ + if (SK_PRIV(sk)->num != htons(ETH_P_X25) && + SK_PRIV(sk)->num != htons(WP_X25_PROT) && + SK_PRIV(sk)->num != htons(DSP_PROT)) + return -EINVAL; - if ((sk = wanpipe_alloc_socket()) == NULL) - return NULL; + if (sk->sk_state == WANSOCK_BIND_LISTEN) { + sk->sk_max_ack_backlog = backlog; + sk->sk_state = WANSOCK_LISTEN; + return 0; + }else{ + printk(KERN_INFO "af_wanpipe: Listening sock was not binded\n"); + } - sk->sk_type = osk->sk_type; - sk->sk_socket = osk->sk_socket; - sk->sk_priority = osk->sk_priority; - sk->sk_protocol = osk->sk_protocol; - wp_sk(sk)->num = wp_sk(osk)->num; - sk->sk_rcvbuf = osk->sk_rcvbuf; - sk->sk_sndbuf = osk->sk_sndbuf; - sk->sk_state = WANSOCK_CONNECTING; - sk->sk_sleep = osk->sk_sleep; + return -EINVAL; +} - if (sock_flag(osk, SOCK_DBG)) - sock_set_flag(sk, SOCK_DBG); - return sk; -} -/* - * FIXME: wanpipe_opt has to include a sock in its definition and stop using - * sk_protinfo, but this code is not even compilable now, so lets leave it for - * later. - */ -static struct proto wanpipe_proto = { - .name = "WANPIPE", - .owner = THIS_MODULE, - .obj_size = sizeof(struct sock), -}; -/*============================================================ - * wanpipe_make_new +/*====================================================================== + * wanpipe_accept + * + * ACCEPT() System call. X25API Specific function. + * For each incoming call, create a new socket and + * return it to the user. + *=====================================================================*/ + +static int wanpipe_accept(struct socket *sock, struct socket *newsock, int flags) +{ + struct sock *sk; + struct sock *newsk=NULL, *newsk_frmskb=NULL; + struct sk_buff *skb; + DECLARE_WAITQUEUE(wait, current); + int err=-EINVAL; + struct ifreq ifr; + + if (newsock->sk != NULL){ + printk(KERN_INFO "af_wanpipe: Accept is Releaseing an unused sock !\n"); + wanpipe_kill_sock(newsock->sk); + newsock->sk=NULL; + } + + if ((sk = sock->sk) == NULL) + return -ENOTSOCK; + + if (sk->sk_type != SOCK_RAW) + return -EOPNOTSUPP; + + if (sk->sk_state != WANSOCK_LISTEN) + return -ENETDOWN; + + if (SK_PRIV(sk)->num != htons(ETH_P_X25) && SK_PRIV(sk)->num != htons(WP_X25_PROT) && SK_PRIV(sk)->num != htons(DSP_PROT)) + return -EPROTOTYPE; + + add_wait_queue(sk->sk_sleep,&wait); + current->state = TASK_INTERRUPTIBLE; + for (;;){ + skb = skb_dequeue(&sk->sk_receive_queue); + if (skb){ + err=0; + break; + } + + if (sk->sk_state != WANSOCK_LISTEN){ + err = -ENETDOWN; + break; + } + + if (signal_pending(current)) { + err = -ERESTARTSYS; + break; + } + schedule(); + } + current->state = TASK_RUNNING; + remove_wait_queue(sk->sk_sleep,&wait); + + if (err != 0) + return err; + + ifr.ifr_data=NULL; + + newsk=(struct sock*)*(unsigned long *)&skb->data[0]; + if (newsk){ + + struct net_device *dev; + + /* Decrement the usage count of newsk, since + * we go the pointer for skb */ + __sock_put(newsk); + + if (wansk_is_zapped(newsk) && SK_PRIV(newsk) && + (dev = (struct net_device *)SK_PRIV(newsk)->dev)){ + + if (dev && dev->do_ioctl){ + struct sock* dev_sk; + dev->do_ioctl(dev,&ifr,SIOC_ANNEXG_GET_SK); + + if ((dev_sk=(struct sock*)ifr.ifr_data)!=NULL){ + __sock_put(dev_sk); + + if (dev_sk == newsk){ + /* Got the right device with correct + * sk_id */ + goto accept_newsk_ok; + }else{ + /* This should never happen */ + printk(KERN_INFO "af_wanpipe: Accept killing newsk, layer ptr mismatch!\n"); + } + }else{ + printk(KERN_INFO "af_wanpipe: Accept killing newsk, get sk failed!\n"); + } + + ifr.ifr_data=(void*)newsk; + if (dev->do_ioctl(dev,&ifr,SIOC_ANNEXG_UNBIND_SK)==0){ + dev->do_ioctl(dev,NULL,SIOC_ANNEXG_CLEAR_CALL); + } + }else{ + printk(KERN_INFO "af_wanpipe: Accept killing newsk, lower layer down!\n"); + } + }else{ + /* This can happen if the device goes down, before we get + * the chance to accept the call */ + printk(KERN_INFO "af_wanpipe: Accept killing newsk, newsk not zapped!\n"); + } + +#ifdef LINUX_2_6 + sock_set_flag(newsk, SOCK_DEAD); +#else + newsk->dead=1; +#endif + + wanpipe_kill_sock(newsk); + + KFREE_SKB(skb); + return -EINVAL; + }else{ + KFREE_SKB(skb); + return -ENODEV; + } + +accept_newsk_ok: + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9) + newsk->sk_pair = NULL; +#endif + newsk->sk_socket = newsock; + newsk->sk_sleep = &newsock->wait; + + /* Now attach up the new socket */ + sk->sk_ack_backlog--; + newsock->sk = newsk; + + if (newsk_frmskb){ + __sock_put(newsk_frmskb); + newsk_frmskb=NULL; + } + KFREE_SKB(skb); + return 0; +} + + + + +/*============================================================ + * wanpipe_api_sock_rcv + * + * Wanpipe socket bottom half handler. This function + * is called by the WANPIPE device drivers to queue a + * incomming packet into the socket receive queue. + * Once the packet is queued, all processes waiting to + * read are woken up. + * + * During socket bind, this function is bounded into + * WANPIPE driver private. + *===========================================================*/ + +static int wanpipe_api_sock_rcv(struct sk_buff *skb, netdevice_t *dev, struct sock *sk) +{ + struct wan_sockaddr_ll *sll; + /* + * When we registered the protocol we saved the socket in the data + * field for just this event. + */ + + if (!skb){ + return -ENODEV; + } + + if (!wansk_is_zapped(sk)){ + return -EINVAL; + } + + sll = (struct wan_sockaddr_ll*)skb->cb; + + sll->sll_family = sk->sk_family; + sll->sll_hatype = dev->type; + sll->sll_protocol = skb->protocol; + sll->sll_pkttype = skb->pkt_type; + sll->sll_ifindex = dev->ifindex; + sll->sll_halen = 0; + + if (dev->hard_header_parse) + sll->sll_halen = dev->hard_header_parse(skb, sll->sll_addr); + + /* + * WAN_PACKET_DATA : Data which should be passed up the receive queue. + * WAN_PACKET_ASYC : Asynchronous data like place call, which should + * be passed up the listening sock. + * WAN_PACKET_ERR : Asynchronous data like clear call or restart + * which should go into an error queue. + */ + + AF_SKB_INC(skb->truesize); + switch (skb->pkt_type){ + + case WAN_PACKET_DATA: + +#ifdef CONFIG_PRODUCT_WANPIPE_SOCK_DATASCOPE + if (SK_PRIV(sk) && DATA_SC(sk) && DATA_SC(sk)->parent){ +#ifdef LINUX_2_6 + if (sock_flag(sk, SOCK_DEAD)){ +#else + if (test_bit(0,&sk->dead)){ +#endif + return -ENODEV; + } + return wanpipe_sk_parent_rx(sk,skb); + }else{ + if (sock_queue_rcv_skb(sk,skb)<0){ + AF_SKB_DEC(skb->truesize); + sk->sk_data_ready(sk,0); + return -ENOMEM; + } + } +#else + if (sock_queue_rcv_skb(sk,skb)<0){ + AF_SKB_DEC(skb->truesize); + sk->sk_data_ready(sk,0); + return -ENOMEM; + } +#endif + break; + case WAN_PACKET_CMD: + /* Bug fix: update Mar6. + * Do not set the sock lcn number here, since + * cmd is not guaranteed to be executed on the + * board, thus Lcn could be wrong */ + sk->sk_data_ready(sk,skb->len); + KFREE_SKB(skb); + break; + case WAN_PACKET_ERR: + if (sock_queue_err_skb(sk,skb)<0){ + AF_SKB_DEC(skb->truesize); + return -ENOMEM; + } + break; + default: + printk(KERN_INFO "af_wanpipe: BH Illegal Packet Type Dropping\n"); + KFREE_SKB(skb); + break; + } + + return 0; +} + +/*============================================================ + * wanpipe_alloc_socket * * Allocate memory for the a new sock, and sock * private data. * * Increment the module use count. * - * This function is used by wanpipe_create() and - * wanpipe_make_new() functions. - * *===========================================================*/ static struct sock *wanpipe_alloc_socket(void) @@ -505,22 +792,33 @@ struct sock *sk; struct wanpipe_opt *wan_opt; - if ((sk = sk_alloc(PF_WANPIPE, GFP_ATOMIC, &wanpipe_proto, 1)) == NULL) +#ifdef LINUX_2_6 +#ifdef AF_WANPIPE_2612_UPDATE + if ((sk = sk_alloc(PF_WANPIPE, GFP_ATOMIC, &packet_proto,1)) == NULL) + +#else + if ((sk = sk_alloc(PF_WANPIPE, GFP_ATOMIC, 1,NULL)) == NULL) +#endif +#else + if ((sk = sk_alloc(PF_WANPIPE, GFP_ATOMIC, 1)) == NULL) +#endif return NULL; if ((wan_opt = kmalloc(sizeof(struct wanpipe_opt), GFP_ATOMIC)) == NULL) { sk_free(sk); return NULL; } + memset(wan_opt, 0x00, sizeof(struct wanpipe_opt)); - wp_sk(sk) = wan_opt; + SK_PRIV_INIT(sk,wan_opt); + + AF_MEM_INC(sizeof(struct sock)); + AF_MEM_INC(sizeof(struct wanpipe_opt)); - /* Use timer to send data to the driver. This will act - * as a BH handler for sendmsg functions */ - init_timer(&wan_opt->tx_timer); - wan_opt->tx_timer.data = (unsigned long)sk; - wan_opt->tx_timer.function = wanpipe_delayed_transmit; +#ifndef LINUX_2_6 + MOD_INC_USE_COUNT; +#endif sock_init_data(NULL, sk); return sk; @@ -537,46 +835,56 @@ * to find a network device to which the packet should * be passed to. * - * Each packet is queued into sk->sk_write_queue and + * Each packet is queued into sk->write_queue and * delayed transmit bottom half handler is marked for * execution. * * A socket must be in WANSOCK_CONNECTED state before - * a packet is queued into sk->sk_write_queue. + * a packet is queued into sk->write_queue. *===========================================================*/ +#ifdef LINUX_2_6 static int wanpipe_sendmsg(struct kiocb *iocb, struct socket *sock, - struct msghdr *msg, int len) + struct msghdr *msg, size_t len) + +#else +static int wanpipe_sendmsg(struct socket *sock, struct msghdr *msg, int len, + struct scm_cookie *scm) +#endif { - wanpipe_opt *wp; struct sock *sk = sock->sk; struct wan_sockaddr_ll *saddr=(struct wan_sockaddr_ll *)msg->msg_name; struct sk_buff *skb; - struct net_device *dev; + netdevice_t *dev; unsigned short proto; unsigned char *addr; - int ifindex, err, reserve = 0; + int ifindex, err=-EINVAL, reserve = 0; + WAN_ASSERT_EINVAL(!SK_PRIV(sk)); - if (!sock_flag(sk, SOCK_ZAPPED)) + if (!wansk_is_zapped(sk)) return -ENETDOWN; if (sk->sk_state != WANSOCK_CONNECTED) return -ENOTCONN; - if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_CMSG_COMPAT)) + if (msg->msg_flags&~MSG_DONTWAIT) return(-EINVAL); - /* it was <=, now one can send - * zero length packets */ - if (len < sizeof(x25api_hdr_t)) + if ((SK_PRIV(sk)->num == htons(ETH_P_X25) || + SK_PRIV(sk)->num == htons(WP_X25_PROT)) && (len < sizeof(x25api_hdr_t))) + return -EINVAL; + + if (SK_PRIV(sk)->num == htons(DSP_PROT) && (len < sizeof(dspapi_hdr_t))) return -EINVAL; - wp = wp_sk(sk); + if (len < WP_API_HDR_SZ){ + return -EINVAL; + } if (saddr == NULL) { ifindex = sk->sk_bound_dev_if; - proto = wp->num; + proto = SK_PRIV(sk)->num; addr = NULL; }else{ @@ -589,12 +897,14 @@ addr = saddr->sll_addr; } - dev = dev_get_by_index(ifindex); + dev = (struct net_device *)SK_PRIV(sk)->dev; if (dev == NULL){ - printk(KERN_INFO "wansock: Send failed, dev index: %i\n",ifindex); + printk(KERN_INFO "af_wanpipe: Send failed, dev index: %i\n",ifindex); return -ENXIO; } - dev_put(dev); + + if (netif_queue_stopped(dev)) + return -EBUSY; if (sock->type == SOCK_RAW) reserve = dev->hard_header_len; @@ -603,14 +913,16 @@ return -EMSGSIZE; } - skb = sock_alloc_send_skb(sk, len + LL_RESERVED_SPACE(dev), - msg->msg_flags & MSG_DONTWAIT, &err); - +#if defined(LINUX_2_1) + dev_lock_list(); +#endif + + ALLOC_SKB(skb,len+dev->hard_header_len+15); if (skb==NULL){ goto out_unlock; } - skb_reserve(skb, LL_RESERVED_SPACE(dev)); + skb_reserve(skb, (dev->hard_header_len+15)&~15); skb->nh.raw = skb->data; /* Returns -EFAULT on error */ @@ -629,7 +941,6 @@ } skb->protocol = proto; - skb->dev = dev; skb->priority = sk->sk_priority; skb->pkt_type = WAN_PACKET_DATA; @@ -637,313 +948,137 @@ if (!(dev->flags & IFF_UP)) goto out_free; - if (atomic_read(&sk->sk_wmem_alloc) + skb->truesize > - (unsigned int)sk->sk_sndbuf){ - kfree_skb(skb); - return -ENOBUFS; - } - - skb_queue_tail(&sk->sk_write_queue,skb); - atomic_inc(&wp->packet_sent); +#if defined(LINUX_2_1) + dev_unlock_list(); +#endif - if (!(test_and_set_bit(0, &wp->timer))) - mod_timer(&wp->tx_timer, jiffies + 1); + AF_SKB_DEC(skb->truesize); + if (!dev->hard_start_xmit(skb,dev)){ + return(len); + }else{ + err = -EBUSY; + } + AF_SKB_INC(skb->truesize); - return(len); - out_free: - kfree_skb(skb); + KFREE_SKB(skb); out_unlock: +#if defined(LINUX_2_1) + dev_unlock_list(); +#endif return err; } /*============================================================ - * wanpipe_delayed_tarnsmit - * - * Transmit bottom half handler. It dequeues packets - * from sk->sk_write_queue and passes them to the - * driver. If the driver is busy, the packet is - * re-enqueued. + * wanpipe_kill_sock * - * Packet Sent counter is decremented on successful - * transmission. + * Used by wanpipe_release, to delay release of + * the socket. *===========================================================*/ - - -static void wanpipe_delayed_transmit (unsigned long data) +void wanpipe_kill_sock (struct sock *sk) { - struct sock *sk=(struct sock *)data; - struct sk_buff *skb; - wanpipe_opt *wp = wp_sk(sk); - struct net_device *dev = wp->dev; - sdla_t *card = (sdla_t*)wp->card; - - if (!card || !dev){ - clear_bit(0, &wp->timer); - DBG_PRINTK(KERN_INFO "wansock: Transmit delay, no dev or card\n"); - return; - } +#ifndef LINUX_2_6 + struct sock **skp; +#endif + unsigned long flags; - if (sk->sk_state != WANSOCK_CONNECTED || !sock_flag(sk, SOCK_ZAPPED)) { - clear_bit(0, &wp->timer); - DBG_PRINTK(KERN_INFO "wansock: Tx Timer, State not CONNECTED\n"); + if (!sk) return; - } + + WAN_ASSERT_VOID(!SK_PRIV(sk)); - /* If driver is executing command, we must offload - * the board by not sending data. Otherwise a - * pending command will never get a free buffer - * to execute */ - if (atomic_read(&card->u.x.command_busy)){ - wp->tx_timer.expires = jiffies + SLOW_BACKOFF; - add_timer(&wp->tx_timer); - DBG_PRINTK(KERN_INFO "wansock: Tx Timer, command bys BACKOFF\n"); - return; + sk->sk_state = WANSOCK_DISCONNECTED; + wansk_reset_zapped(sk); + sk->sk_bound_dev_if=0; + if (SK_PRIV(sk)->dev){ + dev_put(SK_PRIV(sk)->dev); } - + SK_PRIV(sk)->dev=NULL; - if (test_and_set_bit(0,&wanpipe_tx_critical)){ - printk(KERN_INFO "WanSock: Tx timer critical %s\n",dev->name); - wp->tx_timer.expires = jiffies + SLOW_BACKOFF; - add_timer(&wp->tx_timer); - return; - } + /* This functin can be called from interrupt. We must use + * appropriate locks */ - /* Check for a packet in the fifo and send */ - if ((skb = skb_dequeue(&sk->sk_write_queue)) != NULL){ - - if (dev->hard_start_xmit(skb, dev) != 0){ - - /* Driver failed to transmit, re-enqueue - * the packet and retry again later */ - skb_queue_head(&sk->sk_write_queue,skb); - clear_bit(0,&wanpipe_tx_critical); - return; - }else{ - - /* Packet Sent successful. Check for more packets - * if more packets, re-trigger the transmit routine - * other wise exit - */ - atomic_dec(&wp->packet_sent); - - if (skb_peek(&sk->sk_write_queue) == NULL) { - /* If there is nothing to send, kick - * the poll routine, which will trigger - * the application to send more data */ - sk->sk_data_ready(sk, 0); - clear_bit(0, &wp->timer); - }else{ - /* Reschedule as fast as possible */ - wp->tx_timer.expires = jiffies + 1; - add_timer(&wp->tx_timer); - } + write_lock_irqsave(&wanpipe_sklist_lock,flags); +#ifdef LINUX_2_6 + sk_del_node_init(sk); +#else + for (skp = &wanpipe_sklist; *skp; skp = &(*skp)->next) { + if (*skp == sk) { + *skp = sk->next; + __sock_put(sk); + break; } } - clear_bit(0,&wanpipe_tx_critical); -} +#endif + write_unlock_irqrestore(&wanpipe_sklist_lock,flags); -/*============================================================ - * execute_command - * - * Execute x25api commands. The atomic variable - * chan->command is used to indicate to the driver that - * command is pending for execution. The acutal command - * structure is placed into a sock mbox structure - * (wp_sk(sk)->mbox). - * - * The sock private structure, mbox is - * used as shared memory between sock and the driver. - * Driver uses the sock mbox to execute the command - * and return the result. - * - * For all command except PLACE CALL, the function - * waits for the result. PLACE CALL can be ether - * blocking or nonblocking. The user sets this option - * via ioctl call. - *===========================================================*/ + sk->sk_socket = NULL; + /* Purge queues */ + af_skb_queue_purge(&sk->sk_receive_queue); + af_skb_queue_purge(&sk->sk_error_queue); -static int execute_command(struct sock *sk, unsigned char cmd, unsigned int flags) -{ - wanpipe_opt *wp = wp_sk(sk); - struct net_device *dev; - wanpipe_common_t *chan=NULL; - int err=0; - DECLARE_WAITQUEUE(wait, current); + KFREE(SK_PRIV(sk)); + SK_PRIV_INIT(sk,NULL); - dev = dev_get_by_index(sk->sk_bound_dev_if); - if (dev == NULL){ - printk(KERN_INFO "wansock: Exec failed no dev %i\n", - sk->sk_bound_dev_if); - return -ENODEV; - } - dev_put(dev); - - if ((chan=dev->priv) == NULL){ - printk(KERN_INFO "wansock: Exec cmd failed no priv area\n"); - return -ENODEV; +#if defined(LINUX_2_4)||defined(LINUX_2_6) + if (atomic_read(&sk->sk_refcnt) != 1){ + DEBUG_TEST("af_wanpipe: Error, wrong reference count: %i ! :Kill.\n", + atomic_read(&sk->sk_refcnt)); + atomic_set(&sk->sk_refcnt,1); } + sock_put(sk); +#else + sk_free(sk); +#endif + AF_MEM_DEC(sizeof(struct sock)); + atomic_dec(&wanpipe_socks_nr); - if (atomic_read(&chan->command)){ - printk(KERN_INFO "wansock: ERROR: Command already running %x, %s\n", - atomic_read(&chan->command),dev->name); - return -EINVAL; - } +#ifndef LINUX_2_6 + MOD_DEC_USE_COUNT; +#endif + return; +} - if (!wp->mbox) { - printk(KERN_INFO "wansock: In execute without MBOX\n"); - return -EINVAL; - } - ((mbox_cmd_t*)wp->mbox)->cmd.command = cmd; - ((mbox_cmd_t*)wp->mbox)->cmd.lcn = wp->lcn; - ((mbox_cmd_t*)wp->mbox)->cmd.result = 0x7F; +static void release_queued_pending_sockets(struct sock *sk) +{ + netdevice_t *dev; + struct sk_buff *skb; + struct sock *deadsk; + + while ((skb=skb_dequeue(&sk->sk_receive_queue))!=NULL){ + deadsk=(struct sock *)*(unsigned long*)&skb->data[0]; + if (!deadsk){ + KFREE_SKB(skb); + continue; + } +#ifdef LINUX_2_6 + sock_set_flag(deadsk, SOCK_DEAD); +#else + deadsk->dead=1; +#endif + printk (KERN_INFO "af_wanpipe: Release: found dead sock!\n"); + if (SK_PRIV(deadsk)){ + dev = (struct net_device *)SK_PRIV(deadsk)->dev; + if (dev && dev->do_ioctl){ + struct ifreq ifr; + ifr.ifr_data=(void*)sk; + if (dev->do_ioctl(dev,&ifr,SIOC_ANNEXG_UNBIND_SK)==0){ + dev->do_ioctl(dev,NULL,SIOC_ANNEXG_CLEAR_CALL); + } + } + } - if (flags & O_NONBLOCK){ - cmd |= 0x80; - atomic_set(&chan->command, cmd); - }else{ - atomic_set(&chan->command, cmd); + /* Decrement the sock refcnt, since we took + * the pointer out of the skb buffer */ + __sock_put(deadsk); + wanpipe_kill_sock(deadsk); + KFREE_SKB(skb); } +} - add_wait_queue(sk->sk_sleep,&wait); - current->state = TASK_INTERRUPTIBLE; - for (;;){ - if (((mbox_cmd_t*)wp->mbox)->cmd.result != 0x7F) { - err = 0; - break; - } - if (signal_pending(current)) { - err = -ERESTARTSYS; - break; - } - schedule(); - } - current->state = TASK_RUNNING; - remove_wait_queue(sk->sk_sleep,&wait); - - return err; -} - -/*============================================================ - * wanpipe_destroy_timer - * - * Used by wanpipe_release, to delay release of - * the socket. - *===========================================================*/ - -static void wanpipe_destroy_timer(unsigned long data) -{ - struct sock *sk=(struct sock *)data; - wanpipe_opt *wp = wp_sk(sk); - - if ((!atomic_read(&sk->sk_wmem_alloc) && - !atomic_read(&sk->sk_rmem_alloc)) || - (++wp->force == 5)) { - - if (atomic_read(&sk->sk_wmem_alloc) || - atomic_read(&sk->sk_rmem_alloc)) - printk(KERN_INFO "wansock: Warning, Packet Discarded due to sock shutdown!\n"); - - kfree(wp); - wp_sk(sk) = NULL; - - if (atomic_read(&sk->sk_refcnt) != 1) { - atomic_set(&sk->sk_refcnt, 1); - DBG_PRINTK(KERN_INFO "wansock: Error, wrong reference count: %i ! :delay.\n", - atomic_read(&sk->sk_refcnt)); - } - sock_put(sk); - atomic_dec(&wanpipe_socks_nr); - return; - } - - sk->sk_timer.expires = jiffies + 5 * HZ; - add_timer(&sk->sk_timer); - printk(KERN_INFO "wansock: packet sk destroy delayed\n"); -} - -/*============================================================ - * wanpipe_unlink_driver - * - * When the socket is released, this function is - * used to remove links that bind the sock and the - * driver together. - *===========================================================*/ -static void wanpipe_unlink_driver (struct sock *sk) -{ - struct net_device *dev; - wanpipe_common_t *chan=NULL; - - sock_reset_flag(sk, SOCK_ZAPPED); - sk->sk_state = WANSOCK_DISCONNECTED; - wp_sk(sk)->dev = NULL; - - dev = dev_get_by_index(sk->sk_bound_dev_if); - if (!dev){ - printk(KERN_INFO "wansock: No dev on release\n"); - return; - } - dev_put(dev); - - if ((chan = dev->priv) == NULL){ - printk(KERN_INFO "wansock: No Priv Area on release\n"); - return; - } - - set_bit(0,&chan->common_critical); - chan->sk=NULL; - chan->func=NULL; - chan->mbox=NULL; - chan->tx_timer=NULL; - clear_bit(0,&chan->common_critical); - release_device(dev); - - return; -} - -/*============================================================ - * wanpipe_link_driver - * - * Upon successful bind(), sock is linked to a driver - * by binding in the wanpipe_rcv() bottom half handler - * to the driver function pointer, as well as sock and - * sock mailbox addresses. This way driver can pass - * data up the socket. - *===========================================================*/ - -static void wanpipe_link_driver(struct net_device *dev, struct sock *sk) -{ - wanpipe_opt *wp = wp_sk(sk); - wanpipe_common_t *chan = dev->priv; - if (!chan) - return; - set_bit(0,&chan->common_critical); - chan->sk=sk; - chan->func=wanpipe_rcv; - chan->mbox = wp->mbox; - chan->tx_timer = &wp->tx_timer; - wp->dev = dev; - sock_set_flag(sk, SOCK_ZAPPED); - clear_bit(0,&chan->common_critical); -} - - -/*============================================================ - * release_device - * - * During sock release, clear a critical bit, which - * marks the device a being taken. - *===========================================================*/ - - -static void release_device(struct net_device *dev) -{ - wanpipe_common_t *chan=dev->priv; - clear_bit(0,(void*)&chan->rw_bind); -} /*============================================================ * wanpipe_release @@ -953,90 +1088,147 @@ * protocol entry in the device list. *===========================================================*/ +#if defined(LINUX_2_4)||defined(LINUX_2_6) static int wanpipe_release(struct socket *sock) +#else +static int wanpipe_release(struct socket *sock, struct socket *peersock) +#endif { - wanpipe_opt *wp; + +#if defined(LINUX_2_1) + struct sk_buff *skb; +#endif struct sock *sk = sock->sk; +#ifndef LINUX_2_6 + struct sock **skp; +#endif + unsigned long flags; if (!sk) return 0; - wp = wp_sk(sk); + WAN_ASSERT_EINVAL(!SK_PRIV(sk)); + check_write_queue(sk); +#ifdef CONFIG_PRODUCT_WANPIPE_SOCK_DATASCOPE + if (SK_PRIV(sk) && DATA_SC(sk) && DATA_SC(sk)->parent_sk != NULL){ + wansk_reset_zapped(sk); + wanpipe_unbind_sk_from_parent(sk); + } +#endif + + /* Kill the tx timer, if we don't kill it now, the timer * will run after we kill the sock. Timer code will * try to access the sock which has been killed and cause * kernel panic */ - del_timer(&wp->tx_timer); - /* * Unhook packet receive handler. */ - if (wp->num == htons(X25_PROT) && - sk->sk_state != WANSOCK_DISCONNECTED && sock_flag(sk, SOCK_ZAPPED)) { - struct net_device *dev = dev_get_by_index(sk->sk_bound_dev_if); - wanpipe_common_t *chan; + if (sk->sk_state == WANSOCK_LISTEN || sk->sk_state == WANSOCK_BIND_LISTEN){ + unbind_api_listen_from_protocol (SK_PRIV(sk)->num,sk); + if (SK_PRIV(sk)->dev){ + dev_put(SK_PRIV(sk)->dev); + SK_PRIV(sk)->dev=NULL; + } + release_queued_pending_sockets(sk); + + }else if ((SK_PRIV(sk)->num == htons(ETH_P_X25) || + SK_PRIV(sk)->num == htons(WP_X25_PROT) || + SK_PRIV(sk)->num == htons(DSP_PROT)) && wansk_is_zapped(sk)){ + + netdevice_t *dev = (struct net_device *)SK_PRIV(sk)->dev; if (dev){ - chan=dev->priv; - atomic_set(&chan->disconnect,1); - DBG_PRINTK(KERN_INFO "wansock: Sending Clear Indication %i\n", - sk->sk_state); - dev_put(dev); - } + if(dev->do_ioctl){ + struct ifreq ifr; + ifr.ifr_data=(void*)sk; + if (dev->do_ioctl(dev,&ifr,SIOC_ANNEXG_UNBIND_SK)==0){ + dev->do_ioctl(dev,NULL,SIOC_ANNEXG_CLEAR_CALL); + } + } + }else{ + DEBUG_EVENT("%s: No dev on svc release !\n",__FUNCTION__); + } + }else if (wansk_is_zapped(sk)){ + netdevice_t *dev = (struct net_device *)SK_PRIV(sk)->dev; + if (dev){ + if(dev->do_ioctl){ + struct ifreq ifr; + ifr.ifr_data=(void*)sk; + dev->do_ioctl(dev,&ifr,SIOC_ANNEXG_UNBIND_SK); + } + }else{ + DEBUG_EVENT("%s: No dev on pvc release !\n",__FUNCTION__); + } } - set_bit(1,&wanpipe_tx_critical); - write_lock(&wanpipe_sklist_lock); - sk_del_node_init(sk); - write_unlock(&wanpipe_sklist_lock); - clear_bit(1,&wanpipe_tx_critical); - + sk->sk_state = WANSOCK_DISCONNECTED; + wansk_reset_zapped(sk); + sk->sk_bound_dev_if=0; + if (SK_PRIV(sk)->dev){ + dev_put((struct net_device*)SK_PRIV(sk)->dev); + } - - release_driver(sk); + SK_PRIV(sk)->dev=NULL; + + //FIXME with spinlock_irqsave + write_lock_irqsave(&wanpipe_sklist_lock,flags); +#ifdef LINUX_2_6 + sk_del_node_init(sk); +#else + for (skp = &wanpipe_sklist; *skp; skp = &(*skp)->next) { + if (*skp == sk) { + *skp = sk->next; + __sock_put(sk); + break; + } + } +#endif + write_unlock_irqrestore(&wanpipe_sklist_lock,flags); - /* * Now the socket is dead. No more input will appear. */ sk->sk_state_change(sk); /* It is useless. Just for sanity. */ - + sock->sk = NULL; sk->sk_socket = NULL; + +#ifdef LINUX_2_6 sock_set_flag(sk, SOCK_DEAD); +#else + sk->dead=1; +#endif /* Purge queues */ - skb_queue_purge(&sk->sk_receive_queue); - skb_queue_purge(&sk->sk_write_queue); - skb_queue_purge(&sk->sk_error_queue); - - if (atomic_read(&sk->sk_rmem_alloc) || - atomic_read(&sk->sk_wmem_alloc)) { - del_timer(&sk->sk_timer); - printk(KERN_INFO "wansock: Killing in Timer R %i , W %i\n", - atomic_read(&sk->sk_rmem_alloc), - atomic_read(&sk->sk_wmem_alloc)); - sk->sk_timer.data = (unsigned long)sk; - sk->sk_timer.expires = jiffies + HZ; - sk->sk_timer.function = wanpipe_destroy_timer; - add_timer(&sk->sk_timer); - return 0; - } + af_skb_queue_purge(&sk->sk_receive_queue); + af_skb_queue_purge(&sk->sk_error_queue); - kfree(wp); - wp_sk(sk) = NULL; - if (atomic_read(&sk->sk_refcnt) != 1) { - DBG_PRINTK(KERN_INFO "wansock: Error, wrong reference count: %i !:release.\n", + KFREE(SK_PRIV(sk)); + SK_PRIV_INIT(sk,NULL); + +#if defined(LINUX_2_4)||defined(LINUX_2_6) + if (atomic_read(&sk->sk_refcnt) != 1){ + DEBUG_EVENT("af_wanpipe: Error, wrong reference count: %i !:release.\n", atomic_read(&sk->sk_refcnt)); - atomic_set(&sk->sk_refcnt, 1); + atomic_set(&sk->sk_refcnt,1); } sock_put(sk); +#else + sk_free(sk); +#endif + AF_MEM_DEC(sizeof(struct sock)); atomic_dec(&wanpipe_socks_nr); + +#ifndef LINUX_2_6 + MOD_DEC_USE_COUNT; +#endif + return 0; } @@ -1058,267 +1250,12 @@ if (!atomic_read(&sk->sk_wmem_alloc)) return; - printk(KERN_INFO "wansock: MAJOR ERROR, Data lost on sock release !!!\n"); - -} - -/*============================================================ - * release_driver - * - * This function is called during sock shutdown, to - * release any resources and links that bind the sock - * to the driver. It also changes the state of the - * sock to WANSOCK_DISCONNECTED - *===========================================================*/ - -static void release_driver(struct sock *sk) -{ - wanpipe_opt *wp; - struct sk_buff *skb=NULL; - struct sock *deadsk=NULL; - - if (sk->sk_state == WANSOCK_LISTEN || - sk->sk_state == WANSOCK_BIND_LISTEN) { - while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) { - if ((deadsk = get_newsk_from_skb(skb))){ - DBG_PRINTK (KERN_INFO "wansock: RELEASE: FOUND DEAD SOCK\n"); - sock_set_flag(deadsk, SOCK_DEAD); - start_cleanup_timer(deadsk); - } - kfree_skb(skb); - } - if (sock_flag(sk, SOCK_ZAPPED)) - wanpipe_unlink_card(sk); - }else{ - if (sock_flag(sk, SOCK_ZAPPED)) - wanpipe_unlink_driver(sk); - } - sk->sk_state = WANSOCK_DISCONNECTED; - sk->sk_bound_dev_if = 0; - sock_reset_flag(sk, SOCK_ZAPPED); - wp = wp_sk(sk); - - if (wp) { - kfree(wp->mbox); - wp->mbox = NULL; - } -} - -/*============================================================ - * start_cleanup_timer - * - * If new incoming call's are pending but the socket - * is being released, start the timer which will - * envoke the kill routines for pending socks. - *===========================================================*/ - - -static void start_cleanup_timer (struct sock *sk) -{ - del_timer(&sk->sk_timer); - sk->sk_timer.data = (unsigned long)sk; - sk->sk_timer.expires = jiffies + HZ; - sk->sk_timer.function = wanpipe_kill_sock_timer; - add_timer(&sk->sk_timer); -} - - -/*============================================================ - * wanpipe_kill_sock - * - * This is a function which performs actual killing - * of the sock. It releases socket resources, - * and unlinks the sock from the driver. - *===========================================================*/ - -static void wanpipe_kill_sock_timer (unsigned long data) -{ - - struct sock *sk = (struct sock *)data; - struct sock **skp; - - if (!sk) - return; - - /* This function can be called from interrupt. We must use - * appropriate locks */ - - if (test_bit(1,&wanpipe_tx_critical)){ - sk->sk_timer.expires = jiffies + 10; - add_timer(&sk->sk_timer); - return; - } - - write_lock(&wanpipe_sklist_lock); - sk_del_node_init(sk); - write_unlock(&wanpipe_sklist_lock); - - - if (wp_sk(sk)->num == htons(X25_PROT) && - sk->sk_state != WANSOCK_DISCONNECTED) { - struct net_device *dev = dev_get_by_index(sk->sk_bound_dev_if); - wanpipe_common_t *chan; - if (dev){ - chan=dev->priv; - atomic_set(&chan->disconnect,1); - dev_put(dev); - } - } - - release_driver(sk); - - sk->sk_socket = NULL; - - /* Purge queues */ - skb_queue_purge(&sk->sk_receive_queue); - skb_queue_purge(&sk->sk_write_queue); - skb_queue_purge(&sk->sk_error_queue); - - if (atomic_read(&sk->sk_rmem_alloc) || - atomic_read(&sk->sk_wmem_alloc)) { - del_timer(&sk->sk_timer); - printk(KERN_INFO "wansock: Killing SOCK in Timer\n"); - sk->sk_timer.data = (unsigned long)sk; - sk->sk_timer.expires = jiffies + HZ; - sk->sk_timer.function = wanpipe_destroy_timer; - add_timer(&sk->sk_timer); - return; - } - - kfree(wp_sk(sk)); - wp_sk(sk) = NULL; - - if (atomic_read(&sk->sk_refcnt) != 1) { - atomic_set(&sk->sk_refcnt, 1); - DBG_PRINTK(KERN_INFO "wansock: Error, wrong reference count: %i ! :timer.\n", - atomic_read(&sk->sk_refcnt)); - } - sock_put(sk); - atomic_dec(&wanpipe_socks_nr); - return; -} - -static void wanpipe_kill_sock_accept (struct sock *sk) -{ - - struct sock **skp; - - if (!sk) - return; - - /* This function can be called from interrupt. We must use - * appropriate locks */ - - write_lock(&wanpipe_sklist_lock); - sk_del_node_init(sk); - write_unlock(&wanpipe_sklist_lock); - - sk->sk_socket = NULL; - - - kfree(wp_sk(sk)); - wp_sk(sk) = NULL; - - if (atomic_read(&sk->sk_refcnt) != 1) { - atomic_set(&sk->sk_refcnt, 1); - DBG_PRINTK(KERN_INFO "wansock: Error, wrong reference count: %i ! :timer.\n", - atomic_read(&sk->sk_refcnt)); - } - sock_put(sk); - atomic_dec(&wanpipe_socks_nr); - return; -} - - -static void wanpipe_kill_sock_irq (struct sock *sk) -{ - - if (!sk) - return; - - sk->sk_socket = NULL; - - kfree(wp_sk(sk)); - wp_sk(sk) = NULL; + printk(KERN_INFO "af_wanpipe: MAJOR ERROR, Data lost on sock release !!!\n"); - if (atomic_read(&sk->sk_refcnt) != 1) { - atomic_set(&sk->sk_refcnt, 1); - DBG_PRINTK(KERN_INFO "wansock: Error, wrong reference count: %i !:listen.\n", - atomic_read(&sk->sk_refcnt)); - } - sock_put(sk); - atomic_dec(&wanpipe_socks_nr); } /*============================================================ - * wanpipe_do_bind - * - * Bottom half of the binding system call. - * Once the wanpipe_bind() function checks the - * legality of the call, this function binds the - * sock to the driver. - *===========================================================*/ - -static int wanpipe_do_bind(struct sock *sk, struct net_device *dev, - int protocol) -{ - wanpipe_opt *wp = wp_sk(sk); - wanpipe_common_t *chan=NULL; - int err=0; - - if (sock_flag(sk, SOCK_ZAPPED)) { - err = -EALREADY; - goto bind_unlock_exit; - } - - wp->num = protocol; - - if (protocol == 0){ - release_device(dev); - err = -EINVAL; - goto bind_unlock_exit; - } - - if (dev) { - if (dev->flags&IFF_UP) { - chan=dev->priv; - sk->sk_state = chan->state; - - if (wp->num == htons(X25_PROT) && - sk->sk_state != WANSOCK_DISCONNECTED && - sk->sk_state != WANSOCK_CONNECTING) { - DBG_PRINTK(KERN_INFO - "wansock: Binding to Device not DISCONNECTED %i\n", - sk->sk_state); - release_device(dev); - err = -EAGAIN; - goto bind_unlock_exit; - } - - wanpipe_link_driver(dev,sk); - sk->sk_bound_dev_if = dev->ifindex; - - /* X25 Specific option */ - if (wp->num == htons(X25_PROT)) - wp_sk(sk)->svc = chan->svc; - - } else { - sk->sk_err = ENETDOWN; - sk->sk_error_report(sk); - release_device(dev); - err = -EINVAL; - } - } else { - err = -ENODEV; - } -bind_unlock_exit: - /* FIXME where is this lock */ - - return err; -} - -/*============================================================ * wanpipe_bind * * BIND() System call, which is bound to the AF_WANPIPE @@ -1333,164 +1270,215 @@ { struct wan_sockaddr_ll *sll = (struct wan_sockaddr_ll*)uaddr; struct sock *sk=sock->sk; - wanpipe_opt *wp = wp_sk(sk); - struct net_device *dev = NULL; - sdla_t *card=NULL; + netdevice_t *dev = NULL; char name[15]; + int err=-EINVAL; /* * Check legality */ - + if (addr_len < sizeof(struct wan_sockaddr_ll)){ - printk(KERN_INFO "wansock: Address length error\n"); + printk(KERN_INFO "af_wanpipe: Address length error\n"); return -EINVAL; } if (sll->sll_family != AF_WANPIPE){ - printk(KERN_INFO "wansock: Illegal family name specified.\n"); + printk(KERN_INFO "af_wanpipe: Illegal family name specified.\n"); return -EINVAL; } - card = wanpipe_find_card (sll->sll_card); - if (!card){ - printk(KERN_INFO "wansock: Wanpipe card not found: %s\n",sll->sll_card); - return -ENODEV; - }else{ - wp_sk(sk)->card = (void *)card; - } - - if (!strcmp(sll->sll_device,"svc_listen")){ - - /* Bind a sock to a card structure for listening - */ - int err=0; - - /* This is x25 specific area if protocol doesn't - * match, return error */ - if (sll->sll_protocol != htons(X25_PROT)) - return -EINVAL; - - err= wanpipe_link_card (sk); - if (err < 0) - return err; + WAN_ASSERT_EINVAL(!SK_PRIV(sk)); - if (sll->sll_protocol) - wp->num = sll->sll_protocol; - sk->sk_state = WANSOCK_BIND_LISTEN; - return 0; + sk->sk_family = sll->sll_family; + SK_PRIV(sk)->num = sll->sll_protocol ? sll->sll_protocol : SK_PRIV(sk)->num; - }else if (!strcmp(sll->sll_device,"svc_connect")){ + if (!strcmp(sll->sll_device,"svc_connect") || + !strcmp(sll->sll_device,"dsp_connect")){ - /* This is x25 specific area if protocol doesn't - * match, return error */ - if (sll->sll_protocol != htons(X25_PROT)) - return -EINVAL; + strncpy(name,sll->sll_card,14); + name[14]=0; - /* Find a free device - */ - dev = wanpipe_find_free_dev(card); - if (dev == NULL){ - DBG_PRINTK(KERN_INFO "wansock: No free network devices for card %s\n", - card->devname); - return -EINVAL; + if (SK_PRIV(sk)->num == htons(WP_X25_PROT)){ + SK_PRIV(sk)->num = htons(ETH_P_X25); } - }else{ - /* Bind a socket to a interface name - * This is used by PVC mostly - */ - strlcpy(name,sll->sll_device,sizeof(name)); + + /* Obtain the master device, in case of Annexg this + * device would be a lapb network interface, note + * the usage count on dev will be incremented, once + * we are finshed with the device we should run + * dev_put() to release it */ +#if defined(LINUX_2_4)||defined(LINUX_2_6) dev = dev_get_by_name(name); +#else + dev = dev_get(name); +#endif if (dev == NULL){ - printk(KERN_INFO "wansock: Failed to get Dev from name: %s,\n", + + sk->sk_bound_dev_if = bind_api_to_protocol(NULL, + sll->sll_card, + htons(WP_X25_PROT), + (void*)sk); + if (sk->sk_bound_dev_if >= 0){ + SK_PRIV(sk)->num = htons(WP_X25_PROT); + goto wanpipe_svc_connect_skip; + } + + printk(KERN_INFO "af_wanpipe: Failed to get Dev from name: %s,\n", name); return -ENODEV; } - dev_put(dev); - - if (check_dev(dev, card)){ - printk(KERN_INFO "wansock: Device %s, doesn't belong to card %s\n", - dev->name, card->devname); - return -EINVAL; - } - if (get_atomic_device (dev)) - return -EINVAL; - } + if (!(dev->flags&IFF_UP)){ + printk(KERN_INFO "af_wanpipe: Bind device %s is down!\n", + name); + dev_put(dev); + return -ENODEV; + } + + sk->sk_bound_dev_if = bind_api_to_protocol(dev,sll->sll_card,SK_PRIV(sk)->num,(void*)sk); + + /* We are finished with the lapb master device, we + * need it to find a free svc or dsp device but now + * we can release it */ + dev_put(dev); + +wanpipe_svc_connect_skip: + + if (sk->sk_bound_dev_if < 0){ + sk->sk_bound_dev_if=0; + err=-EINVAL; + }else{ + sk->sk_state = WANSOCK_DISCONNECTED; + SK_PRIV(sk)->dev=dev_get_by_index(sk->sk_bound_dev_if); + if (SK_PRIV(sk)->dev){ + err=0; + }else{ + /* This should never ever happen !*/ + err=-EINVAL; + } + } + + }else if (!strcmp(sll->sll_device,"svc_listen") || + !strcmp(sll->sll_device,"dsp_listen")){ - return wanpipe_do_bind(sk, dev, sll->sll_protocol ? : wp->num); -} + strncpy(name,sll->sll_card,14); + name[14]=0; -/*============================================================ - * get_atomic_device - * - * Sets a bit atomically which indicates that - * the interface is taken. This avoids race conditions. - *===========================================================*/ + if (SK_PRIV(sk)->num == htons(WP_X25_PROT)){ + SK_PRIV(sk)->num = htons(ETH_P_X25); + } + /* Obtain the master device, in case of Annexg this + * device would be a lapb network interface, note + * the usage count on dev will be incremented, once + * we are finshed with the device we should run + * dev_put() to release it */ -static inline int get_atomic_device(struct net_device *dev) -{ - wanpipe_common_t *chan = dev->priv; - if (!test_and_set_bit(0,(void *)&chan->rw_bind)){ - return 0; - } - return 1; -} +#if defined(LINUX_2_4)||defined(LINUX_2_6) + dev = dev_get_by_name(name); +#else + dev = dev_get(name); +#endif + if (dev == NULL){ -/*============================================================ - * check_dev - * - * Check that device name belongs to a particular card. - *===========================================================*/ + err = bind_api_listen_to_protocol(NULL,sll->sll_card, + htons(WP_X25_PROT), + (void*)sk); + if (err==0){ + SK_PRIV(sk)->num = htons(WP_X25_PROT); + goto wanpipe_svc_listen_skip; + } + + printk(KERN_INFO "af_wanpipe: Failed to get Dev from name: %s,\n", + name); + return -ENODEV; + } -static int check_dev(struct net_device *dev, sdla_t *card) -{ - struct net_device* tmp_dev; + if (!(dev->flags&IFF_UP)){ + printk(KERN_INFO "af_wanpipe: Bind device %s is down!\n", + name); + dev_put(dev); + return -ENODEV; + } + + err = bind_api_listen_to_protocol(dev,sll->sll_card,SK_PRIV(sk)->num,sk); + + SK_PRIV(sk)->dev=dev; + sk->sk_bound_dev_if=dev->ifindex; - for (tmp_dev = card->wandev.dev; tmp_dev; - tmp_dev = *((struct net_device **)tmp_dev->priv)) { - if (tmp_dev->ifindex == dev->ifindex){ - return 0; +wanpipe_svc_listen_skip: + + if (!err){ + sk->sk_state = WANSOCK_BIND_LISTEN; } - } - return 1; -} -/*============================================================ - * wanpipe_find_free_dev - * - * Find a free network interface. If found set atomic - * bit indicating that the interface is taken. - * X25API Specific. - *===========================================================*/ + + }else{ + struct ifreq ifr; + strncpy(name,sll->sll_device,14); + name[14]=0; + +#if defined(LINUX_2_4)||defined(LINUX_2_6) + dev = dev_get_by_name(name); +#else + dev = dev_get(name); +#endif + if (dev == NULL){ + printk(KERN_INFO "af_wanpipe: Failed to get Dev from name: %s,\n", + name); + return -ENODEV; + } -struct net_device *wanpipe_find_free_dev(sdla_t *card) -{ - struct net_device* dev; - volatile wanpipe_common_t *chan; + if (!(dev->flags&IFF_UP)){ + printk(KERN_INFO "af_wanpipe: Bind device %s is down!\n", + name); + dev_put(dev); + return -ENODEV; + } - if (test_and_set_bit(0,&find_free_critical)){ - printk(KERN_INFO "CRITICAL in Find Free\n"); - } + ifr.ifr_data = (void*)sk; + err=-ENODEV; - for (dev = card->wandev.dev; dev; - dev = *((struct net_device **)dev->priv)) { - chan = dev->priv; - if (!chan) - continue; - if (chan->usedby == API && chan->svc){ - if (!get_atomic_device (dev)){ - if (chan->state != WANSOCK_DISCONNECTED){ - release_device(dev); +#ifdef CONFIG_PRODUCT_WANPIPE_SOCK_DATASCOPE + if (SK_PRIV(sk)->num == htons(SS7_MONITOR_PROT)){ + return wanpipe_bind_sk_to_parent(sk,dev,sll); + } +#endif + + if (dev->do_ioctl) + err=dev->do_ioctl(dev,&ifr,SIOC_ANNEXG_BIND_SK); + + if (err == 0){ + sk->sk_bound_dev_if = dev->ifindex; + SK_PRIV(sk)->dev = dev; + + + if (SK_PRIV(sk)->num == htons(ETH_P_X25) || + SK_PRIV(sk)->num == htons(WP_X25_PROT) || + SK_PRIV(sk)->num == htons(DSP_PROT)){ + sk->sk_state = WANSOCK_DISCONNECTED; + }else{ + err=dev->do_ioctl(dev,&ifr,SIOC_WANPIPE_DEV_STATE); + if (err == WANSOCK_CONNECTED){ + sk->sk_state = WANSOCK_CONNECTED; }else{ - clear_bit(0,&find_free_critical); - return dev; + sk->sk_state = WANSOCK_CONNECTING; } + err=0; } + }else{ + dev_put(dev); } } - clear_bit(0,&find_free_critical); - return NULL; + + if (!err){ + wansk_set_zapped(sk); + } + +// printk(KERN_INFO "11-11 Bind Socket Prot %i, X25=%i Zapped %i, Bind Dev %i Sock %u!\n", +// SK_PRIV(sk)->num,htons(ETH_P_X25),sk->sk_zapped,sk->sk_bound_dev_if,(u32)sk); + + return err; } /*============================================================ @@ -1501,43 +1489,47 @@ * Crates AF_WANPIPE socket. *===========================================================*/ -static int wanpipe_create(struct socket *sock, int protocol) +int wanpipe_create(struct socket *sock, int protocol) { struct sock *sk; + unsigned long flags; - //FIXME: This checks for root user, SECURITY ? - //if (!capable(CAP_NET_RAW)) - // return -EPERM; - - if (sock->type != SOCK_DGRAM && sock->type != SOCK_RAW) + if (sock->type != SOCK_RAW) return -ESOCKTNOSUPPORT; sock->state = SS_UNCONNECTED; - - if ((sk = wanpipe_alloc_socket()) == NULL) - return -ENOBUFS; + + if ((sk = wanpipe_alloc_socket()) == NULL){ + return -ENOMEM; + } sk->sk_reuse = 1; sock->ops = &wanpipe_ops; sock_init_data(sock,sk); - sock_reset_flag(sk, SOCK_ZAPPED); - sk->sk_family = PF_WANPIPE; - wp_sk(sk)->num = protocol; - sk->sk_state = WANSOCK_DISCONNECTED; - sk->sk_ack_backlog = 0; - sk->sk_bound_dev_if = 0; + wansk_reset_zapped(sk); + sk->sk_family = AF_WANPIPE; + SK_PRIV(sk)->num = protocol; + sk->sk_state = WANSOCK_UNCONFIGURED; + sk->sk_ack_backlog = 0; + sk->sk_bound_dev_if=0; + SK_PRIV(sk)->dev=NULL; atomic_inc(&wanpipe_socks_nr); /* We must disable interrupts because the ISR * can also change the list */ - set_bit(1,&wanpipe_tx_critical); - write_lock(&wanpipe_sklist_lock); + + write_lock_irqsave(&wanpipe_sklist_lock,flags); +#ifdef LINUX_2_6 sk_add_node(sk, &wanpipe_sklist); - write_unlock(&wanpipe_sklist_lock); - clear_bit(1,&wanpipe_tx_critical); - +#else + sk->next = wanpipe_sklist; + wanpipe_sklist = sk; + sock_hold(sk); +#endif + write_unlock_irqrestore(&wanpipe_sklist_lock,flags); + return(0); } @@ -1549,13 +1541,24 @@ * to the user. If necessary we block. *===========================================================*/ +#ifdef LINUX_2_6 + static int wanpipe_recvmsg(struct kiocb *iocb, struct socket *sock, - struct msghdr *msg, int len, int flags) + struct msghdr *msg, size_t len, int flags) +#else +static int wanpipe_recvmsg(struct socket *sock, struct msghdr *msg, int len, + int flags, struct scm_cookie *scm) +#endif { struct sock *sk = sock->sk; struct sk_buff *skb; int copied, err=-ENOBUFS; + struct net_device *dev=NULL; + + WAN_ASSERT_EINVAL(!SK_PRIV(sk)); + if (!wansk_is_zapped(sk)) + return -ENETDOWN; /* * If the address length field is there to be filled in, we fill @@ -1574,7 +1577,7 @@ */ if (flags & MSG_OOB){ - skb = skb_dequeue(&sk->sk_error_queue); + skb=skb_dequeue(&sk->sk_error_queue); }else{ skb=skb_recv_datagram(sk,flags,1,&err); } @@ -1587,6 +1590,14 @@ if(skb==NULL) goto out; + + dev = (struct net_device *)SK_PRIV(sk)->dev; + if (dev){ + if (dev->do_ioctl){ + dev->do_ioctl(dev,NULL,SIOC_ANNEXG_KICK); + } + } + /* * You lose any data beyond the buffer you gave. If it worries a * user program they can ask the device for its MTU anyway. @@ -1599,14 +1610,16 @@ msg->msg_flags|=MSG_TRUNC; } - wanpipe_wakeup_driver(sk); - /* We can't use skb_copy_datagram here */ err = memcpy_toiovec(msg->msg_iov, skb->data, copied); if (err) goto out_free; +#ifdef LINUX_2_1 + sk->stamp=skb->stamp; +#else sock_recv_timestamp(msg, sk, skb); +#endif if (msg->msg_name) memcpy(msg->msg_name, skb->cb, msg->msg_namelen); @@ -1618,49 +1631,12 @@ err = (flags&MSG_TRUNC) ? skb->len : copied; out_free: + AF_SKB_DEC(skb->truesize); skb_free_datagram(sk, skb); out: return err; } - -/*============================================================ - * wanpipe_wakeup_driver - * - * If socket receive buffer is full and driver cannot - * pass data up the sock, it sets a packet_block flag. - * This function check that flag and if sock receive - * queue has room it kicks the driver BH handler. - * - * This way, driver doesn't have to poll the sock - * receive queue. - *===========================================================*/ - -static void wanpipe_wakeup_driver(struct sock *sk) -{ - struct net_device *dev = NULL; - wanpipe_common_t *chan=NULL; - - dev = dev_get_by_index(sk->sk_bound_dev_if); - if (!dev) - return; - - dev_put(dev); - - if ((chan = dev->priv) == NULL) - return; - - if (atomic_read(&chan->receive_block)){ - if (atomic_read(&sk->sk_rmem_alloc) < - ((unsigned)sk->sk_rcvbuf * 0.9)) { - printk(KERN_INFO "wansock: Queuing task for wanpipe\n"); - atomic_set(&chan->receive_block,0); - wanpipe_queue_tq(&chan->wanpipe_task); - wanpipe_mark_bh(); - } - } -} - /*============================================================ * wanpipe_getname * @@ -1673,14 +1649,16 @@ static int wanpipe_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_len, int peer) { - struct net_device *dev; + netdevice_t *dev; struct sock *sk = sock->sk; struct wan_sockaddr_ll *sll = (struct wan_sockaddr_ll*)uaddr; - sll->sll_family = AF_WANPIPE; + WAN_ASSERT_EINVAL(!SK_PRIV(sk)); + + sll->sll_family = sk->sk_family; sll->sll_ifindex = sk->sk_bound_dev_if; - sll->sll_protocol = wp_sk(sk)->num; - dev = dev_get_by_index(sk->sk_bound_dev_if); + sll->sll_protocol = SK_PRIV(sk)->num; + dev = (struct net_device *)SK_PRIV(sk)->dev; if (dev) { sll->sll_hatype = dev->type; sll->sll_halen = dev->addr_len; @@ -1691,8 +1669,6 @@ } *uaddr_len = sizeof(*sll); - dev_put(dev); - return 0; } @@ -1708,897 +1684,410 @@ * *===========================================================*/ -static int wanpipe_notifier(struct notifier_block *this, unsigned long msg, void *data) +int wanpipe_notifier(struct notifier_block *this, unsigned long msg, void *data) { struct sock *sk; - hlist_node *node; - struct net_device *dev = (struct net_device *)data; +#ifdef LINUX_2_6 + struct hlist_node *node; +#endif + netdevice_t *dev = (netdevice_t*)data; - sk_for_each(sk, node, &wanpipe_sklist) { - struct wanpipe_opt *po = wp_sk(sk); + if (dev==NULL){ + DEBUG_EVENT("af_wanpiep:%s: Dev==NULL!\n",__FUNCTION__); + return NOTIFY_DONE; + } - if (!po) - continue; - if (dev == NULL) - continue; - + read_lock(&wanpipe_sklist_lock); +#ifdef LINUX_2_6 + sk_for_each(sk, node, &wanpipe_sklist) { +#else + for (sk = wanpipe_sklist; sk; sk = sk->next) { +#endif switch (msg) { case NETDEV_DOWN: case NETDEV_UNREGISTER: if (dev->ifindex == sk->sk_bound_dev_if) { - printk(KERN_INFO "wansock: Device down %s\n",dev->name); - if (sock_flag(sk, SOCK_ZAPPED)) { - wanpipe_unlink_driver(sk); - sk->sk_err = ENETDOWN; - sk->sk_error_report(sk); - } + + printk(KERN_INFO "af_wanpipe: Device down %s\n",dev->name); - if (msg == NETDEV_UNREGISTER) { - printk(KERN_INFO "wansock: Unregistering Device: %s\n", - dev->name); - wanpipe_unlink_driver(sk); - sk->sk_bound_dev_if = 0; + if (sk->sk_state != WANSOCK_LISTEN && + sk->sk_state != WANSOCK_BIND_LISTEN){ + sk->sk_state = WANSOCK_DISCONNECTED; } - } - break; - case NETDEV_UP: - if (dev->ifindex == sk->sk_bound_dev_if && - po->num && !sock_flag(sk, SOCK_ZAPPED)) { - printk(KERN_INFO "wansock: Registering Device: %s\n", - dev->name); - wanpipe_link_driver(dev,sk); + sk->sk_bound_dev_if = 0; + wansk_reset_zapped(sk); + + if (SK_PRIV(sk) && SK_PRIV(sk)->dev){ + dev_put((struct net_device *)SK_PRIV(sk)->dev); + SK_PRIV(sk)->dev=NULL; + } + sk->sk_data_ready(sk,0); } break; } } + read_unlock(&wanpipe_sklist_lock); + return NOTIFY_DONE; } -/*============================================================ - * wanpipe_ioctl - * - * Execute a user commands, and set socket options. +/*====================================================================== + * wanpipe_poll * - * FIXME: More thought should go into this function. + * Datagram poll: Again totally generic. This also handles + * sequenced packet sockets providing the socket receive queue + * is only ever holding data ready to receive. * - *===========================================================*/ + * Note: when you _don't_ use this routine for this protocol, + * and you use a different write policy from sock_writeable() + * then please supply your own write_space callback. + *=====================================================================*/ -static int wanpipe_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) +static unsigned int wanpipe_poll(struct file * file, struct socket *sock, poll_table *wait) { struct sock *sk = sock->sk; - int err; - - switch(cmd) - { - case SIOCGSTAMP: - return sock_get_timestamp(sk, (struct timeval __user *)arg); - - case SIOC_WANPIPE_CHECK_TX: - - return atomic_read(&sk->sk_wmem_alloc); - - case SIOC_WANPIPE_SOCK_STATE: - - if (sk->sk_state == WANSOCK_CONNECTED) - return 0; - - return 1; - + unsigned int mask=0; + struct net_device *dev=NULL; - case SIOC_WANPIPE_GET_CALL_DATA: - - return get_ioctl_cmd (sk,(void*)arg); - - case SIOC_WANPIPE_SET_CALL_DATA: - - return set_ioctl_cmd (sk,(void*)arg); + if (!sk){ + return 0; + } - case SIOC_WANPIPE_ACCEPT_CALL: - case SIOC_WANPIPE_CLEAR_CALL: - case SIOC_WANPIPE_RESET_CALL: + if (!SK_PRIV(sk) || !wansk_is_zapped(sk)){ + mask |= POLLPRI; + return mask; + } - if ((err=set_ioctl_cmd(sk,(void*)arg)) < 0) - return err; + DEBUG_TX("%s: Sock State %p = %d\n", + __FUNCTION__,sk,sk->sk_state); - err=wanpipe_exec_cmd(sk,cmd,0); - get_ioctl_cmd(sk,(void*)arg); - return err; + poll_wait(file, sk->sk_sleep, wait); - case SIOC_WANPIPE_DEBUG: + /* exceptional events? */ + if (!SK_PRIV(sk) || + !wansk_is_zapped(sk) || + sk->sk_err || + !skb_queue_empty(&sk->sk_error_queue)){ + mask |= POLLPRI; + return mask; + } + if (sk->sk_shutdown & RCV_SHUTDOWN){ + mask |= POLLHUP; + } - return wanpipe_debug(sk,(void*)arg); + /* readable? */ + if (!skb_queue_empty(&sk->sk_receive_queue)){ + mask |= POLLIN | POLLRDNORM; + } - case SIOC_WANPIPE_SET_NONBLOCK: + /* connection hasn't started yet */ + if (sk->sk_state == WANSOCK_CONNECTING || sk->sk_state == WANSOCK_LISTEN){ + DEBUG_TEST("%s: Sk state connecting\n",__FUNCTION__); + return mask; + } - if (sk->sk_state != WANSOCK_DISCONNECTED) - return -EINVAL; + if (sk->sk_state != WANSOCK_CONNECTED){ + mask = POLLPRI; + DEBUG_TEST("%s: Sock not connected event on sock %p State=%i\n", + __FUNCTION__,sk,sk->sk_state); + return mask; + } + + if ((dev = (struct net_device *)SK_PRIV(sk)->dev) == NULL){ + printk(KERN_INFO "af_wanpipe: No Device found in POLL!\n"); + return mask; + } - sock->file->f_flags |= O_NONBLOCK; - return 0; + if (!(dev->flags & IFF_UP)) + return mask; -#ifdef CONFIG_INET - case SIOCADDRT: - case SIOCDELRT: - case SIOCDARP: - case SIOCGARP: - case SIOCSARP: - case SIOCDRARP: - case SIOCGRARP: - case SIOCSRARP: - case SIOCGIFADDR: - case SIOCSIFADDR: - case SIOCGIFBRDADDR: - case SIOCSIFBRDADDR: - case SIOCGIFNETMASK: - case SIOCSIFNETMASK: - case SIOCGIFDSTADDR: - case SIOCSIFDSTADDR: - case SIOCSIFFLAGS: - return inet_dgram_ops.ioctl(sock, cmd, arg); + if (!netif_queue_stopped(dev)){ + DEBUG_TEST("%s: Dev stopped\n",__FUNCTION__); + mask |= POLLOUT | POLLWRNORM | POLLWRBAND; + }else{ +#if defined(LINUX_2_4)||defined(LINUX_2_6) + set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags); +#else + sk->sk_socket->flags |= SO_NOSPACE; #endif - - default: - return -ENOIOCTLCMD; } - /*NOTREACHED*/ + + return mask; } -/*============================================================ - * wanpipe_debug - * - * This function will pass up information about all - * active sockets. - * - * FIXME: More thought should go into this function. - * - *===========================================================*/ - -static int wanpipe_debug (struct sock *origsk, void *arg) +static int wanpipe_api_connected(struct net_device *dev, struct sock *sk) { - struct sock *sk; - struct hlist_node *node; - struct net_device *dev = NULL; - wanpipe_common_t *chan=NULL; - int cnt=0, err=0; - wan_debug_t *dbg_data = (wan_debug_t *)arg; - - sk_for_each(sk, node, &wanpipe_sklist) { - wanpipe_opt *wp = wp_sk(sk); - - if (sk == origsk){ - continue; - } + if (sk == NULL || dev == NULL) + return -EINVAL; - if ((err=put_user(1, &dbg_data->debug[cnt].free))) - return err; - if ((err = put_user(sk->sk_state, - &dbg_data->debug[cnt].state_sk))) - return err; - if ((err = put_user(sk->sk_rcvbuf, - &dbg_data->debug[cnt].rcvbuf))) - return err; - if ((err = put_user(atomic_read(&sk->sk_rmem_alloc), - &dbg_data->debug[cnt].rmem))) - return err; - if ((err = put_user(atomic_read(&sk->sk_wmem_alloc), - &dbg_data->debug[cnt].wmem))) - return err; - if ((err = put_user(sk->sk_sndbuf, - &dbg_data->debug[cnt].sndbuf))) - return err; - if ((err=put_user(sk_count, &dbg_data->debug[cnt].sk_count))) - return err; - if ((err=put_user(wp->poll_cnt, &dbg_data->debug[cnt].poll_cnt))) - return err; - if ((err = put_user(sk->sk_bound_dev_if, - &dbg_data->debug[cnt].bound))) - return err; - - if (sk->sk_bound_dev_if) { - dev = dev_get_by_index(sk->sk_bound_dev_if); - if (!dev) - continue; + if (!wansk_is_zapped(sk)) + return -EINVAL; - chan=dev->priv; - dev_put(dev); + DEBUG_TEST("%s: API Connected!\n",__FUNCTION__); - if ((err=put_user(chan->state, &dbg_data->debug[cnt].d_state))) - return err; - if ((err=put_user(chan->svc, &dbg_data->debug[cnt].svc))) - return err; - - if ((err=put_user(atomic_read(&chan->command), - &dbg_data->debug[cnt].command))) - return err; - - - if (wp){ - sdla_t *card = (sdla_t*)wp->card; - - if (card){ - if ((err=put_user(atomic_read(&card->u.x.command_busy), - &dbg_data->debug[cnt].cmd_busy))) - return err; - } + sk->sk_state = WANSOCK_CONNECTED; + sk->sk_data_ready(sk,0); + return 0; +} - if ((err=put_user(wp->lcn, - &dbg_data->debug[cnt].lcn))) - return err; - - if (wp->mbox) { - if ((err=put_user(1, &dbg_data->debug[cnt].mbox))) - return err; - } - } +static int wanpipe_api_connecting(struct net_device *dev, struct sock *sk) +{ + if (sk == NULL || dev == NULL) + return -EINVAL; - if ((err=put_user(atomic_read(&chan->receive_block), - &dbg_data->debug[cnt].rblock))) - return err; + if (!wansk_is_zapped(sk)) + return -EINVAL; - if (copy_to_user(dbg_data->debug[cnt].name, dev->name, strlen(dev->name))) - return -EFAULT; - } + DEBUG_TEST("%s: API Connecting!\n",__FUNCTION__); - if (++cnt == MAX_NUM_DEBUG) - break; - } + sk->sk_state = WANSOCK_CONNECTING; + sk->sk_data_ready(sk,0); return 0; } -/*============================================================ - * get_ioctl_cmd - * - * Pass up the contents of socket MBOX to the user. - *===========================================================*/ -static int get_ioctl_cmd (struct sock *sk, void *arg) +static int wanpipe_api_disconnected(struct sock *sk) { - x25api_t *usr_data = (x25api_t *)arg; - mbox_cmd_t *mbox_ptr; - int err; - - if (usr_data == NULL) - return -EINVAL; - - if (!wp_sk(sk)->mbox) { + if (sk == NULL) return -EINVAL; - } - - mbox_ptr = (mbox_cmd_t *)wp_sk(sk)->mbox; - - if ((err=put_user(mbox_ptr->cmd.qdm, &usr_data->hdr.qdm))) - return err; - if ((err=put_user(mbox_ptr->cmd.cause, &usr_data->hdr.cause))) - return err; - if ((err=put_user(mbox_ptr->cmd.diagn, &usr_data->hdr.diagn))) - return err; - if ((err=put_user(mbox_ptr->cmd.length, &usr_data->hdr.length))) - return err; - if ((err=put_user(mbox_ptr->cmd.result, &usr_data->hdr.result))) - return err; - if ((err=put_user(mbox_ptr->cmd.lcn, &usr_data->hdr.lcn))) - return err; - - if (mbox_ptr->cmd.length > 0){ - if (mbox_ptr->cmd.length > X25_MAX_DATA) - return -EINVAL; - - if (copy_to_user(usr_data->data, mbox_ptr->data, mbox_ptr->cmd.length)){ - printk(KERN_INFO "wansock: Copy failed !!!\n"); - return -EFAULT; - } - } - return 0; -} - -/*============================================================ - * set_ioctl_cmd - * - * Before command can be execute, socket MBOX must - * be created, and initialized with user data. - *===========================================================*/ - -static int set_ioctl_cmd (struct sock *sk, void *arg) -{ - x25api_t *usr_data = (x25api_t *)arg; - mbox_cmd_t *mbox_ptr; - int err; - if (!wp_sk(sk)->mbox) { - void *mbox_ptr; - struct net_device *dev = dev_get_by_index(sk->sk_bound_dev_if); - if (!dev) - return -ENODEV; - dev_put(dev); + if (sk->sk_state == WANSOCK_BIND_LISTEN || + sk->sk_state == WANSOCK_LISTEN) { - if ((mbox_ptr = kmalloc(sizeof(mbox_cmd_t), GFP_ATOMIC)) == NULL) - return -ENOMEM; - - memset(mbox_ptr, 0, sizeof(mbox_cmd_t)); - wp_sk(sk)->mbox = mbox_ptr; - - wanpipe_link_driver(dev,sk); - } - - mbox_ptr = (mbox_cmd_t*)wp_sk(sk)->mbox; - memset(mbox_ptr, 0, sizeof(mbox_cmd_t)); - - if (usr_data == NULL){ + sk->sk_state = WANSOCK_DISCONNECTED; + sk->sk_data_ready(sk,0); return 0; } - if ((err=get_user(mbox_ptr->cmd.qdm, &usr_data->hdr.qdm))) - return err; - if ((err=get_user(mbox_ptr->cmd.cause, &usr_data->hdr.cause))) - return err; - if ((err=get_user(mbox_ptr->cmd.diagn, &usr_data->hdr.diagn))) - return err; - if ((err=get_user(mbox_ptr->cmd.length, &usr_data->hdr.length))) - return err; - if ((err=get_user(mbox_ptr->cmd.result, &usr_data->hdr.result))) - return err; - - if (mbox_ptr->cmd.length > 0){ - if (mbox_ptr->cmd.length > X25_MAX_DATA) - return -EINVAL; - - if (copy_from_user(mbox_ptr->data, usr_data->data, mbox_ptr->cmd.length)){ - printk(KERN_INFO "Copy failed\n"); - return -EFAULT; - } + + + if (!wansk_is_zapped(sk)){ + return -EINVAL; } + + DEBUG_TEST("%s: API Disconnected!\n",__FUNCTION__); + + sk->sk_state = WANSOCK_DISCONNECTED; + + sk->sk_data_ready(sk,0); return 0; } /*====================================================================== - * wanpipe_poll - * - * Datagram poll: Again totally generic. This also handles - * sequenced packet sockets providing the socket receive queue - * is only ever holding data ready to receive. + * wanpipe_connect * - * Note: when you _don't_ use this routine for this protocol, - * and you use a different write policy from sock_writeable() - * then please supply your own write_space callback. + * CONNECT() System Call. X25API specific function + * Check the state of the sock, and execute PLACE_CALL command. + * Connect can ether block or return without waiting for connection, + * if specified by user. *=====================================================================*/ -unsigned int wanpipe_poll(struct file * file, struct socket *sock, poll_table *wait) +static int wanpipe_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len, int flags) { struct sock *sk = sock->sk; - unsigned int mask; - - ++wp_sk(sk)->poll_cnt; - - poll_wait(file, sk->sk_sleep, wait); - mask = 0; - - /* exceptional events? */ - if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue)) { - mask |= POLLPRI; - return mask; - } - if (sk->sk_shutdown & RCV_SHUTDOWN) - mask |= POLLHUP; - - /* readable? */ - if (!skb_queue_empty(&sk->sk_receive_queue)) { - mask |= POLLIN | POLLRDNORM; - } + struct wan_sockaddr_ll *addr = (struct wan_sockaddr_ll*)uaddr; + netdevice_t *dev; + int err; - /* connection hasn't started yet */ - if (sk->sk_state == WANSOCK_CONNECTING) { - return mask; + if (!wansk_is_zapped(sk)){ /* Must bind first - autobinding does not work */ + return -EINVAL; } - - if (sk->sk_state == WANSOCK_DISCONNECTED) { - mask = POLLPRI; - return mask; + + WAN_ASSERT_EINVAL(!SK_PRIV(sk)); + + if (SK_PRIV(sk)->num != htons(ETH_P_X25) && + SK_PRIV(sk)->num != htons(WP_X25_PROT) && + SK_PRIV(sk)->num != htons(DSP_PROT) && + SK_PRIV(sk)->num != htons(LAPB_PROT) && + SK_PRIV(sk)->num != htons(SS7_PROT)){ + DEBUG_EVENT("%s: Illegal protocol in connect() sys call!\n", + __FUNCTION__); + return -EINVAL; } - /* This check blocks the user process if there is - * a packet already queued in the socket write queue. - * This option is only for X25API protocol, for other - * protocol like chdlc enable streaming mode, - * where multiple packets can be pending in the socket - * transmit queue */ - - if (wp_sk(sk)->num == htons(X25_PROT)) { - if (atomic_read(&wp_sk(sk)->packet_sent)) - return mask; + if (sk->sk_state == WANSOCK_CONNECTED){ + return EISCONN; /* No reconnect on a seqpacket socket */ } - /* writable? */ - if (sock_writeable(sk)){ - mask |= POLLOUT | POLLWRNORM | POLLWRBAND; - }else{ - set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags); + if (SK_PRIV(sk)->num == htons(SS7_PROT)){ + sock->state = SS_CONNECTING; + sk->sk_state = WANSOCK_CONNECTING; + return 0; } - return mask; -} - -/*====================================================================== - * wanpipe_listen - * - * X25API Specific function. Set a socket into LISTENING MODE. - *=====================================================================*/ - - -static int wanpipe_listen(struct socket *sock, int backlog) -{ - struct sock *sk = sock->sk; - - /* This is x25 specific area if protocol doesn't - * match, return error */ - if (wp_sk(sk)->num != htons(X25_PROT)) - return -EINVAL; - - if (sk->sk_state == WANSOCK_BIND_LISTEN) { - - sk->sk_max_ack_backlog = backlog; - sk->sk_state = WANSOCK_LISTEN; - return 0; - }else{ - printk(KERN_INFO "wansock: Listening sock was not binded\n"); + if (sk->sk_state != WANSOCK_DISCONNECTED){ + printk(KERN_INFO "af_wanpipe: Trying to connect on channel NON DISCONNECT\n"); + return -ECONNREFUSED; } - return -EINVAL; -} - -/*====================================================================== - * wanpipe_link_card - * - * Connects the listening socket to the driver - *=====================================================================*/ - -static int wanpipe_link_card (struct sock *sk) -{ - sdla_t *card = (sdla_t*)wp_sk(sk)->card; - - if (!card) - return -ENOMEM; + sk->sk_state = WANSOCK_DISCONNECTED; + sock->state = SS_UNCONNECTED; - if ((card->sk != NULL) || (card->func != NULL)){ - printk(KERN_INFO "wansock: Listening queue is already established\n"); + if (addr_len != sizeof(struct wan_sockaddr_ll)){ return -EINVAL; } - card->sk=sk; - card->func=wanpipe_listen_rcv; - sock_set_flag(sk, SOCK_ZAPPED); - - return 0; -} - -/*====================================================================== - * wanpipe_listen - * - * X25API Specific function. Disconnect listening socket from - * the driver. - *=====================================================================*/ - -static void wanpipe_unlink_card (struct sock *sk) -{ - sdla_t *card = (sdla_t*)wp_sk(sk)->card; - - if (card){ - card->sk=NULL; - card->func=NULL; - } -} - -/*====================================================================== - * wanpipe_exec_cmd - * - * Ioctl function calls this function to execute user command. - * Connect() sytem call also calls this function to execute - * place call. This function blocks until command is executed. - *=====================================================================*/ - -static int wanpipe_exec_cmd(struct sock *sk, int cmd, unsigned int flags) -{ - int err = -EINVAL; - wanpipe_opt *wp = wp_sk(sk); - mbox_cmd_t *mbox_ptr = (mbox_cmd_t*)wp->mbox; - - if (!mbox_ptr){ - printk(KERN_INFO "NO MBOX PTR !!!!!\n"); + if (addr->sll_family != AF_WANPIPE){ return -EINVAL; } - - /* This is x25 specific area if protocol doesn't - * match, return error */ - if (wp->num != htons(X25_PROT)) - return -EINVAL; - - - switch (cmd){ - - case SIOC_WANPIPE_ACCEPT_CALL: - - if (sk->sk_state != WANSOCK_CONNECTING) { - err = -EHOSTDOWN; - break; - } - - err = execute_command(sk,X25_ACCEPT_CALL,0); - if (err < 0) - break; - /* Update. Mar6 2000. - * Do not set the sock lcn number here, since - * it is done in wanpipe_listen_rcv(). - */ - if (sk->sk_state == WANSOCK_CONNECTED) { - wp->lcn = ((mbox_cmd_t*)wp->mbox)->cmd.lcn; - DBG_PRINTK(KERN_INFO "\nwansock: Accept OK %i\n", - wp->lcn); - err = 0; - - }else{ - DBG_PRINTK (KERN_INFO "\nwansock: Accept Failed %i\n", - wp->lcn); - wp->lcn = 0; - err = -ECONNREFUSED; - } - break; - - case SIOC_WANPIPE_CLEAR_CALL: - - if (sk->sk_state == WANSOCK_DISCONNECTED) { - err = -EINVAL; - break; - } - - - /* Check if data buffers are pending for transmission, - * if so, check whether user wants to wait until data - * is transmitted, or clear a call and drop packets */ - - if (atomic_read(&sk->sk_wmem_alloc) || - check_driver_busy(sk)) { - mbox_cmd_t *mbox = wp->mbox; - if (mbox->cmd.qdm & 0x80){ - mbox->cmd.result = 0x35; - err = -EAGAIN; - break; - } - } - - sk->sk_state = WANSOCK_DISCONNECTING; - - err = execute_command(sk,X25_CLEAR_CALL,0); - if (err < 0) - break; - - err = -ECONNREFUSED; - if (sk->sk_state == WANSOCK_DISCONNECTED) { - DBG_PRINTK(KERN_INFO "\nwansock: CLEAR OK %i\n", - wp->lcn); - wp->lcn = 0; - err = 0; - } - break; - - case SIOC_WANPIPE_RESET_CALL: - - if (sk->sk_state != WANSOCK_CONNECTED) { - err = -EINVAL; - break; - } - - - /* Check if data buffers are pending for transmission, - * if so, check whether user wants to wait until data - * is transmitted, or reset a call and drop packets */ - - if (atomic_read(&sk->sk_wmem_alloc) || - check_driver_busy(sk)) { - mbox_cmd_t *mbox = wp->mbox; - if (mbox->cmd.qdm & 0x80){ - mbox->cmd.result = 0x35; - err = -EAGAIN; - break; - } - } - - - err = execute_command(sk, X25_RESET,0); - if (err < 0) - break; - - err = mbox_ptr->cmd.result; - break; - - - case X25_PLACE_CALL: - - err=execute_command(sk,X25_PLACE_CALL,flags); - if (err < 0) - break; - - if (sk->sk_state == WANSOCK_CONNECTED) { - - wp->lcn = ((mbox_cmd_t*)wp->mbox)->cmd.lcn; - - DBG_PRINTK(KERN_INFO "\nwansock: PLACE CALL OK %i\n", - wp->lcn); - err = 0; - - } else if (sk->sk_state == WANSOCK_CONNECTING && - (flags & O_NONBLOCK)) { - wp->lcn = ((mbox_cmd_t*)wp->mbox)->cmd.lcn; - DBG_PRINTK(KERN_INFO "\nwansock: Place Call OK: Waiting %i\n", - wp->lcn); - - err = 0; + if ((dev = (struct net_device *)SK_PRIV(sk)->dev) == NULL){ + printk(KERN_INFO "Sock user data is null\n"); + return -ENETUNREACH; + } - }else{ - DBG_PRINTK(KERN_INFO "\nwansock: Place call Failed\n"); - err = -ECONNREFUSED; - } + if (!dev->do_ioctl) + return -ENETUNREACH; - break; + sock->state = SS_CONNECTING; + sk->sk_state = WANSOCK_CONNECTING; - default: - return -EINVAL; + err=dev->do_ioctl(dev,NULL,SIOC_ANNEXG_PLACE_CALL); + if (err){ + sk->sk_state = WANSOCK_DISCONNECTED; + sock->state = SS_UNCONNECTED; + return err; } - return err; + return 0; } -static int check_driver_busy (struct sock *sk) +static int sk_buf_check (struct sock *sk, int len) { - struct net_device *dev = dev_get_by_index(sk->sk_bound_dev_if); - wanpipe_common_t *chan; - - if (!dev) - return 0; - - dev_put(dev); - - if ((chan=dev->priv) == NULL) - return 0; + if (!wansk_is_zapped(sk)) + return -EINVAL; + + if (atomic_read(&sk->sk_rmem_alloc) + len >= (unsigned)sk->sk_rcvbuf) + return -ENOMEM; - return atomic_read(&chan->driver_busy); + return 0; } - -/*====================================================================== - * wanpipe_accept - * - * ACCEPT() System call. X25API Specific function. - * For each incoming call, create a new socket and - * return it to the user. - *=====================================================================*/ - -static int wanpipe_accept(struct socket *sock, struct socket *newsock, int flags) +static int sk_poll_wake (struct sock *sk) { - struct sock *sk; - struct sock *newsk; - struct sk_buff *skb; - DECLARE_WAITQUEUE(wait, current); - int err=0; - - if (newsock->sk != NULL){ - wanpipe_kill_sock_accept(newsock->sk); - newsock->sk=NULL; - } - - if ((sk = sock->sk) == NULL) + if (!wansk_is_zapped(sk)) return -EINVAL; - if (sk->sk_type != SOCK_RAW) - return -EOPNOTSUPP; - - if (sk->sk_state != WANSOCK_LISTEN) - return -EINVAL; - - if (wp_sk(sk)->num != htons(X25_PROT)) - return -EINVAL; - - add_wait_queue(sk->sk_sleep,&wait); - current->state = TASK_INTERRUPTIBLE; - for (;;){ - skb = skb_dequeue(&sk->sk_receive_queue); - if (skb){ - err=0; - break; - } - if (signal_pending(current)) { - err = -ERESTARTSYS; - break; - } - schedule(); - } - current->state = TASK_RUNNING; - remove_wait_queue(sk->sk_sleep,&wait); - - if (err != 0) - return err; - - newsk = get_newsk_from_skb(skb); - if (!newsk){ - return -EINVAL; - } - - set_bit(1,&wanpipe_tx_critical); - write_lock(&wanpipe_sklist_lock); - sk_add_node(newsk, &wanpipe_sklist); - write_unlock(&wanpipe_sklist_lock); - clear_bit(1,&wanpipe_tx_critical); - - newsk->sk_socket = newsock; - newsk->sk_sleep = &newsock->wait; - - /* Now attach up the new socket */ - sk->sk_ack_backlog--; - newsock->sk = newsk; - - kfree_skb(skb); - - DBG_PRINTK(KERN_INFO "\nwansock: ACCEPT Got LCN %i\n", - wp_sk(newsk)->lcn); + sk->sk_data_ready(sk,0); return 0; } -/*====================================================================== - * get_newsk_from_skb - * - * Accept() uses this function to get the address of the new - * socket structure. - *=====================================================================*/ - -struct sock * get_newsk_from_skb (struct sk_buff *skb) -{ - struct net_device *dev = skb->dev; - wanpipe_common_t *chan; - if (!dev){ - return NULL; - } - - if ((chan = dev->priv) == NULL){ - return NULL; - } - - if (!chan->sk){ - return NULL; - } - return (struct sock *)chan->sk; -} - -/*====================================================================== - * wanpipe_connect - * - * CONNECT() System Call. X25API specific function - * Check the state of the sock, and execute PLACE_CALL command. - * Connect can ether block or return without waiting for connection, - * if specified by user. - *=====================================================================*/ +#if defined(LINUX_2_6) +struct proto_ops wanpipe_ops = { + .family =PF_WANPIPE, + .owner =THIS_MODULE, + .release =wanpipe_release, + .bind =wanpipe_bind, + .connect =wanpipe_connect, + .socketpair =sock_no_socketpair, + .accept =wanpipe_accept, + .getname =wanpipe_getname, + .poll =wanpipe_poll, + .ioctl =wanpipe_ioctl, + .listen =wanpipe_listen, + .shutdown =sock_no_shutdown, + .setsockopt =sock_no_setsockopt, + .getsockopt =sock_no_getsockopt, + .sendmsg =wanpipe_sendmsg, + .recvmsg =wanpipe_recvmsg +}; -static int wanpipe_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len, int flags) -{ - struct sock *sk = sock->sk; - struct wan_sockaddr_ll *addr = (struct wan_sockaddr_ll*)uaddr; - struct net_device *dev; - int err; +static struct net_proto_family wanpipe_family_ops = { + .family = PF_WANPIPE, + .create = wanpipe_create, + .owner = THIS_MODULE, +}; - if (wp_sk(sk)->num != htons(X25_PROT)) - return -EINVAL; +static struct notifier_block wanpipe_netdev_notifier = { + .notifier_call =wanpipe_notifier, +}; - if (sk->sk_state == WANSOCK_CONNECTED) - return -EISCONN; /* No reconnect on a seqpacket socket */ +#else - if (sk->sk_state != WAN_DISCONNECTED) { - printk(KERN_INFO "wansock: Trying to connect on channel NON DISCONNECT\n"); - return -ECONNREFUSED; - } - sk->sk_state = WANSOCK_DISCONNECTED; - sock->state = SS_UNCONNECTED; +struct proto_ops wanpipe_ops = { + family: PF_WANPIPE, + release: wanpipe_release, + bind: wanpipe_bind, + connect : wanpipe_connect, + socketpair : sock_no_socketpair, + accept : wanpipe_accept, + getname: wanpipe_getname, + poll : wanpipe_poll, + ioctl : wanpipe_ioctl, + listen : wanpipe_listen, + shutdown: sock_no_shutdown, + setsockopt: sock_no_setsockopt, + getsockopt: sock_no_getsockopt, + sendmsg: wanpipe_sendmsg, + recvmsg: wanpipe_recvmsg +}; - if (addr_len != sizeof(struct wan_sockaddr_ll)) - return -EINVAL; +static struct net_proto_family wanpipe_family_ops = { + PF_WANPIPE, + wanpipe_create +}; - if (addr->sll_family != AF_WANPIPE) - return -EINVAL; +struct notifier_block wanpipe_netdev_notifier={ + wanpipe_notifier, + NULL, + 0 +}; - if ((dev = dev_get_by_index(sk->sk_bound_dev_if)) == NULL) - return -ENETUNREACH; +#endif - dev_put(dev); - - if (!sock_flag(sk, SOCK_ZAPPED)) /* Must bind first - autobinding does not work */ - return -EINVAL; - sock->state = SS_CONNECTING; - sk->sk_state = WANSOCK_CONNECTING; - if (!wp_sk(sk)->mbox) { - if (wp_sk (sk)->svc) - return -EINVAL; - else { - int err; - if ((err=set_ioctl_cmd(sk,NULL)) < 0) - return err; - } - } +MODULE_AUTHOR ("Nenad Corbic "); +MODULE_DESCRIPTION ("Sangoma WANPIPE: API Socket Support"); +MODULE_LICENSE("GPL"); - if ((err=wanpipe_exec_cmd(sk, X25_PLACE_CALL,flags)) != 0){ - sock->state = SS_UNCONNECTED; - sk->sk_state = WANSOCK_CONNECTED; - return err; - } +void __exit af_wanpipe_exit(void) +{ + DEBUG_EVENT("af_wanpipe: Unregistering Wanpipe API Socket Module\n"); - if (sk->sk_state != WANSOCK_CONNECTED && (flags & O_NONBLOCK)) { - return 0; - } + unregister_wanpipe_api_socket(); - if (sk->sk_state != WANSOCK_CONNECTED) { - sock->state = SS_UNCONNECTED; - return -ECONNREFUSED; - } + unregister_netdevice_notifier(&wanpipe_netdev_notifier); + sock_unregister(PF_WANPIPE); - sock->state = SS_CONNECTED; - return 0; + return; } -const struct proto_ops wanpipe_ops = { - .family = PF_WANPIPE, - .owner = THIS_MODULE, - .release = wanpipe_release, - .bind = wanpipe_bind, - .connect = wanpipe_connect, - .socketpair = sock_no_socketpair, - .accept = wanpipe_accept, - .getname = wanpipe_getname, - .poll = wanpipe_poll, - .ioctl = wanpipe_ioctl, - .listen = wanpipe_listen, - .shutdown = sock_no_shutdown, - .setsockopt = sock_no_setsockopt, - .getsockopt = sock_no_getsockopt, - .sendmsg = wanpipe_sendmsg, - .recvmsg = wanpipe_recvmsg -}; - -static struct net_proto_family wanpipe_family_ops = { - .family = PF_WANPIPE, - .create = wanpipe_create, - .owner = THIS_MODULE, -}; - -struct notifier_block wanpipe_netdev_notifier = { - .notifier_call = wanpipe_notifier, -}; +static char fullname[] = "WANPIPE(tm) Socket API Module"; -#ifdef MODULE -void cleanup_module(void) +int __init af_wanpipe_init(void) { - printk(KERN_INFO "wansock: Cleaning up \n"); - unregister_netdevice_notifier(&wanpipe_netdev_notifier); - sock_unregister(PF_WANPIPE); - proto_unregister(&wanpipe_proto); -} - -int init_module(void) -{ - int rc; - - printk(KERN_INFO "wansock: Registering Socket \n"); + struct wanpipe_api_register_struct wan_api_reg; - rc = proto_register(&wanpipe_proto, 0); - if (rc != 0) - goto out; + if (WANPIPE_VERSION_BETA){ + DEBUG_EVENT("%s Beta%s-%s %s %s\n", + fullname, WANPIPE_SUB_VERSION, WANPIPE_VERSION, + WANPIPE_COPYRIGHT_DATES, WANPIPE_COMPANY); + }else{ + DEBUG_EVENT("%s Stable %s-%s %s %s\n", + fullname, WANPIPE_VERSION, WANPIPE_SUB_VERSION, + WANPIPE_COPYRIGHT_DATES, WANPIPE_COMPANY); + } + sock_register(&wanpipe_family_ops); register_netdevice_notifier(&wanpipe_netdev_notifier); -out: - return rc; + + wan_api_reg.wanpipe_api_sock_rcv = wanpipe_api_sock_rcv; + wan_api_reg.wanpipe_api_connected = wanpipe_api_connected; + wan_api_reg.wanpipe_api_disconnected = wanpipe_api_disconnected; + wan_api_reg.wanpipe_api_connecting = wanpipe_api_connecting; + wan_api_reg.wanpipe_listen_rcv = wanpipe_listen_rcv; + wan_api_reg.sk_buf_check = sk_buf_check; + wan_api_reg.sk_poll_wake = sk_poll_wake; + + return register_wanpipe_api_socket(&wan_api_reg); } -#endif -MODULE_LICENSE("GPL"); -MODULE_ALIAS_NETPROTO(PF_WANPIPE); + +module_init(af_wanpipe_init); +module_exit(af_wanpipe_exit); + diff -Nur linux.org/net/wanrouter/af_wanpipe_datascope.c linux-2.6.17/net/wanrouter/af_wanpipe_datascope.c --- linux.org/net/wanrouter/af_wanpipe_datascope.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/net/wanrouter/af_wanpipe_datascope.c 2006-08-30 10:07:16.000000000 +0000 @@ -0,0 +1,1813 @@ +/***************************************************************************** +* af_wanpipe_datascope.c +* +* WANPIPE(tm) Datascope Socket Layer. +* +* Author: Nenad Corbic +* +* Copyright: (c) 2003 Sangoma Technologies Inc. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version +* 2 of the License, or (at your option) any later version. +* ============================================================================ +*/ + +#include +#include +#include +#include +#include +#include + +/*=================================================================== + * + * DEFINES + * + *==================================================================*/ + +#define INC_CRC_CNT(a) if (++a >= MAX_SOCK_CRC_QUEUE) a=0; +#define GET_FIN_CRC_CNT(a) { if (--a < 0) a=MAX_SOCK_CRC_QUEUE-1; \ + if (--a < 0) a=MAX_SOCK_CRC_QUEUE-1; } + +#define FLIP_CRC(a,b) { b=0; \ + b |= (a&0x000F)<<12 ; \ + b |= (a&0x00F0) << 4; \ + b |= (a&0x0F00) >> 4; \ + b |= (a&0xF000) >> 12; } + +#define DECODE_CRC(a) { a=( (((~a)&0x000F)<<4) | \ + (((~a)&0x00F0)>>4) | \ + (((~a)&0x0F00)<<4) | \ + (((~a)&0xF000)>>4) ); } +#define BITSINBYTE 8 + +#define NO_FLAG 0 +#define OPEN_FLAG 1 +#define CLOSING_FLAG 2 + + +/*=================================================================== + * + * GLOBAL VARIABLES + * + *==================================================================*/ + +static const int MagicNums[8] = { 0x1189, 0x2312, 0x4624, 0x8C48, 0x1081, 0x2102, 0x4204, 0x8408 }; +static unsigned short CRC_TABLE[256]; +static unsigned long init_crc_g=0; +static const char FLAG[]={ 0x7E, 0xFC, 0xF9, 0xF3, 0xE7, 0xCF, 0x9F, 0x3F }; + + +/*=================================================================== + * + * FUNCTION PROTOTYPES + * + *==================================================================*/ + +#ifdef LINUX_2_6 +HLIST_HEAD(wanpipe_parent_sklist); +#else +struct sock * wanpipe_parent_sklist = NULL; +#endif +static rwlock_t wanpipe_parent_sklist_lock = RW_LOCK_UNLOCKED; + +static int wanpipe_check_prot_options(struct sock *sk); +void wanpipe_unbind_sk_from_parent(struct sock *sk); +static int wanpipe_attach_sk_to_parent (struct sock *parent_sk, struct sock *sk); +static int wanpipe_unattach_sk_from_parent (struct sock *parent_sk, struct sock *sk); +static wanpipe_hdlc_engine_t * + wanpipe_get_hdlc_engine (struct sock *parent_sk,unsigned long active_ch); +static void free_hdlc_engine(wanpipe_hdlc_engine_t *hdlc_eng); + +static int bind_sk_to_parent_prot(void **,unsigned char*,struct sock *sk); +static int unbind_sk_from_parent_prot(void **, unsigned char *,struct sock *sk); +static int bind_hdlc_into_timeslots(struct sock *parent_sk, + wanpipe_hdlc_engine_t *hdlc_eng); +static void unbind_hdlc_from_timeslots(struct sock *parent_sk, wanpipe_hdlc_engine_t *hdlc_eng); + +static int decode_byte (wanpipe_hdlc_engine_t *hdlc_eng, + wanpipe_hdlc_decoder_t *chan, + unsigned char *byte, + unsigned char txdir); +static void init_hdlc_decoder(wanpipe_hdlc_decoder_t *chan); + +static void init_crc(void); +static void calc_rx_crc(wanpipe_hdlc_decoder_t *chan); +static void tx_up_decode_pkt(wanpipe_hdlc_engine_t *,wanpipe_hdlc_decoder_t *,unsigned char); +static int wanpipe_hdlc_decode (wanpipe_hdlc_engine_t *hdlc_eng, unsigned char, struct sk_buff *skb); + +static int wanpipe_sk_ss7_monitor_rx(void**map, struct sk_buff **skb_ptr); +static int wanpipe_skb_timeslot_parse(struct sock *parent_sk, struct sk_buff *skb, unsigned char dir); +static int wanpipe_handle_hdlc_data(struct sock *parent_sk); +static int wanpipe_rx_prot_data(void **map, unsigned short protocol, struct sk_buff *skb); +//static void print_hdlc_list(wanpipe_hdlc_engine_t **list); +static void wanpipe_free_parent_sock(struct sock *sk); + +static void wanpipe_sk_parent_rx_bh (unsigned long data); + +extern struct sock *wanpipe_make_new(struct sock *); +extern atomic_t wanpipe_socks_nr; + + + + +/*============================================================ + * wanpipe_bind_sk_to_parent + * + *===========================================================*/ + +int wanpipe_bind_sk_to_parent(struct sock *sk, netdevice_t *dev, struct wan_sockaddr_ll *sll) +{ + int err=0; + struct sock *parent_sk; + unsigned long flags; + struct ifreq ifr; + void *buf; + + memset(&ifr,0,sizeof(struct ifreq)); + + if (sll->sll_protocol){ + SK_PRIV(sk)->num = sll->sll_protocol; + } + + buf = wan_malloc(sizeof(wanpipe_datascope_t)); + if (!buf){ + DEBUG_EVENT("%s: Wanpipe Socket failed to allocate datascope struct!\n", + dev->name); + return -ENOMEM; + } + + DATA_SC_INIT(sk,buf); + + memset(DATA_SC(sk),0,sizeof(wanpipe_datascope_t)); + + DATA_SC(sk)->prot_type = sll->sll_prot; + DATA_SC(sk)->active_ch = sll->sll_active_ch; + + /* Find the parent socket for this interface */ + parent_sk=NULL; + write_lock_irqsave(&wanpipe_parent_sklist_lock,flags); +#ifdef LINUX_2_6 + { + struct hlist_node *node; + sk_for_each(parent_sk, node, &wanpipe_parent_sklist) { + if (SK_PRIV((parent_sk))->dev == dev) { + break; + } + } + } +#else + { + struct sock **skp; + for (skp = &wanpipe_parent_sklist; *skp; skp = &(*skp)->next) { + if (SK_PRIV((*skp))->dev == dev) { + parent_sk=*skp; + break; + } + } + } +#endif + write_unlock_irqrestore(&wanpipe_parent_sklist_lock,flags); + + DEBUG_EVENT("%s: Dev name %s parensk=%p\n",__FUNCTION__,dev->name, parent_sk); + + if (parent_sk == NULL){ + + init_crc(); + + /* Device is not being used + * + * Create a parent socket that will be used + * to interface to network device */ + + parent_sk=wanpipe_make_new(sk); + if (!parent_sk){ + DEBUG_EVENT("wansock: Failed to allocate new ss7 monitor sock!\n"); + return -ENOMEM; + } + atomic_inc(&wanpipe_socks_nr); + + buf = wan_malloc(sizeof(wanpipe_datascope_t)); + if (!buf){ + DEBUG_EVENT("%s: Wanpipe Socket failed to allocate datascope struct!\n", + dev->name); + wanpipe_free_parent_sock(parent_sk); + return -ENOMEM; + } + + DATA_SC_INIT(parent_sk,buf); + memset(DATA_SC(parent_sk),0,sizeof(wanpipe_datascope_t)); + + buf=wan_malloc(sizeof(wanpipe_parent_t)); + if (!buf){ + DEBUG_EVENT("%s: Wanpipe Socket failed to allocate parent struct!\n", + dev->name); + wan_free(DATA_SC(parent_sk)); + wanpipe_free_parent_sock(parent_sk); + return -ENOMEM; + } + + PPRIV_INIT(parent_sk,buf); + memset(PPRIV(parent_sk),0,sizeof(wanpipe_parent_t)); + + PPRIV(parent_sk)->lock = RW_LOCK_UNLOCKED; + + SK_PRIV(parent_sk)->dev=dev; + + tasklet_init((&PPRIV(parent_sk)->rx_task), + wanpipe_sk_parent_rx_bh, (unsigned long)parent_sk); + skb_queue_head_init(&PPRIV(parent_sk)->rx_queue); + + wansk_reset_zapped(parent_sk); + DATA_SC(parent_sk)->parent=1; + + if (DATA_SC(sk)->active_ch){ + PPRIV(parent_sk)->hdlc_enabled=1; + } + + /* Bind the parent socket to network device */ + + ifr.ifr_data = (void*)parent_sk; + err=-EINVAL; + if (dev->do_ioctl) + err=dev->do_ioctl(dev,&ifr,SIOC_WANPIPE_BIND_SK); + + if (err != 0){ + DEBUG_EVENT("%s: Error: Dev busy with another protocol!\n", + dev->name); + wanpipe_free_parent_sock(parent_sk); + return err; + } + + + DEBUG_EVENT("%s: Parent sock registered to dev %s\n", + dev->name,dev->name); + + PPRIV(parent_sk)->time_slots = 24; + PPRIV(parent_sk)->media = WAN_MEDIA_T1; + PPRIV(parent_sk)->seven_bit_hdlc = sll->sll_seven_bit_hdlc; + + DEBUG_EVENT("%s: Parent hdlc engine %s Bits %d\n", + dev->name, + PPRIV(parent_sk)->hdlc_enabled? + "Enabled":"Disabled", + PPRIV(parent_sk)->seven_bit_hdlc?7:8); + + PPRIV(parent_sk)->time_slots = + dev->do_ioctl(dev,NULL,SIOC_WANPIPE_GET_TIME_SLOTS); + if (PPRIV(parent_sk)->time_slots < 0){ + DEBUG_EVENT("%s: Error, failed to obtain time slots from driver!\n", + dev->name); + wanpipe_free_parent_sock(parent_sk); + return -EINVAL; + } + + PPRIV(parent_sk)->media = + dev->do_ioctl(dev,NULL,SIOC_WANPIPE_GET_MEDIA_TYPE); + if (PPRIV(parent_sk)->media < 0){ + DEBUG_EVENT("%s: Error, failed to obtain media type from driver!\n", + dev->name); + wanpipe_free_parent_sock(parent_sk); + return -EINVAL; + } + + if (PPRIV(parent_sk)->media==WAN_MEDIA_NONE){ + PPRIV(parent_sk)->time_slots=0; + PPRIV(parent_sk)->hdlc_enabled=1; + DEBUG_EVENT("%s: Parent connected to Serial Device!\n", + dev->name); + }else{ + DEBUG_EVENT("%s: Parent connected to %s Timeslots=%i!\n", + dev->name, + PPRIV(parent_sk)->media==WAN_MEDIA_T1?"T1":"E1", + PPRIV(parent_sk)->time_slots); + } + + DEBUG_EVENT("%s: Parent hdlc engine %s Bits %d\n", + dev->name, + PPRIV(parent_sk)->hdlc_enabled? + "Enabled":"Disabled", + PPRIV(parent_sk)->seven_bit_hdlc?7:8); + + /* Insert parent socket into global parent socket list */ + write_lock_irqsave(&wanpipe_parent_sklist_lock,flags); +#ifdef LINUX_2_6 + sk_add_node(parent_sk,&wanpipe_parent_sklist); +#else + parent_sk->next = wanpipe_parent_sklist; + wanpipe_parent_sklist = parent_sk; + wp_sock_hold(parent_sk); +#endif + write_unlock_irqrestore(&wanpipe_parent_sklist_lock,flags); + + err=dev->do_ioctl(dev,&ifr,SIOC_WANPIPE_DEV_STATE); + if (err == WANSOCK_CONNECTED){ + parent_sk->sk_state = WANSOCK_CONNECTED; + }else{ + parent_sk->sk_state = WANSOCK_DISCONNECTED; + } + + parent_sk->sk_bound_dev_if = dev->ifindex; + SK_PRIV(parent_sk)->dev = dev; + wansk_set_zapped(parent_sk); + + }else{ + if (SK_PRIV(parent_sk)->num != SK_PRIV(sk)->num){ + DEBUG_EVENT("%s: Error parent prot 0x%X doesn't match sk prot 0x%X!\n", + dev->name,SK_PRIV(parent_sk)->num,SK_PRIV(sk)->num); + return -EFAULT; + } + } + + /* Initialize the sk parameters */ + DATA_SC(sk)->parent_sk=parent_sk; + wp_sock_hold(parent_sk); + + if (PPRIV(parent_sk)->hdlc_enabled){ + + if (PPRIV(parent_sk)->media != WAN_MEDIA_NONE && !DATA_SC(sk)->active_ch){ + DEBUG_EVENT("%s: Error invalid sk active ch selection: 0x%X!\n", + dev->name,DATA_SC(sk)->active_ch); + DEBUG_EVENT("%s: Parent hdlc engine enabled!\n", + dev->name); + wanpipe_unbind_sk_from_parent(sk); + return -EINVAL; + } + if (PPRIV(parent_sk)->media == WAN_MEDIA_NONE){ + DATA_SC(sk)->active_ch=0; + } + } + + if (!PPRIV(parent_sk)->hdlc_enabled && DATA_SC(sk)->active_ch){ + DEBUG_EVENT("%s: Error invalid sk active ch selection: 0x%X!\n", + dev->name,DATA_SC(sk)->active_ch); + DEBUG_EVENT("%s: Parent hdlc engine disabled!\n", + dev->name); + wanpipe_unbind_sk_from_parent(sk); + return -EINVAL; + } + + + DATA_SC(sk)->delta= sll->sll_prot_opt & DELTA_PROT_OPT; + if (DATA_SC(sk)->delta){ + DEBUG_EVENT("%s: Datascope enabling DELTA parsing\n",dev->name); + } + + if (sll->sll_prot_opt & MULTI_PROT_OPT){ + DATA_SC(sk)->max_mult_cnt=sll->sll_mult_cnt; + DEBUG_EVENT("%s: Datascope enabling MULTI parsing: Max mult cnt = %i\n", + dev->name,DATA_SC(sk)->max_mult_cnt); + } + + if (wanpipe_check_prot_options(sk) != 0){ + DEBUG_EVENT("%s: Error invalid sk protocol specified: 0x%lX!\n", + dev->name,DATA_SC(sk)->prot_type); + wanpipe_unbind_sk_from_parent(sk); + return -EINVAL; + } + + + err=wanpipe_attach_sk_to_parent(parent_sk,sk); + if (err!=0){ + wanpipe_unbind_sk_from_parent(sk); + return err; + } + + SK_PRIV(sk)->dev=dev; + sk->sk_bound_dev_if = dev->ifindex; + sk->sk_state = parent_sk->sk_state; + wansk_set_zapped(sk); + + return 0; +} + +/*============================================================ + * wanpipe_unbind_sk_from_parent + * + *===========================================================*/ + +void wanpipe_unbind_sk_from_parent(struct sock *sk) +{ + + struct sock *parent_sk; + unsigned long flags; + int sk_child_exists=0; + + if (!DATA_SC(sk)){ + return; + } + + parent_sk=DATA_SC(sk)->parent_sk; + if (!parent_sk){ + wan_free(DATA_SC(sk)); + DATA_SC_INIT(sk,NULL); + return; + } + + sk_child_exists = wanpipe_unattach_sk_from_parent(parent_sk,sk); + + /* If this is the last socket in the parents list + * remove the parent as well */ + if (!sk_child_exists){ + +#ifdef LINUX_2_6 + sock_set_flag(parent_sk, SOCK_DEAD); +#else + set_bit(0,&parent_sk->dead); +#endif + tasklet_kill(&PPRIV(parent_sk)->rx_task); + skb_queue_purge(&PPRIV(parent_sk)->rx_queue); + + DEBUG_EVENT("%s: Parent sock unregistered from dev %s\n", + SK_PRIV(parent_sk)->dev->name, + SK_PRIV(parent_sk)->dev->name); + + /* Remove parent from the global parent list */ + write_lock_irqsave(&wanpipe_parent_sklist_lock,flags); +#ifdef LINUX_2_6 + sk_del_node_init(parent_sk); +#else + { + struct sock **skp; + for (skp = &wanpipe_parent_sklist; *skp; skp = &(*skp)->next) { + if (*skp == parent_sk) { + *skp = parent_sk->next; + wp_sock_put(parent_sk); + break; + } + } + } +#endif + wanpipe_free_parent_sock(parent_sk); + parent_sk=NULL; + + write_unlock_irqrestore(&wanpipe_parent_sklist_lock,flags); + + } + + wansk_reset_zapped(sk); + wan_free(DATA_SC(sk)); + DATA_SC_INIT(sk,NULL); + + return; +} + + +void wanpipe_wakup_sk_attached_to_parent(struct sock *parent_sk) +{ + struct sock *sk; + int i; + + if (!DATA_SC(parent_sk) || !DATA_SC(parent_sk)->parent){ + return; + } + + for (i=0;isk_to_prot_map[i]) != NULL){ + sk->sk_state = parent_sk->sk_state; + sk->sk_data_ready(sk,0); + } + } +} + +static void wanpipe_sk_parent_rx_bh (unsigned long data) +{ + struct sock *parent_sk = (struct sock *)data; + struct sk_buff *skb; + unsigned char txdir=0; + int err; + +#ifdef LINUX_2_6 + if (sock_flag(parent_sk, SOCK_DEAD)){ +#else + if (test_bit(0,&parent_sk->dead)){ +#endif + return; + } + + read_lock(&PPRIV(parent_sk)->lock); + + while ((skb=skb_dequeue(&PPRIV(parent_sk)->rx_queue))){ +#ifdef LINUX_2_6 + if (sock_flag(parent_sk, SOCK_DEAD)){ +#else + if (test_bit(0,&parent_sk->dead)){ +#endif + read_unlock(&PPRIV(parent_sk)->lock); + return; + } + + /* Protocol specific here */ + if (PPRIV(parent_sk)->hdlc_enabled){ + + wp_sock_rx_hdr_t *hdr=(wp_sock_rx_hdr_t *)skb->data; + txdir=hdr->direction; + + skb_pull(skb,sizeof(wp_sock_rx_hdr_t)); + + if (wanpipe_skb_timeslot_parse(parent_sk,skb,txdir)){ + /* There is data to be passed up + * check all hdlc engines */ + wanpipe_handle_hdlc_data(parent_sk); + } + wan_skb_free(skb); + err = 0; + }else{ + err = wanpipe_rx_prot_data(PPRIV(parent_sk)->sk_to_prot_map, + SK_PRIV(parent_sk)->num, + skb); + } + } + + read_unlock(&PPRIV(parent_sk)->lock); + + return; +} + + +int wanpipe_sk_parent_rx(struct sock *parent_sk, struct sk_buff *skb) +{ + unsigned char txdir=0; + int err; + + if (skb->len <= WANPIPE_HEADER_SZ){ + wan_skb_free(skb); + return 0; + } + + if (!PPRIV(parent_sk)){ + wan_skb_free(skb); + return 0; + } + +#ifdef LINUX_2_6 + if (sock_flag(parent_sk, SOCK_DEAD)){ +#else + if (test_bit(0,&parent_sk->dead)){ +#endif + wan_skb_free(skb); + return 0; + } + + skb_queue_tail(&PPRIV(parent_sk)->rx_queue,skb); + tasklet_hi_schedule(&PPRIV(parent_sk)->rx_task); + + return 0; + + read_lock(&PPRIV(parent_sk)->lock); + + /* Protocol specific here */ + if (PPRIV(parent_sk)->hdlc_enabled){ + + wp_sock_rx_hdr_t *hdr=(wp_sock_rx_hdr_t *)skb->data; + txdir=hdr->direction; + + skb_pull(skb,sizeof(wp_sock_rx_hdr_t)); + + if (wanpipe_skb_timeslot_parse(parent_sk,skb,txdir)){ + /* There is data to be passed up + * check all hdlc engines */ + wanpipe_handle_hdlc_data(parent_sk); + } + wan_skb_free(skb); + err = 0; + }else{ + err = wanpipe_rx_prot_data(PPRIV(parent_sk)->sk_to_prot_map, + SK_PRIV(parent_sk)->num, + skb); + } + + read_unlock(&PPRIV(parent_sk)->lock); + + return err; +} + + +static int wanpipe_rx_prot_data(void **map, unsigned short protocol, struct sk_buff *skb) +{ + int sk_id=MAX_PARENT_PROT_NUM; + struct sock *sk; + int err; + + /* Protocol specific here */ + + if (protocol == htons(SS7_MONITOR_PROT)){ + sk_id=wanpipe_sk_ss7_monitor_rx(map,&skb); + }else{ + if (net_ratelimit()){ + DEBUG_EVENT("%s: Invalid sk prot configuration 0x%X\n",__FUNCTION__, + protocol); + } + wan_skb_free(skb); + return 0; + } + + if (sk_id < 0){ + /* The packet was intentionaly dropped by + * the protocol layer. The packet was + * handled by the protocol layer thus, + * no deallocation is needed */ + return 0; + } + + if (sk_id >= MAX_PARENT_PROT_NUM){ + if (net_ratelimit()){ + DEBUG_EVENT("%s: Invalid skb pkt len %i id=%i\n", + __FUNCTION__, + skb->len,sk_id); + } + wan_skb_free(skb); + return 0; + } + + if ((sk=map[sk_id]) == NULL){ + if (net_ratelimit()){ + DEBUG_EVENT("%s: No sk for prot %s\n", + __FUNCTION__, + DECODE_SS7_PROT(sk_id+1)); + } + wan_skb_free(skb); + return 0; + } + + if ((err=sock_queue_rcv_skb(sk,skb))<0){ + sk->sk_data_ready(sk,0); + if (net_ratelimit()){ + DEBUG_EVENT("%s: Sock failed to rx on prot %s: sock full: err %i truesize %i sktotal %i skblen %i!\n", + __FUNCTION__, + DECODE_SS7_PROT(DATA_SC(sk)->prot_type), + err,skb->truesize, + sk->sk_rcvbuf, + skb->len); + } + + //FIXME: skb ptr can be mangled at this poing + // we should never get here + kfree(skb); + return 0; + } + + return 0; +} + +static int wanpipe_handle_hdlc_data(struct sock *parent_sk) +{ + wanpipe_hdlc_engine_t *hdlc_eng; + struct sk_buff *skb; + + for (hdlc_eng = PPRIV(parent_sk)->hdlc_eng_list; + hdlc_eng; + hdlc_eng=hdlc_eng->next){ + while ((skb=wan_skb_dequeue(&hdlc_eng->data_q)) != NULL){ + wanpipe_rx_prot_data(hdlc_eng->sk_to_prot_map, + SK_PRIV(parent_sk)->num, + skb); + } + } + + return 0; +} + +/******************************************************************* + * + * PRIVATE FUNCTIONS + * + *******************************************************************/ + + +static inline unsigned short wanpipe_skb_get_checksum(struct sk_buff *skb) +{ + return *((unsigned short*)&skb->data[skb->len-2]); +} + +static int wanpipe_skb_mult_check(struct sk_buff **orig_skb, + unsigned short *orig_csum, + struct sk_buff **up_skb, + unsigned short max_mult_cnt) +{ + unsigned short csum; + struct sk_buff *cur_skb=*orig_skb; + struct sk_buff *skb=*up_skb; + unsigned short *cur_skb_cnt,*skb_cnt; + + csum=wanpipe_skb_get_checksum(skb); + skb_cnt=(unsigned short*)&skb->data[0]; + + if (cur_skb == NULL){ + /* This is the first incoming packet for this + * protocol */ + *orig_skb = skb; + *orig_csum = csum; + *skb_cnt=1; + + return -1; + + } + + cur_skb_cnt=(unsigned short*)&cur_skb->data[0]; + + if (csum == *orig_csum){ + /* Same as already stored packet, + * increment the packet count */ + + if (++(*cur_skb_cnt) >= max_mult_cnt){ + /* We have reached the maximum number of + * multiple packets, send the packet up + * the stack */ + + DEBUG_EVENT("REACHED MAX MULT COUNT %i\n", + max_mult_cnt); + + *skb_cnt = *cur_skb_cnt; + + kfree_skb(cur_skb); + *orig_skb=NULL; + *orig_csum=0; + + }else{ + /* We incremented the count thus drop + * the packet */ + return 1; + } + }else{ + /* Different packet recevied, we must pass previous + * packet up the stack and store current one */ + *up_skb = cur_skb; + + DEBUG_EVENT("GOT DIFF PKT sending with cnt %i\n", + *cur_skb_cnt); + + /* Store the incoming packet and incremnet its + * rx count */ + *orig_skb=skb; + *orig_csum=csum; + *skb_cnt=1; + } + + return 0; +} + + + +static int wanpipe_sk_ss7_monitor_rx(void **map, struct sk_buff **skb_ptr) +{ + struct sk_buff *skb=*skb_ptr; + int len=skb->len-WANPIPE_HEADER_SZ; + + wp_sock_rx_hdr_t *hdr=(wp_sock_rx_hdr_t *)skb->data; + int txdir=hdr->direction; + + unsigned short csum; + struct sock *sk; + int err; + + if ((sk=map[HDLC_BIT_MAP]) != NULL){ + return HDLC_BIT_MAP; + } + + if (len == SS7_FISU_LEN){ + + if ((sk=map[SS7_FISU_BIT_MAP]) == NULL){ + goto ss7_drop_pkt; + } + + if (DATA_SC(sk)->delta){ + + csum=wanpipe_skb_get_checksum(skb); + if (txdir){ + if (csum == DATA_SC(sk)->u.ss7.tx_fisu_skb_csum){ + goto ss7_drop_pkt; + } + DATA_SC(sk)->u.ss7.tx_fisu_skb_csum=csum; + }else{ + if (csum == DATA_SC(sk)->u.ss7.rx_fisu_skb_csum){ + goto ss7_drop_pkt; + } + DATA_SC(sk)->u.ss7.rx_fisu_skb_csum=csum; + } + + }else if (DATA_SC(sk)->max_mult_cnt){ + + if (txdir){ + err=wanpipe_skb_mult_check((struct sk_buff **)&DATA_SC(sk)->u.ss7.tx_fisu_skb, + &DATA_SC(sk)->u.ss7.tx_fisu_skb_csum, + skb_ptr, + DATA_SC(sk)->max_mult_cnt); + + }else{ + err=wanpipe_skb_mult_check((struct sk_buff **)&DATA_SC(sk)->u.ss7.rx_fisu_skb, + &DATA_SC(sk)->u.ss7.rx_fisu_skb_csum, + skb_ptr, + DATA_SC(sk)->max_mult_cnt); + } + + if (err < 0){ + goto ss7_skip_pkt; + }else if ( err > 0){ + goto ss7_drop_pkt; + } + } + + return (SS7_FISU_BIT_MAP); + + + }else if (len > SS7_FISU_LEN && len < SS7_MSU_LEN){ + + if ((sk=map[SS7_LSSU_BIT_MAP]) == NULL){ + goto ss7_drop_pkt; + } + + if (DATA_SC(sk)->delta){ + + csum=wanpipe_skb_get_checksum(skb); + if (txdir){ + if (csum == DATA_SC(sk)->u.ss7.tx_lssu_skb_csum){ + goto ss7_drop_pkt; + } + + DATA_SC(sk)->u.ss7.tx_lssu_skb_csum=csum; + + }else{ + if (csum == DATA_SC(sk)->u.ss7.rx_lssu_skb_csum){ + goto ss7_drop_pkt; + } + + DATA_SC(sk)->u.ss7.rx_lssu_skb_csum=csum; + } + + }else if (DATA_SC(sk)->max_mult_cnt){ + + if (txdir){ + err=wanpipe_skb_mult_check((struct sk_buff **)&DATA_SC(sk)->u.ss7.tx_lssu_skb, + &DATA_SC(sk)->u.ss7.tx_lssu_skb_csum, + skb_ptr, + DATA_SC(sk)->max_mult_cnt); + }else{ + err=wanpipe_skb_mult_check((struct sk_buff **)&DATA_SC(sk)->u.ss7.rx_lssu_skb, + &DATA_SC(sk)->u.ss7.rx_lssu_skb_csum, + skb_ptr, + DATA_SC(sk)->max_mult_cnt); + } + + if (err < 0){ + goto ss7_skip_pkt; + }else if ( err > 0){ + goto ss7_drop_pkt; + } + } + + return (SS7_LSSU_BIT_MAP); + + }else if (len >= SS7_MSU_LEN && len <= SS7_MSU_END_LEN){ + + if ((sk=map[SS7_MSU_BIT_MAP]) == NULL){ + goto ss7_drop_pkt; + } + + return (SS7_MSU_BIT_MAP); + } + +#if 1 + if (net_ratelimit()){ + DEBUG_EVENT("%s: Error: Illegal ss7 frame len %i\n", + __FUNCTION__,len); + } +#endif + + /* Invalid protocol or ss7 packet */ + return MAX_PARENT_PROT_NUM; + +ss7_drop_pkt: + kfree_skb(skb); + *skb_ptr=NULL; + +ss7_skip_pkt: + return -1; +} + + + + +static int wanpipe_check_prot_options(struct sock *sk) +{ + if (SK_PRIV(sk)->num == htons(SS7_MONITOR_PROT)){ + + if ((DATA_SC(sk)->prot_type & (1<prot_type & SS7_ALL_PROT) == 0){ + return -EINVAL; + } + return 0; + } + + return -EINVAL; +} + +static int wanpipe_attach_sk_to_parent (struct sock *parent_sk, struct sock *sk) +{ + unsigned long flags; + + if (PPRIV(parent_sk)->hdlc_enabled){ + + wanpipe_hdlc_engine_t *hdlc_eng; + + hdlc_eng = wanpipe_get_hdlc_engine(parent_sk,DATA_SC(sk)->active_ch); + if (!hdlc_eng){ + return -ENOMEM; + } + + DEBUG_INIT("%s: (DEBUG) GOT HDLC ENGINE %p Bound = %d\n", + SK_PRIV(parent_sk)->dev->name,hdlc_eng,hdlc_eng->bound); + + write_lock_irqsave(&PPRIV(parent_sk)->lock,flags); + + if (bind_sk_to_parent_prot(hdlc_eng->sk_to_prot_map, + SK_PRIV(parent_sk)->dev->name,sk) != 0){ + write_unlock_irqrestore(&PPRIV(parent_sk)->lock,flags); + if (!hdlc_eng->bound){ + free_hdlc_engine(hdlc_eng); + } + return -EEXIST; + } + + /* Insert the HDLC engine in parent hdlc + * engine list */ + if (!hdlc_eng->bound){ + int err; + + DEBUG_INIT("%s: (DEBUG) BOUND HDLC ENGINE %p to Parent\n", + SK_PRIV(parent_sk)->dev->name,hdlc_eng); + + hdlc_eng->next = PPRIV(parent_sk)->hdlc_eng_list; + PPRIV(parent_sk)->hdlc_eng_list = hdlc_eng; + wp_dev_hold(hdlc_eng); + + err=bind_hdlc_into_timeslots(parent_sk,hdlc_eng); + if (err!=0){ + unbind_hdlc_from_timeslots(parent_sk,hdlc_eng); + unbind_sk_from_parent_prot(hdlc_eng->sk_to_prot_map, + SK_PRIV(parent_sk)->dev->name, + sk); + write_unlock_irqrestore(&PPRIV(parent_sk)->lock,flags); + free_hdlc_engine(hdlc_eng); + return -ENOMEM; + } + + hdlc_eng->bound=1; + } + + DATA_SC(sk)->hdlc_eng = hdlc_eng; + wp_dev_hold(hdlc_eng); + + write_unlock_irqrestore(&PPRIV(parent_sk)->lock,flags); + + }else{ + + write_lock_irqsave(&PPRIV(parent_sk)->lock,flags); + + if (bind_sk_to_parent_prot(PPRIV(parent_sk)->sk_to_prot_map, + SK_PRIV(parent_sk)->dev->name,sk) != 0){ + write_unlock_irqrestore(&PPRIV(parent_sk)->lock,flags); + return -EEXIST; + } + + write_unlock_irqrestore(&PPRIV(parent_sk)->lock,flags); + } + + return 0; +} + + + +int wanpipe_unattach_sk_from_parent (struct sock *parent_sk, struct sock *sk) +{ + unsigned long flags; + int sk_child_exists=0; + + /* Unbind sk from parents list */ + write_lock_irqsave(&PPRIV(parent_sk)->lock,flags); + + if (PPRIV(parent_sk)->hdlc_enabled){ + + wanpipe_hdlc_engine_t *hdlc_eng = DATA_SC(sk)->hdlc_eng; + if (hdlc_eng){ + sk_child_exists = + unbind_sk_from_parent_prot(hdlc_eng->sk_to_prot_map, + SK_PRIV(parent_sk)->dev->name, + sk); + if (!sk_child_exists){ + unbind_hdlc_from_timeslots(parent_sk,DATA_SC(sk)->hdlc_eng); + + hdlc_eng->bound=0; + wp_dev_put(hdlc_eng); + DATA_SC(sk)->hdlc_eng=NULL; + + free_hdlc_engine(hdlc_eng); + + }else{ + wp_dev_put(DATA_SC(sk)->hdlc_eng); + DATA_SC(sk)->hdlc_eng=NULL; + } + } + + sk_child_exists = (PPRIV(parent_sk)->hdlc_eng_list == NULL) ? 0:1; + + }else{ + sk_child_exists = + unbind_sk_from_parent_prot(PPRIV(parent_sk)->sk_to_prot_map, + SK_PRIV(parent_sk)->dev->name, + sk); + } + + wp_sock_put(DATA_SC(sk)->parent_sk); + DATA_SC(sk)->parent_sk=NULL; + + write_unlock_irqrestore(&PPRIV(parent_sk)->lock,flags); + + return sk_child_exists; +} + + +/************************************************************** + * + * HDLC ENGINE + * + **************************************************************/ + +static int wanpipe_skb_timeslot_parse(struct sock *parent_sk, + struct sk_buff *skb, + unsigned char txdir) +{ + wanpipe_hdlc_engine_t *chan; + wanpipe_hdlc_list_t *list_el; + unsigned int ch=0,stream_full=0; + unsigned char *buf; + int len=skb->len; + +// read_lock(&PPRIV(parent_sk)->lock); + + if (PPRIV(parent_sk)->media == WAN_MEDIA_NONE){ + list_el=PPRIV(parent_sk)->time_slot_hdlc_map[0]; + if (list_el){ + chan=list_el->hdlc; + + if (!chan->skb_decode_size){ + + chan->skb_decode_size=len; + + if (chan->skb_decode_size > MAX_SOCK_HDLC_LIMIT){ + chan->skb_decode_size=MAX_SOCK_HDLC_LIMIT; + } + + DEBUG_EVENT("%s: Autocfg serial hdlc tx up size to %d\n", + SK_PRIV(parent_sk)->dev->name, + chan->skb_decode_size); + } + + if (wanpipe_hdlc_decode(chan,txdir,skb)){ + stream_full=1; + } + return stream_full; + } + } + + for (;;){ + + for (list_el=PPRIV(parent_sk)->time_slot_hdlc_map[ch]; + list_el; + list_el = list_el->next){ + + chan=list_el->hdlc; + + if (!chan->skb_decode_size){ + + chan->skb_decode_size=len; + + if (chan->skb_decode_size > MAX_SOCK_HDLC_LIMIT){ + chan->skb_decode_size=MAX_SOCK_HDLC_LIMIT; + } + + if (chan->skb_decode_size % chan->timeslots){ + chan->skb_decode_size-= + chan->skb_decode_size % + chan->timeslots; + chan->skb_decode_size+=chan->timeslots; + } + + DEBUG_EVENT("%s: Autocfg hdlc tx up size to %d\n", + SK_PRIV(parent_sk)->dev->name, + chan->skb_decode_size); + } + + + if (txdir){ + + if (chan->raw_tx_skb){ + buf=skb_put(chan->raw_tx_skb,1); + buf[0]=skb->data[0]; + + if (chan->raw_tx_skb->len >= chan->skb_decode_size){ + if (wanpipe_hdlc_decode(chan,txdir,chan->raw_tx_skb)){ + stream_full=1; + } + wan_skb_init(chan->raw_tx_skb,16); + wan_skb_trim(chan->raw_tx_skb,0); + } + + }else{ + DEBUG_EVENT("%s:%s: Critical Error no hdlc raw_tx_skb ptr!\n", + SK_PRIV(parent_sk)->dev->name, + __FUNCTION__); + } + }else{ + if (chan->raw_rx_skb){ + buf=skb_put(chan->raw_rx_skb,1); + buf[0]=skb->data[0]; + + if (chan->raw_rx_skb->len >= chan->skb_decode_size){ + if (wanpipe_hdlc_decode(chan,txdir,chan->raw_rx_skb)){ + stream_full=1; + } + wan_skb_init(chan->raw_rx_skb,16); + wan_skb_trim(chan->raw_rx_skb,0); + } + + }else{ + DEBUG_EVENT("%s:%s: Critical Error no hdlc raw_rx_skb ptr!\n", + SK_PRIV(parent_sk)->dev->name, + __FUNCTION__); + } + } + } + skb_pull(skb,1); + + if (skb->len < 1){ + break; + } + + if (++ch >= PPRIV(parent_sk)->time_slots){ + ch=0; + } + + }//for(;;) + +// read_unlock(&PPRIV(parent_sk)->lock); + + return stream_full; +} + +/* HDLC Bitstream Decode Functions */ +static int wanpipe_hdlc_decode (wanpipe_hdlc_engine_t *hdlc_eng, unsigned char txdir, struct sk_buff *skb) +{ + int i; + int word_len; + int found=0; + unsigned char *buf; + int len; + int gotdata=0; + + buf = skb->data; + len = skb->len; + + word_len=len-(len%4); + /* Before decoding the packet, make sure that the current + * bit stream contains data. Decoding is very expensive, + * thus perform word (32bit) comparision test */ + + for (i=0;itx_decoder; + }else{ + hdlc_decoder = &hdlc_eng->rx_decoder; + } + + for (i=0; irx_decode_len >= MAX_SOCK_HDLC_LIMIT){ + DEBUG_EVENT ("ERROR Rx decode len > max\n"); + init_hdlc_decoder(hdlc_decoder); + } + } + + return gotdata; +} + +static int decode_byte (wanpipe_hdlc_engine_t *hdlc_eng, + wanpipe_hdlc_decoder_t *chan, + unsigned char *byte_ptr, + unsigned char txdir) +{ + int i; + int gotdata=0; + unsigned long byte=*byte_ptr; + + /* Test each bit in an incoming bitstream byte. Search + * for an hdlc flag 0x7E, six 1s in a row. Once the + * flag is obtained, construct the data packets. + * The complete data packets are sent up the API stack */ + + for (i=0; iseven_bit_hdlc && i == 7){ + continue; + } + + if (test_bit(i,&byte)){ + /* Got a 1 */ + + ++chan->rx_decode_onecnt; + + /* Make sure that we received a valid flag, + * before we start decoding incoming data */ + if (!test_bit(NO_FLAG,&chan->hdlc_flag)){ + chan->rx_decode_buf[chan->rx_decode_len] |= (1 << chan->rx_decode_bit_cnt); + + if (++chan->rx_decode_bit_cnt >= BITSINBYTE){ + + /* Completed a byte of data, update the + * crc count, and start on the next + * byte. */ + calc_rx_crc(chan); +#ifdef PRINT_PKT + printk(" %02X", data); +#endif + ++chan->rx_decode_len; + if (chan->rx_decode_len > MAX_SOCK_HDLC_BUF){ + init_hdlc_decoder(&hdlc_eng->tx_decoder); + }else{ + chan->rx_decode_buf[chan->rx_decode_len]=0; + chan->rx_decode_bit_cnt=0; + chan->hdlc_flag=0; + set_bit(CLOSING_FLAG,&chan->hdlc_flag); + } + } + } + }else{ + /* Got a zero */ + if (chan->rx_decode_onecnt == 5){ + + /* bit stuffed zero detected, + * do not increment our decode_bit_count. + * thus, ignore this bit*/ + + + }else if (chan->rx_decode_onecnt == 6){ + + /* Got a Flag */ + if (test_bit(CLOSING_FLAG,&chan->hdlc_flag)){ + + /* Got a closing flag, thus asemble + * the packet and send it up the + * stack */ + chan->hdlc_flag=0; + set_bit(OPEN_FLAG,&chan->hdlc_flag); + + if (chan->rx_decode_len >= 3){ + + GET_FIN_CRC_CNT(chan->crc_cur); + FLIP_CRC(chan->rx_crc[chan->crc_cur],chan->crc_fin); + DECODE_CRC(chan->crc_fin); + + /* Check CRC error before passing data up + * the API socket */ + if (chan->crc_fin==chan->rx_orig_crc){ + tx_up_decode_pkt(hdlc_eng,chan,txdir); + gotdata=1; + }else{ + //++chan->ifstats.rx_crc_errors; + //CRC Error; initialize hdlc eng + init_hdlc_decoder(&hdlc_eng->tx_decoder); + } + }else{ + //Abort + //++chan->ifstats.rx_frame_errors; + } + + }else if (test_bit(NO_FLAG,&chan->hdlc_flag)){ + /* Got a very first flag */ + chan->hdlc_flag=0; + set_bit(OPEN_FLAG,&chan->hdlc_flag); + } + + /* After a flag, initialize the decode and + * crc buffers and get ready for the next + * data packet */ + chan->rx_decode_len=0; + chan->rx_decode_buf[chan->rx_decode_len]=0; + chan->rx_decode_bit_cnt=0; + chan->rx_crc[0]=-1; + chan->rx_crc[1]=-1; + chan->rx_crc[2]=-1; + chan->crc_cur=0; + chan->crc_prv=0; + }else{ + /* Got a valid zero, thus increment the + * rx_decode_bit_cnt, as a result of which + * a zero is left in the consturcted + * byte. NOTE: we must have a valid flag */ + + if (!test_bit(NO_FLAG,&chan->hdlc_flag)){ + if (++chan->rx_decode_bit_cnt >= BITSINBYTE){ + calc_rx_crc(chan); +#ifdef PRINT_PKT + printk(" %02X", data); +#endif + ++chan->rx_decode_len; + if (chan->rx_decode_len > MAX_SOCK_HDLC_BUF){ + init_hdlc_decoder(&hdlc_eng->tx_decoder); + }else{ + chan->rx_decode_buf[chan->rx_decode_len]=0; + chan->rx_decode_bit_cnt=0; + chan->hdlc_flag=0; + set_bit(CLOSING_FLAG,&chan->hdlc_flag); + } + } + } + } + chan->rx_decode_onecnt=0; + } + } + + return gotdata; +} + + +static void init_crc(void) +{ + int i,j; + + if (test_and_set_bit(0,&init_crc_g)){ + return; + } + + for(i=0;i<256;i++){ + CRC_TABLE[i]=0; + for (j=0;jcrc_cur); + + /* Save the incoming CRC value, so it can be checked + * against the calculated one */ + chan->rx_orig_crc = (((chan->rx_orig_crc<<8)&0xFF00) | chan->rx_decode_buf[chan->rx_decode_len]); + + chan->rx_crc_tmp = (chan->rx_decode_buf[chan->rx_decode_len] ^ chan->rx_crc[chan->crc_prv]) & 0xFF; + chan->rx_crc[chan->crc_cur] = chan->rx_crc[chan->crc_prv] >> 8; + chan->rx_crc[chan->crc_cur] &= 0x00FF; + chan->rx_crc[chan->crc_cur] ^= CRC_TABLE[chan->rx_crc_tmp]; + chan->rx_crc[chan->crc_cur] &= 0xFFFF; + INC_CRC_CNT(chan->crc_prv); +} + +static void tx_up_decode_pkt(wanpipe_hdlc_engine_t *hdlc_eng, + wanpipe_hdlc_decoder_t *chan, + unsigned char txdir) +{ + wp_sock_rx_hdr_t *hdr; + unsigned char *buf; + + struct sk_buff *skb = wan_skb_alloc(chan->rx_decode_len+sizeof(wp_sock_rx_hdr_t)); + if (!skb){ + printk(KERN_INFO "wansock: %s: HDLC Tx up: failed to allocate memory!\n", + __FUNCTION__); + return; + } + + hdr=(wp_sock_rx_hdr_t *)skb_put(skb,sizeof(wp_sock_rx_hdr_t)); + memset(hdr, 0, sizeof(wp_sock_rx_hdr_t)); + hdr->direction=txdir; + + buf = skb_put(skb,chan->rx_decode_len); + memcpy(buf, + chan->rx_decode_buf, + chan->rx_decode_len); + + DEBUG_TX("Tx UP Dir=%d, decod size %i hdr %i skblen=%i\n", + txdir,chan->rx_decode_len, + sizeof(wp_sock_rx_hdr_t), + skb->len); + + wan_skb_queue_tail(&hdlc_eng->data_q,skb); + return; + +} + +/************************************************************** + * + * UTILITY FUNCTIONS + * + **************************************************************/ + + + +static int bind_hdlc_into_timeslots(struct sock *parent_sk, + wanpipe_hdlc_engine_t *hdlc_eng) +{ + int i=0; + wanpipe_hdlc_list_t *hdlc_list; + + if (PPRIV(parent_sk)->media == WAN_MEDIA_NONE){ + hdlc_list=wan_malloc(sizeof(wanpipe_hdlc_list_t)); + if (!hdlc_list){ + DEBUG_EVENT("%s: Error failed to allocate list memory!\n", + SK_PRIV(parent_sk)->dev->name); + return -ENOMEM; + } + memset(hdlc_list,0,sizeof(sizeof(wanpipe_hdlc_list_t))); + + ++hdlc_eng->timeslots; + hdlc_list->hdlc=hdlc_eng; + wp_dev_hold(hdlc_eng); + + hdlc_list->next = PPRIV(parent_sk)->time_slot_hdlc_map[i]; + PPRIV(parent_sk)->time_slot_hdlc_map[i] = hdlc_list; + + DEBUG_EVENT("%s: Binding HDLC engine to Serial\n", + SK_PRIV(parent_sk)->dev->name); + return 0; + + } + + + for (i=0;itime_slots;i++){ + if (test_bit(i,&hdlc_eng->active_ch)){ + + hdlc_list=wan_malloc(sizeof(wanpipe_hdlc_list_t)); + if (!hdlc_list){ + DEBUG_EVENT("%s: Error failed to allocate list memory!\n", + SK_PRIV(parent_sk)->dev->name); + return -ENOMEM; + } + memset(hdlc_list,0,sizeof(sizeof(wanpipe_hdlc_list_t))); + + ++hdlc_eng->timeslots; + hdlc_list->hdlc=hdlc_eng; + wp_dev_hold(hdlc_eng); + + if (PPRIV(parent_sk)->media == WAN_MEDIA_E1){ + hdlc_list->next = PPRIV(parent_sk)->time_slot_hdlc_map[i+1]; + PPRIV(parent_sk)->time_slot_hdlc_map[i+1] = hdlc_list; + }else{ + hdlc_list->next = PPRIV(parent_sk)->time_slot_hdlc_map[i]; + PPRIV(parent_sk)->time_slot_hdlc_map[i] = hdlc_list; + } + + DEBUG_EVENT("%s: Binding HDLC engine to timeslot %i\n", + SK_PRIV(parent_sk)->dev->name,i+1); + } + } + + return 0; +} + +static int remove_hdlc_from_list(wanpipe_hdlc_engine_t **list, wanpipe_hdlc_engine_t *hdlc_eng) +{ + wanpipe_hdlc_engine_t *tmp,*prev; + + if ((tmp=*list) == hdlc_eng){ + *list = hdlc_eng->next; + DEBUG_TEST("DEBUG Removing first hdlc_eng %p from hdlc list: list=%p\n", + hdlc_eng,*list); + wp_dev_put(hdlc_eng); + return 0; + } + + while (tmp != NULL && tmp->next != NULL){ + + prev=tmp; + tmp=tmp->next; + + if (tmp == hdlc_eng){ + prev->next=tmp->next; + DEBUG_TEST("DEBUG Removing hdlc_eng %p from hdlc list: list=%p\n", + hdlc_eng,*list); + wp_dev_put(hdlc_eng); + return 0; + } + } + + return -ENODEV; +} + +static int remove_hdlc_from_ts_list(wanpipe_hdlc_list_t **list, wanpipe_hdlc_engine_t *hdlc_eng) +{ + wanpipe_hdlc_list_t *tmp,*prev; + + if ((tmp=*list)){ + + if (tmp->hdlc == hdlc_eng){ + + *list = tmp->next; + + DEBUG_TEST("DEBUG Removing first hdlc_eng %p from ts list: list=%p\n", + hdlc_eng,*list); + wp_dev_put(hdlc_eng); + + wan_free(tmp); + return 0; + } + } + + while (tmp != NULL && tmp->next != NULL){ + + prev=tmp; + tmp=tmp->next; + + if (tmp->hdlc == hdlc_eng){ + prev->next=tmp->next; + DEBUG_TEST("DEBUG Removing hdlc_eng %p from list: list=%p\n", + hdlc_eng,*list); + wp_dev_put(hdlc_eng); + + wan_free(tmp); + return 0; + } + } + + return -ENODEV; +} + + + +static void unbind_hdlc_from_timeslots(struct sock *parent_sk, wanpipe_hdlc_engine_t *hdlc_eng) +{ + int i; + remove_hdlc_from_list(&PPRIV(parent_sk)->hdlc_eng_list,hdlc_eng); + + for (i=0;itime_slot_hdlc_map[i]){ + remove_hdlc_from_ts_list(&PPRIV(parent_sk)->time_slot_hdlc_map[i], + hdlc_eng); + } + } + + return; +} + + +static wanpipe_hdlc_engine_t *wanpipe_get_hdlc_engine (struct sock *parent_sk, + unsigned long active_ch) +{ + wanpipe_hdlc_engine_t *hdlc_eng; + + for (hdlc_eng = PPRIV(parent_sk)->hdlc_eng_list; + hdlc_eng; + hdlc_eng = hdlc_eng->next){ + if (hdlc_eng->active_ch == active_ch){ + return hdlc_eng; + } + } + + hdlc_eng = wan_malloc(sizeof(wanpipe_hdlc_engine_t)); + if (!hdlc_eng){ + return NULL; + } + + memset(hdlc_eng,0,sizeof(wanpipe_hdlc_engine_t)); + + hdlc_eng->raw_rx_skb = wan_skb_alloc(MAX_SOCK_HDLC_BUF); + if (!hdlc_eng->raw_rx_skb){ + wan_free(hdlc_eng); + return NULL; + } + + hdlc_eng->raw_tx_skb = wan_skb_alloc(MAX_SOCK_HDLC_BUF); + if (!hdlc_eng->raw_tx_skb){ + wan_skb_free(hdlc_eng->raw_rx_skb); + wan_free(hdlc_eng); + return NULL; + } + + hdlc_eng->active_ch=active_ch; + hdlc_eng->seven_bit_hdlc=PPRIV(parent_sk)->seven_bit_hdlc; + + init_hdlc_decoder(&hdlc_eng->rx_decoder); + init_hdlc_decoder(&hdlc_eng->tx_decoder); + + skb_queue_head_init(&hdlc_eng->data_q); + + wp_dev_hold(hdlc_eng); + + return hdlc_eng; +} + +static void init_hdlc_decoder(wanpipe_hdlc_decoder_t *hdlc_decoder) +{ + hdlc_decoder->hdlc_flag=0; + set_bit(NO_FLAG,&hdlc_decoder->hdlc_flag); + + hdlc_decoder->rx_decode_len=0; + hdlc_decoder->rx_decode_buf[hdlc_decoder->rx_decode_len]=0; + hdlc_decoder->rx_decode_bit_cnt=0; + hdlc_decoder->rx_decode_onecnt=0; + hdlc_decoder->rx_crc[0]=-1; + hdlc_decoder->rx_crc[1]=-1; + hdlc_decoder->rx_crc[2]=-1; + hdlc_decoder->crc_cur=0; + hdlc_decoder->crc_prv=0; +} + + +static void free_hdlc_engine(wanpipe_hdlc_engine_t *hdlc_eng) +{ + skb_queue_purge(&hdlc_eng->data_q); + if (hdlc_eng->raw_tx_skb){ + wan_skb_free(hdlc_eng->raw_tx_skb); + hdlc_eng->raw_tx_skb=NULL; + } + if (hdlc_eng->raw_rx_skb){ + wan_skb_free(hdlc_eng->raw_rx_skb); + hdlc_eng->raw_rx_skb=NULL; + } + wp_dev_put(hdlc_eng); +} + +static int bind_sk_to_parent_prot(void **map, unsigned char *devname,struct sock *sk) +{ + int i; + + for (i=0;iprot_type)){ + if (map[i]){ + DEBUG_EVENT("%s: Error SS7 prot %s exists!\n", + devname,DECODE_SS7_PROT((1<lock,flags); + + dev=SK_PRIV(sk)->dev; + if (dev && dev->do_ioctl){ + struct ifreq ifr; + memset(&ifr,0,sizeof(struct ifreq)); + ifr.ifr_data = (void*)sk; + DEBUG_TEST("%s: UNBINDING SK dev=%s\n",__FUNCTION__,dev->name); + dev->do_ioctl(dev,&ifr,SIOC_WANPIPE_UNBIND_SK); + } + + sk->sk_socket = NULL; + + /* Purge queues */ +#ifdef LINUX_2_4 + skb_queue_purge(&sk->sk_receive_queue); + skb_queue_purge(&sk->sk_write_queue); + skb_queue_purge(&sk->sk_error_queue); +#else + while ((skb=skb_dequeue(&sk->sk_receive_queue)) != NULL){ + kfree_skb(skb); + } + while ((skb=skb_dequeue(&sk->sk_write_queue)) != NULL) { + kfree_skb(skb); + } + while ((skb=skb_dequeue(&sk->sk_error_queue)) != NULL){ + kfree_skb(skb); + } +#endif + + write_unlock_irqrestore(&PPRIV(sk)->lock,flags); + + + if (PPRIV(sk)){ + wan_free(PPRIV(sk)); + PPRIV_INIT(sk,NULL); + } + + if (DATA_SC(sk)){ + wan_free(DATA_SC(sk)); + DATA_SC_INIT(sk,NULL); + } + + if (SK_PRIV(sk)){ + kfree(sk->sk_user_data); + sk->sk_user_data=NULL; + } + + #ifdef LINUX_2_4 + if (atomic_read(&sk->refcnt) != 1){ + atomic_set(&sk->refcnt,1); + DEBUG_EVENT("%s:%d: Error, wrong reference count: %i ! :timer.\n", + __FUNCTION__,__LINE__,atomic_read(&sk->refcnt)); + } + wp_sock_put(sk); + #else + sk_free(sk); + #endif + atomic_dec(&wanpipe_socks_nr); +#ifndef LINUX_2_6 + MOD_DEC_USE_COUNT; +#endif + return; +} + + +#if 0 +static void print_hdlc_list(wanpipe_hdlc_engine_t **list, int ts_list) +{ + wanpipe_hdlc_engine_t *tmp; + + DEBUG_EVENT("\n"); + if (ts_list){ + DEBUG_EVENT("TS LIST: "); + for (tmp=*list;tmp;tmp=tmp->ts_next){ + __DEBUG_EVENT("%p ->"); + + }else{ + DEBUG_EVENT("LIST: "); + for (tmp=*list;tmp;tmp=tmp->next){ + __DEBUG_EVENT("%p ->"); + } + } + __DEBUG_EVENT("NULL \n"); + DEBUG_EVENT("\n"); + +} +#endif diff -Nur linux.org/net/wanrouter/patchlevel linux-2.6.17/net/wanrouter/patchlevel --- linux.org/net/wanrouter/patchlevel 2006-06-18 01:49:35.000000000 +0000 +++ linux-2.6.17/net/wanrouter/patchlevel 2006-08-30 10:07:16.000000000 +0000 @@ -1 +1 @@ -2.2.1 +beta7-2.3.4 diff -Nur linux.org/net/wanrouter/waniface.c linux-2.6.17/net/wanrouter/waniface.c --- linux.org/net/wanrouter/waniface.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/net/wanrouter/waniface.c 2006-08-30 10:07:16.000000000 +0000 @@ -0,0 +1,304 @@ +/***************************************************************************** +* waniface.c WAN Multiprotocol Interface Module. Main code. +* +* Author: Nenad Corbic +* +* Copyright: (c) 1995-2002 Sangoma Technologies Inc. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version +* 2 of the License, or (at your option) any later version. +* ============================================================================ +*/ + +#include +#include +#include +#include +#include /* WAN router API definitions */ +#include + +#include +#include +#include +#include + +extern struct wanpipe_lapb_register_struct lapb_protocol; +extern struct wanpipe_x25_register_struct x25_protocol; +extern struct wanpipe_dsp_register_struct dsp_protocol; +extern struct wanpipe_api_register_struct api_socket; +extern struct wanpipe_fw_register_struct wp_fw_protocol; +extern struct wplip_reg wplip_protocol; + +/*===================================== + * Interfaces to Protocol Modules + *====================================*/ + +int bind_api_to_protocol (netdevice_t *dev, char *devname, unsigned short protocol, void *sk_id) +{ + WAN_ASSERT2((!sk_id),-ENODEV); + + switch (htons(protocol)){ + + case ETH_P_X25: + + WAN_ASSERT2((!dev),-ENODEV); + + if (!IS_FUNC_CALL(x25_protocol,x25_bind_api_to_svc)) + return -EPROTONOSUPPORT; + + return x25_protocol.x25_bind_api_to_svc(dev,sk_id); + + case DSP_PROT: + + WAN_ASSERT2((!dev),-ENODEV); + + if (!IS_FUNC_CALL(dsp_protocol, dsp_bind_api)) + return -EPROTONOSUPPORT; + return dsp_protocol.dsp_bind_api(dev, sk_id); + + case WP_X25_PROT: + + WAN_ASSERT2((!devname),-ENODEV); + + if (!IS_FUNC_CALL(wp_fw_protocol,bind_api_to_svc)) + return -EPROTONOSUPPORT; + + return wp_fw_protocol.bind_api_to_svc(devname,sk_id); + + } + + printk(KERN_INFO "Protocol not supported %i!\n",htons(protocol)); + return -EPROTONOSUPPORT; +} + +int bind_api_listen_to_protocol (netdevice_t *dev, char *devname, unsigned short protocol, void *sk_id) +{ + + WAN_ASSERT2((!sk_id),-ENODEV); + + switch (htons(protocol)){ + + case DSP_PROT: + case ETH_P_X25: + + WAN_ASSERT2((!dev),-ENODEV); + + if (!IS_FUNC_CALL(x25_protocol,x25_bind_listen_to_link)) + return -EPROTONOSUPPORT; + + return x25_protocol.x25_bind_listen_to_link(dev,sk_id,htons(protocol)); + + case WP_X25_PROT: + + WAN_ASSERT2((!devname),-ENODEV); + + if (!IS_FUNC_CALL(wp_fw_protocol,bind_listen_to_link)) + return -EPROTONOSUPPORT; + + return wp_fw_protocol.bind_listen_to_link(devname,sk_id,htons(protocol)); + + } + + printk(KERN_INFO "Protocol not supported %i!\n",htons(protocol)); + return -EPROTONOSUPPORT; +} + +int unbind_api_listen_from_protocol (unsigned short protocol, void *sk_id) +{ + WAN_ASSERT2((!sk_id),-ENODEV); + + switch (htons(protocol)){ + + case DSP_PROT: + case ETH_P_X25: + if (!IS_FUNC_CALL(x25_protocol,x25_unbind_listen_from_link)) + return -EPROTONOSUPPORT; + + return x25_protocol.x25_unbind_listen_from_link(sk_id, htons(protocol)); + + case WP_X25_PROT: + if (!IS_FUNC_CALL(wp_fw_protocol,unbind_listen_from_link)) + return -EPROTONOSUPPORT; + + return wp_fw_protocol.unbind_listen_from_link(sk_id, htons(protocol)); + + } + + printk(KERN_INFO "Protocol not supported %i!\n",htons(protocol)); + return -EPROTONOSUPPORT; +} + + +/*================================================ + * Interface to LIP Layer + */ +int wanpipe_lip_rx(void *chan_ptr, void *skb) +{ + wanpipe_common_t *chan = (wanpipe_common_t*)chan_ptr; + + if (!chan->lip){ + return -ENODEV; + } + if (!IS_FUNC_CALL(wplip_protocol,wplip_rx)) + return -EPROTONOSUPPORT; + + return wplip_protocol.wplip_rx(chan->lip,skb); +} + +int wanpipe_lip_connect(void *chan_ptr, int reason) +{ + wanpipe_common_t *chan = (wanpipe_common_t*)chan_ptr; + + if (!chan->lip){ + return -ENODEV; + } + if (!IS_FUNC_CALL(wplip_protocol,wplip_connect)) + return -EPROTONOSUPPORT; + + wplip_protocol.wplip_connect(chan->lip,reason); + + return 0; +} + +int wanpipe_lip_disconnect(void *chan_ptr, int reason) +{ + wanpipe_common_t *chan = (wanpipe_common_t*)chan_ptr; + + if (!chan->lip){ + return -ENODEV; + } + if (!IS_FUNC_CALL(wplip_protocol,wplip_disconnect)) + return -EPROTONOSUPPORT; + + wplip_protocol.wplip_disconnect(chan->lip,reason); + return 0; +} + +int wanpipe_lip_kick(void *chan_ptr,int reason) +{ + wanpipe_common_t *chan = (wanpipe_common_t*)chan_ptr; + + if (!chan->lip){ + return -ENODEV; + } + if (!IS_FUNC_CALL(wplip_protocol,wplip_kick)) + return -EPROTONOSUPPORT; + + wplip_protocol.wplip_kick(chan->lip,reason); + return 0; +} + +int wanpipe_lip_get_if_status(void *chan_ptr,void *m) +{ + wanpipe_common_t *chan = (wanpipe_common_t*)chan_ptr; + + if (!chan->lip){ + return -ENODEV; + } + if (!IS_FUNC_CALL(wplip_protocol,wplip_get_if_status)) + return -EPROTONOSUPPORT; + + wplip_protocol.wplip_get_if_status(chan->lip,m); + return 0; + + +} + +/*========================================== + * Interface to socket API + *=========================================*/ + +int protocol_connected (netdevice_t *dev, void *sk_id) +{ + WAN_ASSERT2((!sk_id),-ENODEV); + WAN_ASSERT2((!dev),-ENODEV); + + if (!IS_FUNC_CALL(api_socket,wanpipe_api_connected)) + return -ENODEV; + + return api_socket.wanpipe_api_connected(dev,sk_id); +} + +int protocol_connecting (netdevice_t *dev, void *sk_id) +{ + WAN_ASSERT2((!sk_id),-ENODEV); + WAN_ASSERT2((!dev),-ENODEV); + + if (!IS_FUNC_CALL(api_socket,wanpipe_api_connecting)) + return -ENODEV; + + return api_socket.wanpipe_api_connecting(dev,sk_id); +} + + +int protocol_disconnected (void *sk_id) +{ + WAN_ASSERT2((!sk_id),-ENODEV); + + if (!IS_FUNC_CALL(api_socket,wanpipe_api_disconnected)) + return -ENODEV; + + return api_socket.wanpipe_api_disconnected(sk_id); +} + +int wanpipe_api_sock_rx (struct sk_buff *skb, netdevice_t *dev, void *sk_id) +{ + WAN_ASSERT2((!sk_id),-ENODEV); + WAN_ASSERT2((!dev),-ENODEV); + WAN_ASSERT2((!skb),-ENOBUFS); + + if (!IS_FUNC_CALL(api_socket,wanpipe_api_sock_rcv)) + return -ENODEV; + + return api_socket.wanpipe_api_sock_rcv(skb, dev, (struct sock *)sk_id); +} + +int wanpipe_api_listen_rx (struct sk_buff *skb, void *sk_id) +{ + WAN_ASSERT2((!sk_id),-ENODEV); + + /* It is ok if skb==NULL, the wanpipe_listen_rcv function + * supports it */ + + if (!IS_FUNC_CALL(api_socket,wanpipe_listen_rcv)){ + printk(KERN_INFO "WANIFACE: No listen_rcv binded !\n"); + return -ENODEV; + } + + return api_socket.wanpipe_listen_rcv(skb, (struct sock *)sk_id); +} + +int wanpipe_api_buf_check (void *sk_id, int len) +{ + WAN_ASSERT2((!sk_id),-ENODEV); + + if (!IS_FUNC_CALL(api_socket,sk_buf_check)) + return -ENODEV; + + return api_socket.sk_buf_check((struct sock *)sk_id,len); +} + + +int wanpipe_api_poll_wake (void *sk_id) +{ + WAN_ASSERT2((!sk_id),-ENODEV); + + if (!IS_FUNC_CALL(api_socket,sk_poll_wake)) + return -ENODEV; + + return api_socket.sk_poll_wake((struct sock *)sk_id); +} + +EXPORT_SYMBOL(bind_api_to_protocol); +EXPORT_SYMBOL(wanpipe_api_sock_rx); +EXPORT_SYMBOL(protocol_disconnected); +EXPORT_SYMBOL(protocol_connected); +EXPORT_SYMBOL(protocol_connecting); +EXPORT_SYMBOL(wanpipe_api_listen_rx); +EXPORT_SYMBOL(unbind_api_listen_from_protocol); +EXPORT_SYMBOL(bind_api_listen_to_protocol); +EXPORT_SYMBOL(wanpipe_api_buf_check); +EXPORT_SYMBOL(wanpipe_api_poll_wake); + diff -Nur linux.org/net/wanrouter/wanmain.c linux-2.6.17/net/wanrouter/wanmain.c --- linux.org/net/wanrouter/wanmain.c 2006-06-18 01:49:35.000000000 +0000 +++ linux-2.6.17/net/wanrouter/wanmain.c 2006-08-30 10:07:16.000000000 +0000 @@ -8,24 +8,26 @@ * o Physical connection management (dial-up, incoming calls) * o Logical connection management (switched virtual circuits) * o Protocol encapsulation/decapsulation + +* Author: Gideon Hack +* Nenad Corbic * -* Author: Gideon Hack -* -* Copyright: (c) 1995-1999 Sangoma Technologies Inc. +* Copyright: (c) 1995-2003 Sangoma Technologies Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * ============================================================================ -* Nov 24, 2000 Nenad Corbic Updated for 2.4.X kernels +* May 13, 2002 Nenad Corbic Updated for ADSL drivers +* Nov 24, 2000 Nenad Corbic Updated for 2.4.X kernels * Nov 07, 2000 Nenad Corbic Fixed the Mulit-Port PPP for kernels 2.2.16 and * greater. * Aug 2, 2000 Nenad Corbic Block the Multi-Port PPP from running on -* kernels 2.2.16 or greater. The SyncPPP +* kernels 2.2.16 or greater. The SyncPPP * has changed. * Jul 13, 2000 Nenad Corbic Added SyncPPP support -* Added extra debugging in device_setup(). +* Added extra debugging in wan_device_setup(). * Oct 01, 1999 Gideon Hack Update for s514 PCI card * Dec 27, 1996 Gene Kozin Initial version (based on Sangoma's WANPIPE) * Jan 16, 1997 Gene Kozin router_devlist made public @@ -36,30 +38,29 @@ * May 17, 1998 K. Baranowski Fixed SNAP encapsulation in wan_encapsulate * Dec 15, 1998 Arnaldo Melo support for firmwares of up to 128000 bytes * check wandev->setup return value -* Dec 22, 1998 Arnaldo Melo vmalloc/vfree used in device_setup to allocate +* Dec 22, 1998 Arnaldo Melo vmalloc/vfree used in wan_device_setup to allocate * kernel memory and copy configuration data to * kernel space (for big firmwares) -* Jun 02, 1999 Gideon Hack Updates for Linux 2.0.X and 2.2.X kernels. +* Jun 02, 1999 Gideon Hack Updates for Linux 2.0.X and 2.2.X kernels. *****************************************************************************/ -#include -#include /* offsetof(), etc. */ -#include -#include /* return codes */ -#include -#include -#include /* support for loadable modules */ -#include /* kmalloc(), kfree() */ -#include -#include /* inline mem*, str* functions */ +#define _K22X_MODULE_FIX_ -#include /* htons(), etc. */ +#include +#include +#include +#include +#include #include /* WAN router API definitions */ +#include /* WAN router API definitions */ +#include -#include /* vmalloc, vfree */ -#include /* copy_to/from_user */ -#include /* __initfunc et al. */ -#include + +#include +#include +#include +#include +#include #define KMEM_SAFETYZONE 8 @@ -120,81 +121,183 @@ #define kfree(x) dbg_kfree(x,__LINE__) *****************************************************************************/ + /* - * Function Prototypes + * Defines and Macros */ +#ifndef wp_min +#define wp_min(a,b) (((a)<(b))?(a):(b)) +#endif +#ifndef wp_max +#define wp_max(a,b) (((a)>(b))?(a):(b)) +#endif + /* - * WAN device IOCTL handlers + * Function Prototypes + */ + +/* + * Kernel loadable module interface. */ +#ifdef MODULE +MODULE_AUTHOR ("Nenad Corbic "); +MODULE_DESCRIPTION ("Sangoma WANPIPE: Proc & User Interface"); -static int wanrouter_device_setup(struct wan_device *wandev, - wandev_conf_t __user *u_conf); -static int wanrouter_device_stat(struct wan_device *wandev, - wandev_stat_t __user *u_stat); -static int wanrouter_device_shutdown(struct wan_device *wandev); -static int wanrouter_device_new_if(struct wan_device *wandev, - wanif_conf_t __user *u_conf); -static int wanrouter_device_del_if(struct wan_device *wandev, - char __user *u_name); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,9) +MODULE_LICENSE("GPL"); +#endif +#endif -/* - * Miscellaneous +/* + * WAN device IOCTL handlers */ -static struct wan_device *wanrouter_find_device(char *name); -static int wanrouter_delete_interface(struct wan_device *wandev, char *name); -void lock_adapter_irq(spinlock_t *lock, unsigned long *smp_flags); -void unlock_adapter_irq(spinlock_t *lock, unsigned long *smp_flags); +static int wan_device_setup(wan_device_t *wandev, wandev_conf_t *u_conf); +static int wan_device_stat(wan_device_t *wandev, wandev_stat_t *u_stat); +static int wan_device_shutdown(wan_device_t *wandev, wandev_conf_t *u_conf); +static int wan_device_new_if(wan_device_t *wandev, wanif_conf_t *u_conf); +static int wan_device_del_if(wan_device_t *wandev, char *u_name); +static int wan_device_debugging(wan_device_t *wandev); + +static int wan_device_new_if_lip(wan_device_t *wandev, wanif_conf_t *u_conf); +static int wan_device_del_if_lip(wan_device_t *wandev, netdevice_t *dev); + +/* WAN Annexg IOCLT handlers */ + +#ifdef CONFIG_PRODUCT_WANPIPE_ANNEXG +static int wan_device_new_if_lapb(wan_device_t *wandev, wanif_conf_t *u_conf); +static int wan_device_del_if_lapb(wan_device_t *wandev, netdevice_t *dev); +static int wan_device_new_if_x25(wan_device_t *wandev, wanif_conf_t *u_conf); +static int wan_device_del_if_x25(wan_device_t *wandev, netdevice_t *dev); +static int wan_device_new_if_dsp(wan_device_t *wandev, wanif_conf_t *u_conf); +static int wan_device_del_if_dsp(wan_device_t *wandev, netdevice_t *dev); +#endif + +static int wan_device_unreg_lip(netdevice_t *dev); + +/* + * Miscellaneous + */ + +static wan_device_t *find_device (char *name); +static int delete_interface (wan_device_t *wandev, netdevice_t *dev, int force); /* * Global Data */ -static char wanrouter_fullname[] = "Sangoma WANPIPE Router"; -static char wanrouter_copyright[] = "(c) 1995-2000 Sangoma Technologies Inc."; -static char wanrouter_modname[] = ROUTER_NAME; /* short module name */ -struct wan_device* wanrouter_router_devlist; /* list of registered devices */ +static char fullname[] = "WANPIPE(tm) Interface Support Module"; +static char modname[] = ROUTER_NAME; /* short module name */ +struct wan_devlist_ wan_devlist = + WAN_LIST_HEAD_INITIALIZER(wan_devlist); +//wan_device_t* router_devlist = NULL; /* list of registered devices */ +static int devcnt = 0; +static unsigned char wan_version[100]; -/* - * Organize Unique Identifiers for encapsulation/decapsulation + +/* + * Organize Unique Identifiers for encapsulation/decapsulation */ -static unsigned char wanrouter_oui_ether[] = { 0x00, 0x00, 0x00 }; +static unsigned char oui_ether[] = { 0x00, 0x00, 0x00 }; #if 0 -static unsigned char wanrouter_oui_802_2[] = { 0x00, 0x80, 0xC2 }; +static unsigned char oui_802_2[] = { 0x00, 0x80, 0xC2 }; +#endif + + +struct wanpipe_api_register_struct api_socket; +struct wanpipe_lapb_register_struct lapb_protocol; +struct wanpipe_x25_register_struct x25_protocol; +struct wanpipe_dsp_register_struct dsp_protocol; +struct wanpipe_fw_register_struct wp_fw_protocol; +struct wplip_reg wplip_protocol; + +#if defined(CONFIG_WANPIPE_HWEC) +struct wanec_iface_ wanec_iface; #endif -static int __init wanrouter_init(void) +/* + * Kernel Loadable Module Entry Points + */ + +/* + * Module 'insert' entry point. + * o print announcement + * o initialize static data + * o create /proc/net/wanrouter directory and static entries + * + * Return: 0 Ok + * < 0 error. + * Context: process + */ + +int __init wanrouter_init (void) { int err; - printk(KERN_INFO "%s v%u.%u %s\n", - wanrouter_fullname, ROUTER_VERSION, ROUTER_RELEASE, - wanrouter_copyright); + if (WANPIPE_VERSION_BETA){ + DEBUG_EVENT("%s Beta%s-%s %s %s\n", + fullname, WANPIPE_SUB_VERSION, WANPIPE_VERSION, + WANPIPE_COPYRIGHT_DATES,WANPIPE_COMPANY); + sprintf(wan_version,"Beta%s-%s", + WANPIPE_SUB_VERSION, WANPIPE_VERSION); + }else{ + DEBUG_EVENT("%s Stable %s-%s %s %s\n", + fullname, WANPIPE_VERSION, WANPIPE_SUB_VERSION, + WANPIPE_COPYRIGHT_DATES,WANPIPE_COMPANY); + sprintf(wan_version,"Stable %s-%s", + WANPIPE_VERSION, WANPIPE_SUB_VERSION); + } + + WAN_LIST_INIT(&wan_devlist); err = wanrouter_proc_init(); - if (err) - printk(KERN_INFO "%s: can't create entry in proc filesystem!\n", - wanrouter_modname); + + if (err){ + printk(KERN_INFO + "%s: can't create entry in proc filesystem!\n", modname); + } +#ifdef CONFIG_PRODUCT_WANPIPE_ANNEXG + UNREG_PROTOCOL_FUNC(dsp_protocol); + UNREG_PROTOCOL_FUNC(x25_protocol); + UNREG_PROTOCOL_FUNC(api_socket); + UNREG_PROTOCOL_FUNC(lapb_protocol); +#endif + UNREG_PROTOCOL_FUNC(wplip_protocol); +#if defined(CONFIG_WANPIPE_HWEC) + UNREG_PROTOCOL_FUNC(wanec_iface); +#endif + return err; } -static void __exit wanrouter_cleanup (void) +/* + * Module 'remove' entry point. + * o delete /proc/net/wanrouter directory and static entries. + */ + +void __exit wanrouter_exit (void) { +#if defined(CONFIG_WANPIPE_HWEC) + UNREG_PROTOCOL_FUNC(wanec_iface); +#endif + +#ifdef CONFIG_PRODUCT_WANPIPE_ANNEXG + UNREG_PROTOCOL_FUNC(dsp_protocol); + UNREG_PROTOCOL_FUNC(x25_protocol); + UNREG_PROTOCOL_FUNC(api_socket); + UNREG_PROTOCOL_FUNC(lapb_protocol); +#endif + UNREG_PROTOCOL_FUNC(wp_fw_protocol); wanrouter_proc_cleanup(); } -/* - * This is just plain dumb. We should move the bugger to drivers/net/wan, - * slap it first in directory and make it module_init(). The only reason - * for subsys_initcall() here is that net goes after drivers (why, BTW?) - */ -subsys_initcall(wanrouter_init); -module_exit(wanrouter_cleanup); +module_init(wanrouter_init); +module_exit(wanrouter_exit); /* * Kernel APIs @@ -203,7 +306,7 @@ /* * Register WAN device. * o verify device credentials - * o create an entry for the device in the /proc/net/router directory + * o create an entry for the device in the /proc/net/wanrouter directory * o initialize internally maintained fields of the wan_device structure * o link device data space to a singly-linked list * o if it's the first device, then start kernel 'thread' @@ -217,34 +320,34 @@ */ -int register_wan_device(struct wan_device *wandev) +int register_wan_device(wan_device_t *wandev) { int err, namelen; if ((wandev == NULL) || (wandev->magic != ROUTER_MAGIC) || (wandev->name == NULL)) return -EINVAL; - + namelen = strlen(wandev->name); if (!namelen || (namelen > WAN_DRVNAME_SZ)) return -EINVAL; - - if (wanrouter_find_device(wandev->name)) + + if (find_device(wandev->name) != NULL) return -EEXIST; -#ifdef WANDEBUG +#ifdef WANDEBUG printk(KERN_INFO "%s: registering WAN device %s\n", - wanrouter_modname, wandev->name); + modname, wandev->name); #endif /* - * Register /proc directory entry + * Register /proc directory entry */ err = wanrouter_proc_add(wandev); if (err) { printk(KERN_INFO - "%s: can't create /proc/net/router/%s entry!\n", - wanrouter_modname, wandev->name); + "%s: can't create /proc/net/wanrouter/%s entry!\n", + modname, wandev->name); return err; } @@ -252,11 +355,18 @@ * Initialize fields of the wan_device structure maintained by the * router and update local data. */ - + wandev->ndev = 0; - wandev->dev = NULL; - wandev->next = wanrouter_router_devlist; - wanrouter_router_devlist = wandev; + WAN_LIST_INIT(&wandev->dev_head); + WAN_LIST_INSERT_HEAD(&wan_devlist, wandev, next); + //wandev->dev = NULL; + //wandev->next = router_devlist; + //router_devlist = wandev; + ++devcnt; + +#if !defined(LINUX_2_6) + MOD_INC_USE_COUNT; /* prevent module from unloading */ +#endif return 0; } @@ -264,7 +374,7 @@ * Unregister WAN device. * o shut down device * o unlink device data space from the linked list - * o delete device entry in the /proc/net/router directory + * o delete device entry in the /proc/net/wanrouter directory * o decrement module use count * * Return: 0 Ok @@ -275,32 +385,44 @@ int unregister_wan_device(char *name) { - struct wan_device *wandev, *prev; + wan_device_t *wandev; if (name == NULL) return -EINVAL; - for (wandev = wanrouter_router_devlist, prev = NULL; - wandev && strcmp(wandev->name, name); - prev = wandev, wandev = wandev->next) - ; + + WAN_LIST_FOREACH(wandev, &wan_devlist, next){ + if (!strcmp(wandev->name, name)){ + break; + } + } + //for (wandev = router_devlist, prev = NULL; + // wandev && strcmp(wandev->name, name); + // prev = wandev, wandev = wandev->next) + // ; if (wandev == NULL) return -ENODEV; -#ifdef WANDEBUG - printk(KERN_INFO "%s: unregistering WAN device %s\n", - wanrouter_modname, name); +#ifdef WANDEBUG + printk(KERN_INFO "%s: unregistering WAN device %s\n", modname, name); #endif - if (wandev->state != WAN_UNCONFIGURED) - wanrouter_device_shutdown(wandev); - - if (prev) - prev->next = wandev->next; - else - wanrouter_router_devlist = wandev->next; - + if (wandev->state != WAN_UNCONFIGURED) { + wan_device_shutdown(wandev, NULL); + } + + WAN_LIST_REMOVE(wandev, next); + //if (prev){ + // prev->next = wandev->next; + //}else{ + // router_devlist = wandev->next; + //} + + --devcnt; wanrouter_proc_delete(wandev); +#if !defined(LINUX_2_6) + MOD_DEC_USE_COUNT; +#endif return 0; } @@ -333,21 +455,21 @@ skb_push(skb, 7); skb->data[0] = 0; skb->data[1] = NLPID_SNAP; - memcpy(&skb->data[2], wanrouter_oui_ether, - sizeof(wanrouter_oui_ether)); + memcpy(&skb->data[2], oui_ether, sizeof(oui_ether)); *((unsigned short*)&skb->data[5]) = htons(type); break; default: /* Unknown packet type */ printk(KERN_INFO "%s: unsupported Ethertype 0x%04X on interface %s!\n", - wanrouter_modname, type, dev->name); + modname, type, dev->name); hdr_len = -EINVAL; } return hdr_len; } + /* * Decapsulate packet. * @@ -359,28 +481,29 @@ */ -__be16 wanrouter_type_trans(struct sk_buff *skb, struct net_device *dev) +unsigned short wanrouter_type_trans (struct sk_buff *skb, netdevice_t *dev) { int cnt = skb->data[0] ? 0 : 1; /* there may be a pad present */ - __be16 ethertype; + unsigned short ethertype; switch (skb->data[cnt]) { + + case CISCO_IP: case NLPID_IP: /* IP datagramm */ ethertype = htons(ETH_P_IP); cnt += 1; break; case NLPID_SNAP: /* SNAP encapsulation */ - if (memcmp(&skb->data[cnt + 1], wanrouter_oui_ether, - sizeof(wanrouter_oui_ether))){ + if (memcmp(&skb->data[cnt + 1], oui_ether, sizeof(oui_ether))){ printk(KERN_INFO "%s: unsupported SNAP OUI %02X-%02X-%02X " - "on interface %s!\n", wanrouter_modname, + "on interface %s!\n", modname, skb->data[cnt+1], skb->data[cnt+2], skb->data[cnt+3], dev->name); return 0; - } - ethertype = *((__be16*)&skb->data[cnt+4]); + } + ethertype = *((unsigned short*)&skb->data[cnt+4]); cnt += 6; break; @@ -389,7 +512,7 @@ default: printk(KERN_INFO "%s: unsupported NLPID 0x%02X on interface %s!\n", - wanrouter_modname, skb->data[cnt], dev->name); + modname, skb->data[cnt], dev->name); return 0; } skb->protocol = ethertype; @@ -411,47 +534,101 @@ { int err = 0; struct proc_dir_entry *dent; - struct wan_device *wandev; - void __user *data = (void __user *)arg; - - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - - if ((cmd >> 8) != ROUTER_IOCTL) + wan_device_t *wandev; + + if ((cmd>>8) != ROUTER_IOCTL){ + DEBUG_EVENT("%s: Invalid CMD=0x%X ROUTER_IOCTL=0x%X\n", + __FUNCTION__,cmd>>8,ROUTER_IOCTL); return -EINVAL; - - dent = PDE(inode); - if ((dent == NULL) || (dent->data == NULL)) + } + + dent = WP_PDE(inode); + if ((dent == NULL) || (dent->data == NULL)){ + DEBUG_EVENT("%s: Invalid dent %p\n", + __FUNCTION__,inode->u.generic_ip); return -EINVAL; - + } + wandev = dent->data; - if (wandev->magic != ROUTER_MAGIC) + if (wandev->magic != ROUTER_MAGIC){ + DEBUG_EVENT("%s: Invalid wandev Magic Number\n", + __FUNCTION__); return -EINVAL; + } + + if (wandev->config_id != WANCONFIG_EDUKIT){ + ADMIN_CHECK(); + } switch (cmd) { case ROUTER_SETUP: - err = wanrouter_device_setup(wandev, data); + ADMIN_CHECK(); + err = wan_device_setup(wandev, (void*)arg); break; case ROUTER_DOWN: - err = wanrouter_device_shutdown(wandev); + ADMIN_CHECK(); + err = wan_device_shutdown(wandev, (void*)arg); break; case ROUTER_STAT: - err = wanrouter_device_stat(wandev, data); + ADMIN_CHECK(); + err = wan_device_stat(wandev, (void*)arg); break; case ROUTER_IFNEW: - err = wanrouter_device_new_if(wandev, data); + ADMIN_CHECK(); + err = wan_device_new_if(wandev, (void*)arg); break; case ROUTER_IFDEL: - err = wanrouter_device_del_if(wandev, data); + ADMIN_CHECK(); + err = wan_device_del_if(wandev, (void*)arg); + break; + +#ifdef CONFIG_PRODUCT_WANPIPE_ANNEXG + case ROUTER_IFNEW_LAPB: + err = wan_device_new_if_lapb(wandev,(void*)arg); + break; + + case ROUTER_IFNEW_X25: + err = wan_device_new_if_x25(wandev,(void*)arg); + break; + + case ROUTER_IFNEW_DSP: + err = wan_device_new_if_dsp(wandev,(void*)arg); + break; +#endif + + case ROUTER_IFNEW_LIP: + err = wan_device_new_if_lip(wandev,(void*)arg); break; + case ROUTER_IFDEL_LIP: + err = wan_device_del_if_lip(wandev,(void*)arg); + break; + case ROUTER_IFSTAT: break; + case ROUTER_VER: + err=copy_to_user((char*)arg,wan_version,strlen(wan_version)); + break; + + case ROUTER_DEBUGGING: + ADMIN_CHECK(); + err = wan_device_debugging(wandev); + break; + + case ROUTER_DEBUG_READ: + ADMIN_CHECK(); + if (wandev->debug_read){ + err = wandev->debug_read(wandev, (void*)arg); + }else{ + err = -EINVAL; + } + break; + default: if ((cmd >= ROUTER_USER) && (cmd <= ROUTER_USER_MAX) && @@ -474,74 +651,93 @@ * o call driver's setup() entry point */ -static int wanrouter_device_setup(struct wan_device *wandev, - wandev_conf_t __user *u_conf) +static int wan_device_setup (wan_device_t *wandev, wandev_conf_t *u_conf) { void *data = NULL; wandev_conf_t *conf; int err = -EINVAL; - if (wandev->setup == NULL) { /* Nothing to do ? */ + if (wandev->setup == NULL){ /* Nothing to do ? */ printk(KERN_INFO "%s: ERROR, No setup script: wandev->setup()\n", wandev->name); return 0; } - conf = kmalloc(sizeof(wandev_conf_t), GFP_KERNEL); + conf = wan_malloc(sizeof(wandev_conf_t)); if (conf == NULL){ printk(KERN_INFO "%s: ERROR, Failed to allocate kernel memory !\n", wandev->name); return -ENOBUFS; } - - if (copy_from_user(conf, u_conf, sizeof(wandev_conf_t))) { + + if(copy_from_user(conf, u_conf, sizeof(wandev_conf_t))) { printk(KERN_INFO "%s: Failed to copy user config data to kernel space!\n", wandev->name); - kfree(conf); + + DEBUG_SUB_MEM(sizeof(wandev_conf_t)); + wan_free(conf); return -EFAULT; } - - if (conf->magic != ROUTER_MAGIC) { - kfree(conf); + + if (conf->magic != ROUTER_MAGIC){ + DEBUG_SUB_MEM(sizeof(wandev_conf_t)); + wan_free(conf); printk(KERN_INFO "%s: ERROR, Invalid MAGIC Number\n", wandev->name); - return -EINVAL; + return -EINVAL; } - if (conf->data_size && conf->data) { - if (conf->data_size > 128000 || conf->data_size < 0) { - printk(KERN_INFO + if (conf->card_type == WANOPT_ADSL || + conf->card_type == WANOPT_AFT || + conf->card_type == WANOPT_AFT104 || + conf->card_type == WANOPT_AFT300 || + conf->config_id == WANCONFIG_DEBUG){ + conf->data=NULL; + conf->data_size=0; + err = wandev->setup(wandev, conf); + + }else if (conf->data_size && conf->data){ + if(conf->data_size > 128000 || conf->data_size < 0) { + DEBUG_SUB_MEM(sizeof(wandev_conf_t)); + wan_free(conf); + printk(KERN_INFO "%s: ERROR, Invalid firmware data size %i !\n", wandev->name, conf->data_size); - kfree(conf); - return -EINVAL; + return -EINVAL;; } data = vmalloc(conf->data_size); - if (!data) { - printk(KERN_INFO + if (data) { + if(!copy_from_user(data, conf->data, conf->data_size)){ + conf->data=data; + err = wandev->setup(wandev,conf); + }else{ + printk(KERN_INFO + "%s: ERROR, Faild to copy from user data !\n", + wandev->name); + err = -EFAULT; + } + }else{ + printk(KERN_INFO "%s: ERROR, Faild allocate kernel memory !\n", wandev->name); - kfree(conf); - return -ENOBUFS; + err = -ENOBUFS; } - if (!copy_from_user(data, conf->data, conf->data_size)) { - conf->data = data; - err = wandev->setup(wandev, conf); - } else { - printk(KERN_INFO - "%s: ERROR, Faild to copy from user data !\n", - wandev->name); - err = -EFAULT; + + if (data){ + vfree(data); } - vfree(data); - } else { - printk(KERN_INFO - "%s: ERROR, No firmware found ! Firmware size = %i !\n", - wandev->name, conf->data_size); + }else{ + /* No Firmware found. This is ok for ADSL cards or when we are + * operating in DEBUG mode */ + + printk(KERN_INFO + "%s: ERROR, No firmware found ! Firmware size = %i !\n", + wandev->name, conf->data_size); } - kfree(conf); + DEBUG_SUB_MEM(sizeof(wandev_conf_t)); + wan_free(conf); return err; } @@ -550,34 +746,80 @@ * o delete all not opened logical channels for this device * o call driver's shutdown() entry point */ - -static int wanrouter_device_shutdown(struct wan_device *wandev) + +static int wan_device_shutdown (wan_device_t *wandev, wandev_conf_t *u_conf) { - struct net_device *dev; + struct wan_dev_le *devle; + netdevice_t *dev; + wandev_conf_t *conf = NULL; + wan_smp_flag_t smp_flags; int err=0; - - if (wandev->state == WAN_UNCONFIGURED) + int force=0; + + if (wandev->state == WAN_UNCONFIGURED){ return 0; + } + + if (u_conf){ + conf = wan_malloc(sizeof(wandev_conf_t)); + if (conf == NULL){ + printk(KERN_INFO "%s: ERROR, Failed to allocate kernel memory !\n", + wandev->name); + return -ENOBUFS; + } + + if(copy_from_user(conf, u_conf, sizeof(wandev_conf_t))) { + printk(KERN_INFO "%s: Failed to copy user config data to kernel space!\n", + wandev->name); + DEBUG_SUB_MEM(sizeof(wandev_conf_t)); + wan_free(conf); + return -EFAULT; + } + }else{ + /* Module is being unloaded we have no choice here */ + force=1; + } + + printk(KERN_INFO "\n"); + printk(KERN_INFO "%s: Shutting Down!\n",wandev->name); + + devle = WAN_LIST_FIRST(&wandev->dev_head); + while(devle){ - printk(KERN_INFO "\n%s: Shutting Down!\n",wandev->name); - - for (dev = wandev->dev; dev;) { - err = wanrouter_delete_interface(wandev, dev->name); - if (err) + dev = WAN_DEVLE2DEV(devle); + if ((err=delete_interface(wandev, dev, force)) != 0){ return err; - /* The above function deallocates the current dev - * structure. Therefore, we cannot use dev->priv - * as the next element: wandev->dev points to the - * next element */ - dev = wandev->dev; - } + } - if (wandev->ndev) - return -EBUSY; /* there are opened interfaces */ + wan_spin_lock_irq(&wandev->lock, &smp_flags); + WAN_LIST_REMOVE(devle, dev_link); + --wandev->ndev; + wan_spin_unlock_irq(&wandev->lock, &smp_flags); + + wan_free(devle); + /* the next interface is alwast first */ + devle = WAN_LIST_FIRST(&wandev->dev_head); + } + + if (wandev->ndev){ + if (conf){ + DEBUG_SUB_MEM(sizeof(wandev_conf_t)); + wan_free(conf); + } + return -EBUSY; /* there are opened interfaces */ + } + if (wandev->shutdown) - err=wandev->shutdown(wandev); + err=wandev->shutdown(wandev, conf); + + if (u_conf){ + if(copy_to_user(u_conf, conf, sizeof(wandev_conf_t))) + return -EFAULT; + DEBUG_SUB_MEM(sizeof(wandev_conf_t)); + wan_free(conf); + } return err; } @@ -585,8 +827,7 @@ * Get WAN device status & statistics. */ -static int wanrouter_device_stat(struct wan_device *wandev, - wandev_stat_t __user *u_stat) +static int wan_device_stat (wan_device_t *wandev, wandev_stat_t *u_stat) { wandev_stat_t stat; @@ -600,7 +841,7 @@ stat.ndev = wandev->ndev; stat.state = wandev->state; - if (copy_to_user(u_stat, &stat, sizeof(stat))) + if(copy_to_user(u_stat, &stat, sizeof(stat))) return -EFAULT; return 0; @@ -615,122 +856,93 @@ * o make sure there is no interface name conflict * o register network interface */ - -static int wanrouter_device_new_if(struct wan_device *wandev, - wanif_conf_t __user *u_conf) +static int wan_device_new_if (wan_device_t *wandev, wanif_conf_t *u_conf) { - wanif_conf_t *cnf; - struct net_device *dev = NULL; -#ifdef CONFIG_WANPIPE_MULTPPP - struct ppp_device *pppdev=NULL; -#endif - int err; + struct wan_dev_le *devle; + wanif_conf_t *conf=NULL; + netdevice_t *dev=NULL; + int err=-EINVAL; if ((wandev->state == WAN_UNCONFIGURED) || (wandev->new_if == NULL)) return -ENODEV; - cnf = kmalloc(sizeof(wanif_conf_t), GFP_KERNEL); - if (!cnf) - return -ENOBUFS; + conf = wan_malloc(sizeof(wanif_conf_t)); + if (!conf){ + return -ENOMEM; + } + + if(copy_from_user(conf, u_conf, sizeof(wanif_conf_t))){ + err=-EFAULT; + goto wan_device_new_if_exit; + } + + if (conf->magic != ROUTER_MAGIC){ + err=-EINVAL; + goto wan_device_new_if_exit; + } - err = -EFAULT; - if (copy_from_user(cnf, u_conf, sizeof(wanif_conf_t))) - goto out; - - err = -EINVAL; - if (cnf->magic != ROUTER_MAGIC) - goto out; - - if (cnf->config_id == WANCONFIG_MPPP) { -#ifdef CONFIG_WANPIPE_MULTPPP - pppdev = kmalloc(sizeof(struct ppp_device), GFP_KERNEL); - err = -ENOBUFS; - if (pppdev == NULL) - goto out; - memset(pppdev, 0, sizeof(struct ppp_device)); - pppdev->dev = kmalloc(sizeof(struct net_device), GFP_KERNEL); - if (pppdev->dev == NULL) { - kfree(pppdev); - err = -ENOBUFS; - goto out; - } - memset(pppdev->dev, 0, sizeof(struct net_device)); - err = wandev->new_if(wandev, (struct net_device *)pppdev, cnf); - dev = pppdev->dev; -#else - printk(KERN_INFO "%s: Wanpipe Mulit-Port PPP support has not been compiled in!\n", - wandev->name); - err = -EPROTONOSUPPORT; - goto out; -#endif - } else { - dev = kmalloc(sizeof(struct net_device), GFP_KERNEL); - err = -ENOBUFS; - if (dev == NULL) - goto out; - memset(dev, 0, sizeof(struct net_device)); - err = wandev->new_if(wandev, dev, cnf); + dev=wan_netif_alloc(conf->name, WAN_IFT_OTHER, &err); + if (dev == NULL){ + goto wan_device_new_if_exit; } + devle = wan_malloc(sizeof(struct wan_dev_le)); + if (devle == NULL){ + wan_free(dev); + goto wan_device_new_if_exit; + } + + err = wandev->new_if(wandev, dev, conf); + if (!err) { /* Register network interface. This will invoke init() * function supplied by the driver. If device registered * successfully, add it to the interface list. */ - if (dev->name == NULL) { + if (dev->name == NULL){ err = -EINVAL; - } else { - - #ifdef WANDEBUG - printk(KERN_INFO "%s: registering interface %s...\n", - wanrouter_modname, dev->name); - #endif - + }else if (dev_get_by_name(dev->name)){ + err = -EEXIST; /* name already exists */ + }else if (dev->priv){ err = register_netdev(dev); if (!err) { - struct net_device *slave = NULL; - unsigned long smp_flags=0; - - lock_adapter_irq(&wandev->lock, &smp_flags); - - if (wandev->dev == NULL) { - wandev->dev = dev; - } else { - for (slave=wandev->dev; - *((struct net_device **)slave->priv); - slave = *((struct net_device **)slave->priv)); - - *((struct net_device **)slave->priv) = dev; - } + wan_smp_flag_t smp_flags=0; + + devle->dev = dev; + + wan_spin_lock_irq(&wandev->lock, &smp_flags); + WAN_LIST_INSERT_HEAD(&wandev->dev_head, devle, dev_link); ++wandev->ndev; + wan_spin_unlock_irq(&wandev->lock, &smp_flags); + err = 0; - unlock_adapter_irq(&wandev->lock, &smp_flags); - err = 0; /* done !!! */ - goto out; + wan_free(conf); + return 0; } } + if (wandev->del_if) wandev->del_if(wandev, dev); } /* This code has moved from del_if() function */ - kfree(dev->priv); - dev->priv = NULL; + if (dev->priv){ + wan_free(dev->priv); + dev->priv=NULL; + } -#ifdef CONFIG_WANPIPE_MULTPPP - if (cnf->config_id == WANCONFIG_MPPP) - kfree(pppdev); - else - kfree(dev); -#else - /* Sync PPP is disabled */ - if (cnf->config_id != WANCONFIG_MPPP) - kfree(dev); -#endif +wan_device_new_if_exit: + + if (dev){ + DEBUG_SUB_MEM(sizeof(netdevice_t)); + wan_netif_free(dev); + } + if (conf){ + DEBUG_SUB_MEM(sizeof(conf)); + wan_free(conf); + } -out: - kfree(cnf); return err; } @@ -741,38 +953,92 @@ * o copy configuration data to kernel address space */ -static int wanrouter_device_del_if(struct wan_device *wandev, char __user *u_name) +static int wan_device_del_if (wan_device_t *wandev, char *u_name) { + struct wan_dev_le *devle; + netdevice_t *dev=NULL; + wan_smp_flag_t smp_flags; char name[WAN_IFNAME_SZ + 1]; int err = 0; if (wandev->state == WAN_UNCONFIGURED) return -ENODEV; - + memset(name, 0, sizeof(name)); - if (copy_from_user(name, u_name, WAN_IFNAME_SZ)) + if(copy_from_user(name, u_name, WAN_IFNAME_SZ)) return -EFAULT; - err = wanrouter_delete_interface(wandev, name); - if (err) - return err; + WAN_LIST_FOREACH(devle, &wandev->dev_head, dev_link){ + dev = WAN_DEVLE2DEV(devle); + if (dev && !strcmp(name, wan_netif_name(dev))){ + break; + } + } + + if (devle == NULL || dev == NULL){ + if ((dev = dev_get_by_name(name)) == NULL){ + printk(KERN_INFO "%s: dev_get_by_name failed\n", name); + return err; + } + + dev_put(dev); +#ifdef CONFIG_PRODUCT_WANPIPE_ANNEXG + if (dev->type == ARPHRD_LAPB){ + printk(KERN_INFO "%s: Unregistering LAPB interface\n", dev->name); + return wan_device_del_if_lapb(wandev,dev); + }else if (dev->type == ARPHRD_X25){ + printk(KERN_INFO "%s: Unregistering X25 interface\n", dev->name); + return wan_device_del_if_x25(wandev,dev); + }else if (dev->type == ARPHRD_VOID){ + printk(KERN_INFO "%s: Unregistering DSP interface\n", dev->name); + return wan_device_del_if_dsp(wandev,dev); + }else +#endif + { + printk(KERN_INFO "%s: Unregistering LIP interface\n", dev->name); + return wan_device_del_if_lip(wandev,dev); + } + +#if 0 + FIXME: Find a better way to distinguish between + interfaces + printk(KERN_INFO "%s: Unknown interface dev type %d\n", + dev->name,dev->type); + err=-EINVAL; +#endif + return -ENODEV; + } + + + err = delete_interface(wandev, dev,0); + if (err){ + return(err); + } + + wan_spin_lock_irq(&wandev->lock, &smp_flags); + WAN_LIST_REMOVE(devle, dev_link); + --wandev->ndev; + wan_spin_unlock_irq(&wandev->lock, &smp_flags); + wan_free(devle); + /* If last interface being deleted, shutdown card * This helps with administration at leaf nodes - * (You can tell if the person at the other end of the phone + * (You can tell if the person at the other end of the phone * has an interface configured) and avoids DoS vulnerabilities * in binary driver files - this fixes a problem with the current * Sangoma driver going into strange states when all the network * interfaces are deleted and the link irrecoverably disconnected. - */ - - if (!wandev->ndev && wandev->shutdown) - err = wandev->shutdown(wandev); + */ + if (!wandev->ndev && wandev->shutdown){ + err = wandev->shutdown(wandev, NULL); + } return err; } + /* * Miscellaneous Functions */ @@ -782,13 +1048,17 @@ * Return pointer to the WAN device data space or NULL if device not found. */ -static struct wan_device *wanrouter_find_device(char *name) +static wan_device_t *find_device(char *name) { - struct wan_device *wandev; + wan_device_t *wandev; - for (wandev = wanrouter_router_devlist; - wandev && strcmp(wandev->name, name); - wandev = wandev->next); + WAN_LIST_FOREACH(wandev, &wan_devlist, next){ + if (!strcmp(wandev->name, name)){ + break; + } + } + //for (wandev = router_devlist;wandev && strcmp(wandev->name, name); + // wandev = wandev->next); return wandev; } @@ -809,76 +1079,1141 @@ * sure that opened interfaces are not removed! */ -static int wanrouter_delete_interface(struct wan_device *wandev, char *name) +static int delete_interface (wan_device_t *wandev, netdevice_t *dev, int force) { - struct net_device *dev = NULL, *prev = NULL; - unsigned long smp_flags=0; - - lock_adapter_irq(&wandev->lock, &smp_flags); - dev = wandev->dev; - prev = NULL; - while (dev && strcmp(name, dev->name)) { - struct net_device **slave = dev->priv; - prev = dev; - dev = *slave; - } - unlock_adapter_irq(&wandev->lock, &smp_flags); + int err; - if (dev == NULL) + if (dev == NULL){ return -ENODEV; /* interface not found */ + } - if (netif_running(dev)) + if (netif_running(dev)){ return -EBUSY; /* interface in use */ - - if (wandev->del_if) - wandev->del_if(wandev, dev); - - lock_adapter_irq(&wandev->lock, &smp_flags); - if (prev) { - struct net_device **prev_slave = prev->priv; - struct net_device **slave = dev->priv; - - *prev_slave = *slave; - } else { - struct net_device **slave = dev->priv; - wandev->dev = *slave; } - --wandev->ndev; - unlock_adapter_irq(&wandev->lock, &smp_flags); + /* Unregister the lip interface attached + * to this interace */ + err=wan_device_unreg_lip(dev); + if (err){ + return err; + } + + if (wandev->del_if){ + int err; + if ((err=wandev->del_if(wandev, dev))){ + return err; + } + } - printk(KERN_INFO "%s: unregistering '%s'\n", wandev->name, dev->name); + + printk(KERN_INFO "%s: unregistering '%s'\n", wandev->name, dev->name); + /* Due to new interface linking method using dev->priv, * this code has moved from del_if() function.*/ - kfree(dev->priv); - dev->priv=NULL; + if (dev->priv){ + wan_free(dev->priv); + dev->priv=NULL; + } unregister_netdev(dev); + + DEBUG_SUB_MEM(sizeof(netdevice_t)); - free_netdev(dev); - +#ifdef LINUX_2_4 return 0; +#else + /* Changed behaviour for 2.6 kernels */ + wan_netif_free(dev); + return 0; +#endif + } -void lock_adapter_irq(spinlock_t *lock, unsigned long *smp_flags) +/* + * ============================================================================ + * Debugging WAN device. + */ + +static int wan_device_debugging (wan_device_t *wandev) { - spin_lock_irqsave(lock, *smp_flags); + int error = 0; + + if (wandev->state == WAN_UNCONFIGURED){ + return 0; + } + + if (wandev->debugging){ + error = wandev->debugging(wandev); + } + + return 0; } +unsigned long wan_set_ip_address (netdevice_t *dev, int option, unsigned long ip) +{ + + struct sockaddr_in *if_data; + struct ifreq if_info; + int err=0; + mm_segment_t fs; + + /* Setup a structure for adding/removing routes */ + memset(&if_info, 0, sizeof(if_info)); + strcpy(if_info.ifr_name, dev->name); + + switch (option){ + + case WAN_LOCAL_IP: + + if_data = (struct sockaddr_in *)&if_info.ifr_addr; + if_data->sin_addr.s_addr = ip; + if_data->sin_family = AF_INET; + + fs = get_fs(); /* Save file system */ + set_fs(get_ds()); + err = wp_devinet_ioctl(SIOCSIFADDR, &if_info); + set_fs(fs); + break; + + case WAN_POINTOPOINT_IP: + + if_data = (struct sockaddr_in *)&if_info.ifr_dstaddr; + if_data->sin_addr.s_addr = ip; + if_data->sin_family = AF_INET; + + fs = get_fs(); /* Save file system */ + set_fs(get_ds()); + err = wp_devinet_ioctl(SIOCSIFDSTADDR, &if_info); + set_fs(fs); + break; + + case WAN_NETMASK_IP: + break; + + case WAN_BROADCAST_IP: + break; + } + + return err; +} + +unsigned long wan_get_ip_address (netdevice_t *dev, int option) +{ + +#if defined(LINUX_2_4) || defined(LINUX_2_6) + struct in_ifaddr *ifaddr; + struct in_device *in_dev; + + if ((in_dev = in_dev_get(dev)) == NULL){ + return 0; + } +#else + struct in_ifaddr *ifaddr; + struct in_device *in_dev; + + if ((in_dev = dev->ip_ptr) == NULL){ + return 0; + } +#endif + +#if defined(LINUX_2_4) || defined(LINUX_2_6) + wp_rcu_read_lock(in_dev); + for (ifaddr=in_dev->ifa_list; ifaddr != NULL; + ifaddr=ifaddr->ifa_next) { + if (strcmp(dev->name, ifaddr->ifa_label) == 0){ + break; + } + } + wp_rcu_read_unlock(in_dev); + in_dev_put(in_dev); +#else + for (ifaddr=in_dev->ifa_list; ifaddr != NULL; + ifaddr=ifaddr->ifa_next){ + if (strcmp(dev->name, ifaddr->ifa_label) == 0) + { + break; + } + } +#endif + + if (ifaddr == NULL ){ + return 0; + } + + switch (option){ + + case WAN_LOCAL_IP: + return ifaddr->ifa_local; + break; + + case WAN_POINTOPOINT_IP: + return ifaddr->ifa_address; + break; + + case WAN_NETMASK_IP: + return ifaddr->ifa_mask; + break; + + case WAN_BROADCAST_IP: + return ifaddr->ifa_broadcast; + break; + default: + return 0; + } -void unlock_adapter_irq(spinlock_t *lock, unsigned long *smp_flags) + return 0; +} + +static inline void set_sockaddr(struct sockaddr_in *sin, u32 addr, u16 port) { - spin_unlock_irqrestore(lock, *smp_flags); + sin->sin_family = AF_INET; + sin->sin_addr.s_addr = addr; + sin->sin_port = port; } -EXPORT_SYMBOL(register_wan_device); -EXPORT_SYMBOL(unregister_wan_device); -EXPORT_SYMBOL(wanrouter_encapsulate); -EXPORT_SYMBOL(wanrouter_type_trans); -EXPORT_SYMBOL(lock_adapter_irq); -EXPORT_SYMBOL(unlock_adapter_irq); +void wan_add_gateway(netdevice_t *dev) +{ + mm_segment_t oldfs; + struct rtentry route; + int res; +#if 0 + unsigned long local_ip; + unsigned long remote_ip; + unsigned long netmask_ip; + + local_ip=wan_get_ip_address(dev, WAN_LOCAL_IP); + remote_ip=wan_get_ip_address(dev, WAN_POINTOPOINT_IP); + netmask_ip=wan_get_ip_address(dev, WAN_NETMASK_IP); +#endif + memset((char*)&route,0,sizeof(struct rtentry)); -MODULE_LICENSE("GPL"); +#if 0 + if (local_ip && remote_ip && local_ip != remote_ip){ + set_sockaddr((struct sockaddr_in *) &route.rt_gateway, remote_ip, 0); + } +#endif + route.rt_dev = dev->name; + set_sockaddr((struct sockaddr_in *) &route.rt_dst, 0, 0); + set_sockaddr((struct sockaddr_in *) &route.rt_genmask, 0, 0); + route.rt_flags = 0; + + oldfs = get_fs(); + set_fs(get_ds()); + res = wp_ip_rt_ioctl(SIOCADDRT,&route); + set_fs(oldfs); + + if (res == 0){ + DEBUG_EVENT("%s: IP default route added for: %s\n", + dev->name,dev->name); + DEBUG_TX("%s: IP default route added : %u.%u.%u.%u\n", + dev->name,NIPQUAD(remote_ip)); + }else{ + DEBUG_EVENT("%s: Failed to set IP default route for: %s :Rc=%i\n", + dev->name,dev->name,res); + DEBUG_TX("%s: Failed to set IP default route : %u.%u.%u.%u :Rc=%i\n", + dev->name,NIPQUAD(remote_ip),res); + } + + return; +} + + + +#ifdef CONFIG_PRODUCT_WANPIPE_ANNEXG + +/****************************************************************** + * API,DSP,X25,LAP Layer registration + * + * Each protocol registers its functions to wanrouter.o + * which is the base module needed by all upper layers. + * This way, upper modules are not deppendent on one + * another during module load time. + * + * eg: TCP->WANPIPE->WANROUTER + * API->WANPIPE->WANROUTER + * TCP->LAPB->WANPIPE->WANROUTER + * API->LAPB->WANPIPE->WANROUTER + * TCP->X25->LAPB->WANPIPE->WANROUTER + * API->X25->LAPB->WANPIPE->WANROUTER + * API->DSP->X25->LAPB->WANPIPE->WANROUTER + * + * Any combination of above layers is possible. + * + * (WANPIPE: Frame Relay, Chdlc, PPP etc...) + * + * + */ + + +/*================================================================= + * register_wanpipe_lapb_protocol + * + * The lapb protocol layer binds its function to the wanrouter.o + * module during lapb module load, so they can be + * used by the higher layers such as x25,dsp,socket. + * + */ + + +int register_wanpipe_lapb_protocol (struct wanpipe_lapb_register_struct *lapb_reg) +{ + memcpy(&lapb_protocol,lapb_reg,sizeof(struct wanpipe_lapb_register_struct)); + REG_PROTOCOL_FUNC(lapb_protocol); + return 0; +} + +void unregister_wanpipe_lapb_protocol (void) +{ + UNREG_PROTOCOL_FUNC(lapb_protocol); + return; +} + +/*================================================================= + * register_wanpipe_x25_protocol + * + * The x25 protocol layer binds its function to the wanrouter.o + * module during x25 module load, so they can be + * used by the higher layers such as dsp and socket. + * + */ + +int register_wanpipe_x25_protocol (struct wanpipe_x25_register_struct *x25_api_reg) +{ + memcpy(&x25_protocol,x25_api_reg,sizeof(struct wanpipe_x25_register_struct)); + REG_PROTOCOL_FUNC(x25_protocol); + return 0; +} + +void unregister_wanpipe_x25_protocol (void) +{ + UNREG_PROTOCOL_FUNC(x25_protocol); + return; +} + + +/*================================================================= + * register_wanpipe_dsp_protocol + * + * The dsp protocol layer binds its function to the wanrouter.o + * module during dsp module load, so they can be + * used by the api socket. + * + */ + +int register_wanpipe_dsp_protocol (struct wanpipe_dsp_register_struct *dsp_api_reg) +{ + memcpy(&dsp_protocol, dsp_api_reg, sizeof(struct wanpipe_dsp_register_struct)); + REG_PROTOCOL_FUNC(dsp_protocol); + return 0; +} + +void unregister_wanpipe_dsp_protocol (void) +{ + UNREG_PROTOCOL_FUNC(dsp_protocol); + return; +} + +#endif + +/*================================================================= + * register_wanpipe_api_socket + * + * The api socket binds its function to the wanrouter.o + * module during af_wanpipe_api module load, so they can be + * used by lower protocols, such as x25, frame relay ... + * + */ + +int register_wanpipe_api_socket (struct wanpipe_api_register_struct *wan_api_reg) +{ + memcpy(&api_socket, wan_api_reg, sizeof(struct wanpipe_api_register_struct)); + REG_PROTOCOL_FUNC(api_socket); + ++devcnt; +#if !defined(LINUX_2_6) + MOD_INC_USE_COUNT; +#endif + return 0; +} + +void unregister_wanpipe_api_socket (void) +{ + + UNREG_PROTOCOL_FUNC(api_socket); + --devcnt; +#if !defined(LINUX_2_6) + MOD_DEC_USE_COUNT; +#endif +} + + +/*================================================================= + * register_wanpipe_fw_protocol + * + */ + +int register_wanpipe_fw_protocol (struct wanpipe_fw_register_struct *wp_fw_reg) +{ + memcpy(&wp_fw_protocol, wp_fw_reg, sizeof(struct wanpipe_fw_register_struct)); + REG_PROTOCOL_FUNC(wp_fw_protocol); + return 0; +} + +void unregister_wanpipe_fw_protocol (void) +{ + UNREG_PROTOCOL_FUNC(wp_fw_protocol); + return; +} + + + +#ifdef CONFIG_PRODUCT_WANPIPE_ANNEXG +static int wan_device_new_if_lapb (wan_device_t *wandev, wanif_conf_t *u_conf) +{ + struct wan_dev_le *devle; + wanif_conf_t *conf=NULL; + netdevice_t *dev=NULL; + netdevice_t *annexg_dev=NULL; + netdevice_t *tmp_dev; + int err=-EINVAL; + + if ((wandev->state == WAN_UNCONFIGURED) || (wandev->new_if == NULL)) + return -ENODEV; + + conf=wan_malloc(sizeof(wanif_conf_t)); + if (!conf){ + return -ENOMEM; + } + + if(copy_from_user(conf, u_conf, sizeof(wanif_conf_t))){ + err = -EFAULT; + goto wan_device_new_if_lapb_exit; + } + + if (conf->magic != ROUTER_MAGIC){ + err = -EINVAL; + goto wan_device_new_if_lapb_exit; + } + + if (!test_bit(0,&lapb_protocol.init)){ + err = -EPROTONOSUPPORT; + goto wan_device_new_if_lapb_exit; + } + + err = -EPROTONOSUPPORT; + + if (!conf->name){ + printk(KERN_INFO "wanpipe: NEW_IF lapb no interface name!\n"); + err = -EINVAL; + goto wan_device_new_if_lapb_exit; + } + + if ((tmp_dev=dev_get_by_name(conf->name)) != NULL){ + printk(KERN_INFO "%s: Device already exists!\n", + conf->name); + dev_put(tmp_dev); + err = -EEXIST; + goto wan_device_new_if_lapb_exit; + } + + printk(KERN_INFO "%s: Registering Lapb device %s -> %s\n", + wandev->name, conf->name, conf->master); + + /* Find the Frame Relay DLCI to bind to the LAPB device */ + WAN_LIST_FOREACH(devle, &wandev->dev_head, dev_link){ + //for (dev=wandev->dev; dev; dev=*(netdevice_t**)dev->priv){ + dev = WAN_DEVLE2DEV(devle); + if (dev && !strcmp(dev->name, conf->master)){ + break; + } + } + + if (devle == NULL || dev == NULL){ + printk(KERN_INFO "%s: Master device %s used by Lapb %s not found !\n", + wandev->name, conf->master,conf->name); + err = -ENODEV; + goto wan_device_new_if_lapb_exit; + } + dev = WAN_DEVLE2DEV(devle); + if (!IS_FUNC_CALL(lapb_protocol,lapb_register)){ + goto wan_device_new_if_lapb_exit; + } + + if ((err=lapb_protocol.lapb_register(dev,conf->name,wandev->name,&annexg_dev)) != 0){ + printk(KERN_INFO "%s: Failed to register Lapb Protocol\n",wandev->name); + goto wan_device_new_if_lapb_exit; + } + + if (conf->station == WANOPT_DCE){ + conf->u.lapb.mode |= 0x04; + } + + if (lapb_protocol.lapb_setparms(annexg_dev,&conf->u.lapb)){ + lapb_protocol.lapb_unregister(annexg_dev); + printk(KERN_INFO "%s: Failed to setup Lapb Protocol\n",wandev->name); + err= -EINVAL; + goto wan_device_new_if_lapb_exit; + } + + if (!wandev->bind_annexg){ + printk(KERN_INFO "%s: Device %s doesn't support ANNEXG\n", + wandev->name,dev->name); + lapb_protocol.lapb_unregister(annexg_dev); + err = -EPROTONOSUPPORT; + goto wan_device_new_if_lapb_exit; + } + + if (wandev->bind_annexg(dev, annexg_dev)){ + lapb_protocol.lapb_unregister(annexg_dev); + printk(KERN_INFO "%s: Failed to bind %s to %s\n", + wandev->name,annexg_dev->name,conf->master); + err = -EINVAL; + goto wan_device_new_if_lapb_exit; + } + +wan_device_new_if_lapb_exit: + + if (conf){ + wan_free(conf); + } + + return 0; +} + +static int wan_device_del_if_lapb(wan_device_t *wandev, netdevice_t *dev) +{ + int err; + netdevice_t *master_dev=NULL; + + if (dev->flags & IFF_UP){ + printk(KERN_INFO "%s: Failed to del interface: Device UP!\n", + dev->name); + return -EBUSY; + } + + if (wandev->un_bind_annexg){ + master_dev=wandev->un_bind_annexg(wandev,dev); + } + + if (IS_FUNC_CALL(lapb_protocol,lapb_unregister)){ + if ((err=lapb_protocol.lapb_unregister(dev)) != 0){ + printk(KERN_INFO "%s: Lapb unregister failed rc=%i\n",dev->name,err); + if (wandev->bind_annexg && master_dev){ + wandev->bind_annexg(master_dev,dev); + } + return err; + } + } + + return 0; +} + +static int wan_device_new_if_x25 (wan_device_t *wandev, wanif_conf_t *u_conf) +{ + wanif_conf_t *conf=NULL; + netdevice_t *dev=NULL; + netdevice_t *annexg_dev=NULL; + netdevice_t *tmp_dev; + int err=-EINVAL; + + if ((wandev->state == WAN_UNCONFIGURED) || (wandev->new_if == NULL)) + return -ENODEV; + + conf=wan_malloc(sizeof(wanif_conf_t)); + if (!conf){ + return -ENOMEM; + } + + if(copy_from_user(conf, u_conf, sizeof(wanif_conf_t))){ + err = -EFAULT; + goto wan_device_new_if_x25_exit; + } + + if (conf->magic != ROUTER_MAGIC){ + err = -EINVAL; + goto wan_device_new_if_x25_exit; + } + + if (!test_bit(0,&lapb_protocol.init)){ + printk(KERN_INFO "%s: Lapb protocol not initialized!\n", + wandev->name); + err = -EPROTONOSUPPORT; + goto wan_device_new_if_x25_exit; + } + + err = -EPROTONOSUPPORT; + + if (!conf->name){ + printk(KERN_INFO "wanpipe: NEW_IF x25 no interface name!\n"); + err = -EINVAL; + goto wan_device_new_if_x25_exit; + } + + if ((tmp_dev=dev_get_by_name(conf->name)) != NULL){ + printk(KERN_INFO "%s: Device already exists!\n", + conf->name); + dev_put(tmp_dev); + err = -EEXIST; + goto wan_device_new_if_x25_exit; + } + + printk(KERN_INFO "%s: Registering X25 SVC %s -> %s\n", + wandev->name, conf->name, conf->master); + + if (conf->station == WANOPT_DTE){ + conf->u.x25.dte=1; + }else{ + conf->u.x25.dte=0; + } + + if (!conf->master){ + printk(KERN_INFO "wanpipe: NEW_IF x25 no master interface name!\n"); + err = -EINVAL; + goto wan_device_new_if_x25_exit; + } + + //Find a master device for our x25 lcn + if ((dev = dev_get_by_name(conf->master)) == NULL){ + printk(KERN_INFO "%s: Master device %s used by X25 SVC %s no found!\n", + wandev->name,conf->master,conf->name); + goto wan_device_new_if_x25_exit; + } + dev_put(dev); + + if ((err=lapb_protocol.lapb_x25_register (dev,conf->name,&annexg_dev)) != 0){ + printk(KERN_INFO "%s: Failed to register x25 device %s\n", + wandev->name,conf->name); + goto wan_device_new_if_x25_exit; + } + + memcpy(&conf->u.x25.addr[0],&conf->addr[0],WAN_ADDRESS_SZ); + + if (lapb_protocol.lapb_x25_setparms(dev,annexg_dev,&conf->u.x25)){ + lapb_protocol.lapb_x25_unregister(annexg_dev); + printk(KERN_INFO "%s: Failed to setup X25 Protocol\n",wandev->name); + err = -EINVAL; + goto wan_device_new_if_x25_exit; + } + +wan_device_new_if_x25_exit: + + if (conf){ + wan_free(conf); + } + + return err; +} + + +static int wan_device_del_if_x25(wan_device_t *wandev, netdevice_t *dev) +{ + if (dev->flags & IFF_UP){ + printk(KERN_INFO "%s: Failed to del interface: Device UP!\n", + dev->name); + return -EBUSY; + } + + if (!IS_FUNC_CALL(lapb_protocol,lapb_x25_unregister)) + return 0; + + return lapb_protocol.lapb_x25_unregister(dev); +} + + +static int wan_device_new_if_dsp (wan_device_t *wandev, wanif_conf_t *u_conf) +{ + wanif_conf_t *conf=NULL; + netdevice_t *dev=NULL; + netdevice_t *annexg_dev=NULL; + netdevice_t *tmp_dev; + int err=-EINVAL; + + if ((wandev->state == WAN_UNCONFIGURED) || (wandev->new_if == NULL)) + return -ENODEV; + + conf=wan_malloc(sizeof(wanif_conf_t)); + if (!conf){ + return -ENOMEM; + } + + if (copy_from_user(conf, u_conf, sizeof(wanif_conf_t))){ + err = -EFAULT; + goto wan_device_new_if_dsp_exit; + } + + if (conf->magic != ROUTER_MAGIC){ + err = -EINVAL; + goto wan_device_new_if_dsp_exit; + } + + if (!IS_FUNC_CALL(x25_protocol,x25_dsp_register)){ + printk(KERN_INFO "%s: X25 protocol not initialized.\n",wandev->name); + err = -EPROTONOSUPPORT; + goto wan_device_new_if_dsp_exit; + } + + err = -EPROTONOSUPPORT; + + if (!conf->name){ + printk(KERN_INFO "wanpipe: NEW_IF dsp no interface name!\n"); + err= -EINVAL; + goto wan_device_new_if_dsp_exit; + } + + if ((tmp_dev=dev_get_by_name(conf->name)) != NULL){ + printk(KERN_INFO "%s: Device already exists!\n", + conf->name); + dev_put(tmp_dev); + err = -EEXIST; + goto wan_device_new_if_dsp_exit; + } + + + printk(KERN_INFO "%s: Registering DSP device %s -> %s\n", + wandev->name, conf->name, conf->master); + + if (!conf->master){ + printk(KERN_INFO "wanpipe: NEW_IF lapb no master interface name!\n"); + err = -EINVAL; + goto wan_device_new_if_dsp_exit; + } + + //Find a master device for our x25 lcn + if ((dev = dev_get_by_name(conf->master)) == NULL){ + printk(KERN_INFO "%s: Master device %s, no found for %s\n", + wandev->name, conf->master,conf->name); + goto wan_device_new_if_dsp_exit; + } + dev_put(dev); + + if ((err=x25_protocol.x25_dsp_register (dev, conf->name,&annexg_dev)) != 0){ + goto wan_device_new_if_dsp_exit; + } + + if (IS_FUNC_CALL(x25_protocol,x25_dsp_setparms)){ + if (x25_protocol.x25_dsp_setparms(dev, annexg_dev, &conf->u.dsp)){ + x25_protocol.x25_dsp_unregister(annexg_dev); + printk(KERN_INFO "%s: Failed to setup DSP Protocol\n",wandev->name); + err = -EINVAL; + goto wan_device_new_if_dsp_exit; + } + } + +wan_device_new_if_dsp_exit: + + if (conf){ + wan_free(conf); + } + + return err; +} + + +static int wan_device_del_if_dsp(wan_device_t *wandev, netdevice_t *dev) +{ + printk(KERN_INFO "%s: Unregistering DSP Device %s\n", + wandev->name, dev->name); + + if (!IS_FUNC_CALL(x25_protocol,x25_dsp_unregister)){ + return 0; + } + + return x25_protocol.x25_dsp_unregister(dev); +} + + +/* CONFIG_PRODUCT_WANPIPE_ANNEXG */ +#endif + + + +#if 1 + +int register_wanpipe_lip_protocol (wplip_reg_t *lip_reg) +{ + memcpy(&wplip_protocol,lip_reg,sizeof(wplip_reg_t)); + REG_PROTOCOL_FUNC(wplip_protocol); + return 0; +} + +void unregister_wanpipe_lip_protocol (void) +{ + UNREG_PROTOCOL_FUNC(wplip_protocol); + return; +} + +static int wan_device_unreg_lip(netdevice_t *dev) +{ + void *lip_link = wan_get_lip_ptr(dev); + int err; + + if (!IS_FUNC_CALL(wplip_protocol,wplip_if_unreg)) + return 0; + + if (lip_link){ + err=wplip_protocol.wplip_unreg(lip_link); + if (err){ + return err; + } + wan_set_lip_ptr(dev,NULL); + wan_set_lip_prot(dev,0); + } + return 0; +} + +static int wan_device_new_if_lip (wan_device_t *wandev, wanif_conf_t *u_conf) +{ + wanif_conf_t *conf=NULL; + netdevice_t *dev=NULL; + netdevice_t *tmp_dev; + void *lip_link; + int err=-EINVAL, init_if=0; + + if ((wandev->state == WAN_UNCONFIGURED) || (wandev->new_if == NULL)) + return -ENODEV; + + conf=wan_malloc(sizeof(wanif_conf_t)); + if (!conf){ + return -ENOMEM; + } + + if(copy_from_user(conf, u_conf, sizeof(wanif_conf_t))){ + err = -EFAULT; + goto wan_device_new_if_lip_exit; + } + + if (conf->magic != ROUTER_MAGIC){ + err = -EINVAL; + goto wan_device_new_if_lip_exit; + } + + if (!test_bit(0,&wplip_protocol.init)){ + printk(KERN_INFO "%s: LIP protocol not initialized!\n", + wandev->name); + err = -EPROTONOSUPPORT; + goto wan_device_new_if_lip_exit; + } + + + err = -EPROTONOSUPPORT; + + if (!conf->name){ + printk(KERN_INFO "wanpipe: NEW_IF LIP no interface name!\n"); + err = -EINVAL; + goto wan_device_new_if_lip_exit; + } + + if ((tmp_dev=dev_get_by_name(conf->name)) != NULL){ + printk(KERN_INFO "%s: Device already exists!\n", + conf->name); + dev_put(tmp_dev); + err = -EEXIST; + goto wan_device_new_if_lip_exit; + } + + DEBUG_EVENT("%s: Registering LIP %s -> %s\n", + wandev->name, conf->name, conf->master); + + if (!conf->master){ + printk(KERN_INFO "wanpipe: NEW_IF LIP no master interface name!\n"); + err = -EINVAL; + goto wan_device_new_if_lip_exit; + } + + //Find a master device lip device + if ((dev = dev_get_by_name(conf->master)) == NULL){ + printk(KERN_INFO "%s: Master device %s used by LIP %s no found!\n", + wandev->name,conf->master,conf->name); + goto wan_device_new_if_lip_exit; + } + dev_put(dev); + + lip_link = (wplip_reg_t*)wan_get_lip_ptr(dev); + if (!lip_link){ + + err=wplip_protocol.wplip_register(&lip_link,conf,dev->name); + if (err!=0){ + DEBUG_EVENT("%s: Failed to register LIP Link device %s\n", + wandev->name,conf->name); + goto wan_device_new_if_lip_exit; + } + + + err=wplip_protocol.wplip_bind_link(lip_link,dev); + if (err!=0){ + wplip_protocol.wplip_unreg(lip_link); + wan_set_lip_ptr(dev,NULL); + wan_set_lip_prot(dev,0); + + DEBUG_EVENT("%s: Failed to bind master dev(%s) to LIP Link device\n", + wandev->name,dev->name); + goto wan_device_new_if_lip_exit; + } + + wan_set_lip_ptr(dev,lip_link); + wan_set_lip_prot(dev,conf->protocol); + init_if=1; + } + + err=wplip_protocol.wplip_if_reg(lip_link,conf->name,conf); + if (err != 0){ + printk(KERN_INFO "%s: Failed to register LIP device %s\n", + wandev->name,conf->name); + + if (init_if){ + wplip_protocol.wplip_unreg(lip_link); + wan_set_lip_ptr(dev,NULL); + wan_set_lip_prot(dev,0); + } + + goto wan_device_new_if_lip_exit; + } + +wan_device_new_if_lip_exit: + + if (conf){ + wan_free(conf); + } + + return err; +} + +static int wan_device_del_if_lip(wan_device_t *wandev, netdevice_t *dev) +{ + int err; + + if (dev->flags & IFF_UP){ + printk(KERN_INFO "%s: Failed to del interface: Device UP!\n", + dev->name); + return -EBUSY; + } + + if (!IS_FUNC_CALL(wplip_protocol,wplip_if_unreg)) + return 0; + + err=wan_device_unreg_lip(dev); + if (err){ + return err; + } + + return wplip_protocol.wplip_if_unreg(dev); +} + + +#endif + +#if defined(CONFIG_WANPIPE_HWEC) +int register_wanec_iface (wanec_iface_t *iface) +{ + memcpy(&wanec_iface, iface, sizeof(wanec_iface_t)); + REG_PROTOCOL_FUNC(wanec_iface); + return 0; +} + +void unregister_wanec_iface (void) +{ + UNREG_PROTOCOL_FUNC(wanec_iface); + return; +} + +void *wanpipe_ec_register(void *pcard, int max_channels) +{ + if (wanec_iface.reg){ + return wanec_iface.reg(pcard, max_channels); + } + return NULL; +} +int wanpipe_ec_unregister(void *arg, void *pcard) +{ + if (wanec_iface.unreg){ + return wanec_iface.unreg(arg, pcard); + } + return -EINVAL; +} + +int wanpipe_ec_event_ctrl(void *arg, void *pcard, wan_event_ctrl_t *event_ctrl) +{ + if (wanec_iface.event_ctrl){ + return wanec_iface.event_ctrl(arg, pcard, event_ctrl); + } + return 0; +} + +int wanpipe_ec_isr(void *arg, void *pcard) +{ + if (wanec_iface.isr){ + return wanec_iface.isr(arg, pcard); + } + return 0; +} + +int wanpipe_ec_poll(void *arg, void *pcard) +{ + if (wanec_iface.poll){ + return wanec_iface.poll(arg, pcard); + } + return -EINVAL; +} +#endif + +void wan_skb_destructor (struct sk_buff *skb) +{ + if (skb->dev){ + struct net_device *dev=skb->dev; + atomic_dec(&(dev)->refcnt); + //printk(KERN_INFO "%s: Skb destructor: put dev: refcnt=%i\n", + // dev->name,atomic_read(&dev->refcnt)); + } +} + +/** + * @path: pathname for the application + * @argv: null-terminated argument list + * @envp: null-terminated environment list + * + * Runs a user-space application. The application is started asynchronously. It + * runs as a child of keventd. It runs with full root capabilities. keventd silently + * reaps the child when it exits. + * + * Must be called from process context. Returns zero on success, else a negative + * error code. + */ + +char wanrouter_path[256] = "/usr/sbin/wanrouter"; + +int wan_run_wanrouter(char * hwdevname, char *devname, char *action) +{ + char *argv [3], **envp; + char wan_action[20], wan_device[20], wan_if[20]; + int i = 0, value; + + + if (!wanrouter_path [0]){ + return -ENODEV; + } + + if (in_interrupt ()) { + DEBUG_EVENT("%s: Error: Interrupt mode! Exiting...", + __FUNCTION__); + return -EINVAL; + } + + if (!current->fs->root) { + /* statically linked USB is initted rather early */ + DEBUG_EVENT ("%s: Error: no FS yet",__FUNCTION__); + return -ENODEV; + } + + if (!(envp = (char **) kmalloc (20 * sizeof (char *), GFP_KERNEL))) { + DEBUG_EVENT ("%s: Error: no memory!",__FUNCTION__); + return -ENOMEM; + } + + /* only one standardized param to hotplug command: type */ + argv [0] = wanrouter_path; + argv [1] = "script"; + argv [2] = 0; + + /* minimal command environment */ + envp [i++] = "HOME=/"; + envp [i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin"; + +#if 0 + /* hint that policy agent should enter no-stdout debug mode */ + envp [i++] = "DEBUG=kernel"; +#endif + + sprintf(wan_action, "WAN_ACTION=start"); + envp[i++] = wan_action; + + if (hwdevname){ + sprintf(wan_device, "WAN_DEVICE=%s",hwdevname); + envp[i++] = wan_device; + + if (devname){ + sprintf(wan_if, "WAN_INTERFACE=%s", devname); + envp[i++] = wan_if; + } + } + + envp [i++] = 0; + + /* NOTE: user mode daemons can call the agents too */ + + DEBUG_EVENT ("%s: Call User Mode %s %s",__FUNCTION__, argv [0], argv[1]); + value = wan_call_usermodehelper (argv [0], argv, envp); + kfree (envp); + + if (value != 0){ + DEBUG_EVENT ("%s: Error Call User Mode failed 0x%x",__FUNCTION__,value); + } + + return value; +} + +extern struct proc_dir_entry *proc_router; +EXPORT_SYMBOL(proc_router); +extern int proc_add_line(struct seq_file* m, char* frm, ...); +EXPORT_SYMBOL(proc_add_line); + +EXPORT_SYMBOL(register_wan_device); +EXPORT_SYMBOL(unregister_wan_device); +EXPORT_SYMBOL(wanrouter_encapsulate); +EXPORT_SYMBOL(wanrouter_type_trans); + + +/* From wanproc.c */ +EXPORT_SYMBOL(wanrouter_proc_add_protocol); +EXPORT_SYMBOL(wanrouter_proc_delete_protocol); +EXPORT_SYMBOL(wanrouter_proc_add_interface); +EXPORT_SYMBOL(wanrouter_proc_delete_interface); + + +EXPORT_SYMBOL(wan_get_ip_address); +EXPORT_SYMBOL(wan_set_ip_address); +EXPORT_SYMBOL(wan_add_gateway); +EXPORT_SYMBOL(wan_run_wanrouter); + + +#ifdef CONFIG_PRODUCT_WANPIPE_ANNEXG +/* From waniface.c */ +EXPORT_SYMBOL(register_wanpipe_lapb_protocol); +EXPORT_SYMBOL(unregister_wanpipe_lapb_protocol); +EXPORT_SYMBOL(lapb_protocol); + +EXPORT_SYMBOL(register_wanpipe_x25_protocol); +EXPORT_SYMBOL(unregister_wanpipe_x25_protocol); + +EXPORT_SYMBOL(register_wanpipe_dsp_protocol); +EXPORT_SYMBOL(unregister_wanpipe_dsp_protocol); +#endif + +EXPORT_SYMBOL(register_wanpipe_lip_protocol); +EXPORT_SYMBOL(unregister_wanpipe_lip_protocol); + +EXPORT_SYMBOL(wanpipe_lip_rx); +EXPORT_SYMBOL(wanpipe_lip_connect); +EXPORT_SYMBOL(wanpipe_lip_disconnect); +EXPORT_SYMBOL(wanpipe_lip_kick); + +EXPORT_SYMBOL(wan_skb_destructor); + + +EXPORT_SYMBOL(register_wanpipe_api_socket); +EXPORT_SYMBOL(unregister_wanpipe_api_socket); + + +EXPORT_SYMBOL(register_wanpipe_fw_protocol); +EXPORT_SYMBOL(unregister_wanpipe_fw_protocol); + +#if defined(CONFIG_WANPIPE_HWEC) +EXPORT_SYMBOL(register_wanec_iface); +EXPORT_SYMBOL(unregister_wanec_iface); +EXPORT_SYMBOL(wanpipe_ec_register); +EXPORT_SYMBOL(wanpipe_ec_unregister); +EXPORT_SYMBOL(wanpipe_ec_event_ctrl); +EXPORT_SYMBOL(wanpipe_ec_isr); +EXPORT_SYMBOL(wanpipe_ec_poll); +#endif /* * End diff -Nur linux.org/net/wanrouter/wanproc.c linux-2.6.17/net/wanrouter/wanproc.c --- linux.org/net/wanrouter/wanproc.c 2006-06-18 01:49:35.000000000 +0000 +++ linux-2.6.17/net/wanrouter/wanproc.c 2006-08-30 10:07:16.000000000 +0000 @@ -4,15 +4,20 @@ * This module is completely hardware-independent and provides * access to the router using Linux /proc filesystem. * -* Author: Gideon Hack +* Author: Gideon Hack +* Nenad Corbic * -* Copyright: (c) 1995-1999 Sangoma Technologies Inc. +* Copyright: (c) 1995-2004 Sangoma Technologies Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * ============================================================================ +* Aug 20, 2001 Alex Feldman Support SNMP. +* May 25, 2001 Alex Feldman Added T1/E1 support (TE1). +* May 23, 2001 Nenad Corbic Bug fix supplied by Akash Jain. If the user +* copy fails free up allocated memory. * Jun 02, 1999 Gideon Hack Updates for Linux 2.2.X kernels. * Jun 29, 1997 Alan Cox Merged with 1.0.3 vendor code * Jan 29, 1997 Gene Kozin v1.0.1. Implemented /proc read routines @@ -20,38 +25,199 @@ * Dec 13, 1996 Gene Kozin Initial version (based on Sangoma's WANPIPE) *****************************************************************************/ -#include -#include /* __initfunc et al. */ -#include /* offsetof(), etc. */ -#include /* return codes */ -#include -#include -#include /* WAN router API definitions */ -#include -#include +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) +# include +# include +# include +# include +# include +# include /* WAN router API definitions */ +# include +# include +# include +# define STATIC +# define CONFIG_PROC_FS +#else +# include +# include +# include +# include /* WAN router API definitions */ +# include +# include +# include +# define STATIC static +#endif + +#if defined(LINUX_2_1) || defined(LINUX_2_4) +# ifndef proc_mkdir +# define proc_mkdir(buf, usbdir) create_proc_entry(buf, S_IFDIR, usbdir) +# endif +#endif -#include +#if defined(LINUX_2_6) +# define M_STOP_CNT(m) NULL +#else +# define M_STOP_CNT(m) &m->stop_cnt +#endif -#define PROC_STATS_FORMAT "%30s: %12lu\n" +#define PROC_STATS_1_FORMAT "%25s: %10lu\n" +#define PROC_STATS_2_FORMAT "%25s: %10lu %25s: %10lu\n" +#define PROC_STATS_ALARM_FORMAT "%25s: %10s %25s: %10s\n" +#define PROC_STATS_STR_FORMAT "%25s: %10s\n" +#define PROC_STATS_PMON_FORMAT "%25s: %10lu %25s: %10lu\n" /****** Defines and Macros **************************************************/ -#define PROT_DECODE(prot) ((prot == WANCONFIG_FR) ? " FR" :\ - (prot == WANCONFIG_X25) ? " X25" : \ - (prot == WANCONFIG_PPP) ? " PPP" : \ - (prot == WANCONFIG_CHDLC) ? " CHDLC": \ - (prot == WANCONFIG_MPPP) ? " MPPP" : \ - " Unknown" ) +#ifndef wp_min +#define wp_min(a,b) (((a)<(b))?(a):(b)) +#endif +#ifndef wp_max +#define wp_max(a,b) (((a)>(b))?(a):(b)) +#endif + +#define PROC_BUFSZ 4000 /* buffer size for printing proc info */ +#define PROT_UNKNOWN "Unknown" +#define PROT_DECODE(prot,cap) ((prot == WANCONFIG_FR) ? ((cap)?"FR":"fr") :\ + (prot == WANCONFIG_MFR) ? ((cap)?"FR":"fr") : \ + (prot == WANCONFIG_X25) ? ((cap)?"X25":"x25") : \ + (prot == WANCONFIG_PPP) ? ((cap)?"PPP":"ppp") : \ + (prot == WANCONFIG_CHDLC) ? ((cap)?"CHDLC":"chdlc") :\ + (prot == WANCONFIG_ADSL) ? ((cap)?"ADSL":"adsl") :\ + (prot == WANCONFIG_MPPP) ? ((cap)?"MPPP":"mppp") : \ + (prot == WANCONFIG_SDLC) ? ((cap)?"SDLC":"sdlc") : \ + (prot == WANCONFIG_ATM) ? ((cap)?"ATM":"atm") : \ ++ (prot == WANCONFIG_AFT) ? ((cap)?"AFT HDLC":"aft hdlc") : \ ++ (prot == WANCONFIG_AFT_TE1) ? ((cap)?"AFT HDLC":"aft hdlc") : \ ++ (prot == WANCONFIG_AFT_TE3) ? ((cap)?"AFT HDLC":"aft hdlc") : \ + PROT_UNKNOWN ) + +#define CARD_DECODE(wandev) ((wandev->card_type == WANOPT_ADSL) ? "ADSL" : \ + (wandev->card_type == WANOPT_S50X) ? "S508" : \ + (wandev->fe_iface.get_fe_media_string) ? \ + wandev->fe_iface.get_fe_media_string() : "S514") + + +/****** Data Types **********************************************************/ +#if defined(__LINUX__) +typedef struct wan_stat_entry +{ + struct wan_stat_entry *next; + char *description; /* description string */ + void *data; /* -> data */ + unsigned data_type; /* data type */ +} wan_stat_entry_t; + +typedef struct wan_proc_entry +{ + struct proc_dir_entry *protocol_entry; + int count; +} wan_proc_entry_t; +#endif /****** Function Prototypes *************************************************/ -#ifdef CONFIG_PROC_FS +#ifdef WAN_DEBUG_MEM +extern atomic_t wan_debug_mem; +#endif + +extern struct wan_devlist_ wan_devlist; + +#if defined(CONFIG_PROC_FS) + +#define CONF_PCI_FRM "%-12s| %-13s| %-9s| %-4u| %-8u| %-5u| %-4s| %-10u|\n" +#define CONF_ISA_FRM "%-12s| %-13s| %-9s| %-4u| 0x%-6X| %-5u| %-4s| %-10u|\n" +#define MAP_FRM "%-12s| %-50s\n" +#define INTERFACES_FRM "%-15s| %-12s| %-6u| %-18s|\n" +#define PROC_FR_FRM "%-30s\n" +#define PROC_FR_CFG_FRM "%-15s| %-12s| %-5u|\n" +#define PROC_FR_STAT_FRM "%-15s| %-12s| %-14s|\n" + +#ifdef CONFIG_PRODUCT_WANPIPE_ANNEXG + #define STAT_FRM "%-12s| %-9s| %-8s| %-14s| %-3u | %-3u | %-3u | %-3u | %-3u | %-3u | %-3u | %-3u | %-3u | %-3u |\n" +#else + #define STAT_FRM "%-12s| %-9s| %-8s| %-14s|\n" +#endif + + +/* NEW_PROC */ +/* Strings */ +static char conf_hdr[] = + "Device name | Protocol Map | Adapter | IRQ | Slot/IO " + "| If's | CLK | Baud rate |\n"; +#if defined(__LINUX__) +static char map_hdr[] = + "Device name | Protocol Map \n"; +#endif + +#ifdef CONFIG_PRODUCT_WANPIPE_ANNEXG +static char stat_hdr[] = + "Device name | Protocol | Station | Status | Wanpipe | Lapb | X25 Link | X25 Svc | Dsp |\n"; +#else +static char stat_hdr[] = + "Device name | Protocol | Station | Status |\n"; +#endif + +static char interfaces_hdr[] = + "Interface name | Device name | Media | Operational State |\n"; + +#if defined(__LINUX__) + +/* Proc filesystem interface */ +#ifndef LINUX_2_6 +static int router_proc_perms(struct inode *, int); +static ssize_t router_proc_read(struct file*, char*, size_t,loff_t*); +static ssize_t router_proc_write(struct file*, const char*, size_t,loff_t*); +#endif + +/* Methods for preparing data for reading proc entries */ + +#if defined(LINUX_2_6) +static int config_get_info(struct seq_file *m, void *v); +static int status_get_info(struct seq_file *m, void *v); +static int probe_get_info(struct seq_file *m, void *v); +static int wandev_get_info(struct seq_file *m, void *v); + +static int map_get_info(struct seq_file *m, void *v); +static int interfaces_get_info(struct seq_file *m, void *v); + +static int get_dev_config_info(struct seq_file *m, void *v); +static int get_dev_status_info(struct seq_file *m, void *v); + +static int wandev_mapdir_get_info(struct seq_file *m, void *v); + +#elif defined(LINUX_2_4) +static int config_get_info(char* buf, char** start, off_t offs, int len); +static int status_get_info(char* buf, char** start, off_t offs, int len); +static int probe_get_info(char* buf, char** start, off_t offs, int len); +static int wandev_get_info(char* buf, char** start, off_t offs, int len); + +static int map_get_info(char* buf, char** start, off_t offs, int len); +static int interfaces_get_info(char* buf, char** start, off_t offs, int len); + +static int get_dev_config_info(char* buf, char** start, off_t offs, int len); +static int get_dev_status_info(char* buf, char** start, off_t offs, int len); + +static int wandev_mapdir_get_info(char* buf, char** start, off_t offs, int len); + +#else +static int config_get_info(char* buf, char** start, off_t offs, int len, int dummy); +static int status_get_info(char* buf, char** start, off_t offs, int len, int dummy); +static int probe_get_info(char* buf, char** start, off_t offs, int len, int dummy); +static int wandev_get_info(char* buf, char** start, off_t offs, int len, int dummy); + +static int map_get_info(char* buf, char** start, off_t offs, int len, int dummy); +static int interfaces_get_info(char* buf, char** start, off_t offs, int len, int dummy); + +static int get_dev_config_info(char* buf, char** start, off_t offs, int len, int dummy); +static int get_dev_status_info(char* buf, char** start, off_t offs, int len, int dummy); +#endif + /* Miscellaneous */ /* * Structures for interfacing with the /proc filesystem. - * Router creates its own directory /proc/net/router with the folowing + * Router creates its own directory /proc/net/wanrouter with the folowing * entries: * config device configuration * status global device statistics @@ -59,323 +225,1555 @@ */ /* - * Generic /proc/net/router/ file and inode operations - */ - -/* - * /proc/net/router + * Generic /proc/net/wanrouter/ file and inode operations */ -static struct proc_dir_entry *proc_router; -/* Strings */ -/* - * Interface functions - */ +struct proc_dir_entry *proc_router; +static struct proc_dir_entry *map_dir; -/****** Proc filesystem entry points ****************************************/ +#ifdef LINUX_2_6 -/* - * Iterator - */ -static void *r_start(struct seq_file *m, loff_t *pos) +static int config_open(struct inode *inode, struct file *file) { - struct wan_device *wandev; - loff_t l = *pos; - - lock_kernel(); - if (!l--) - return SEQ_START_TOKEN; - for (wandev = wanrouter_router_devlist; l-- && wandev; - wandev = wandev->next) - ; - return wandev; + return single_open(file, config_get_info, WP_PDE(inode)->data); } -static void *r_next(struct seq_file *m, void *v, loff_t *pos) +static int status_open(struct inode *inode, struct file *file) { - struct wan_device *wandev = v; - (*pos)++; - return (v == SEQ_START_TOKEN) ? wanrouter_router_devlist : wandev->next; + return single_open(file, status_get_info, WP_PDE(inode)->data); } -static void r_stop(struct seq_file *m, void *v) -{ - unlock_kernel(); -} +static struct file_operations config_fops = { + .owner = THIS_MODULE, + .open = config_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; -static int config_show(struct seq_file *m, void *v) +static struct file_operations status_fops = { + .owner = THIS_MODULE, + .open = status_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +static int wandev_open(struct inode *inode, struct file *file) { - struct wan_device *p = v; - if (v == SEQ_START_TOKEN) { - seq_puts(m, "Device name | port |IRQ|DMA| mem.addr |" - "mem.size|option1|option2|option3|option4\n"); - return 0; - } - if (!p->state) - return 0; - seq_printf(m, "%-15s|0x%-4X|%3u|%3u| 0x%-8lX |0x%-6X|%7u|%7u|%7u|%7u\n", - p->name, p->ioport, p->irq, p->dma, p->maddr, p->msize, - p->hw_opt[0], p->hw_opt[1], p->hw_opt[2], p->hw_opt[3]); - return 0; + return single_open(file, wandev_get_info, WP_PDE(inode)->data); } -static int status_show(struct seq_file *m, void *v) +static struct file_operations wandev_fops = { + .owner = THIS_MODULE, + .open = wandev_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .ioctl = wanrouter_ioctl, +}; + +static int wp_hwprobe_open(struct inode *inode, struct file *file) { - struct wan_device *p = v; - if (v == SEQ_START_TOKEN) { - seq_puts(m, "Device name |protocol|station|interface|" - "clocking|baud rate| MTU |ndev|link state\n"); - return 0; - } - if (!p->state) - return 0; - seq_printf(m, "%-15s|%-8s| %-7s| %-9s|%-8s|%9u|%5u|%3u |", - p->name, - PROT_DECODE(p->config_id), - p->config_id == WANCONFIG_FR ? - (p->station ? "Node" : "CPE") : - (p->config_id == WANCONFIG_X25 ? - (p->station ? "DCE" : "DTE") : - ("N/A")), - p->interface ? "V.35" : "RS-232", - p->clocking ? "internal" : "external", - p->bps, - p->mtu, - p->ndev); - - switch (p->state) { - case WAN_UNCONFIGURED: - seq_printf(m, "%-12s\n", "unconfigured"); - break; - case WAN_DISCONNECTED: - seq_printf(m, "%-12s\n", "disconnected"); - break; - case WAN_CONNECTING: - seq_printf(m, "%-12s\n", "connecting"); - break; - case WAN_CONNECTED: - seq_printf(m, "%-12s\n", "connected"); - break; - default: - seq_printf(m, "%-12s\n", "invalid"); - break; - } - return 0; + return single_open(file, probe_get_info, WP_PDE(inode)->data); } -static struct seq_operations config_op = { - .start = r_start, - .next = r_next, - .stop = r_stop, - .show = config_show, -}; - -static struct seq_operations status_op = { - .start = r_start, - .next = r_next, - .stop = r_stop, - .show = status_show, +static struct file_operations wp_hwprobe_fops = { + .owner = THIS_MODULE, + .open = wp_hwprobe_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, }; -static int config_open(struct inode *inode, struct file *file) +static int wp_map_open(struct inode *inode, struct file *file) { - return seq_open(file, &config_op); + return single_open(file, map_get_info, WP_PDE(inode)->data); } -static int status_open(struct inode *inode, struct file *file) +static struct file_operations wp_map_fops = { + .owner = THIS_MODULE, + .open = wp_map_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int wp_iface_open(struct inode *inode, struct file *file) { - return seq_open(file, &status_op); + return single_open(file, interfaces_get_info, WP_PDE(inode)->data); } -static struct file_operations config_fops = { +static struct file_operations wp_iface_fops = { .owner = THIS_MODULE, - .open = config_open, + .open = wp_iface_open, .read = seq_read, .llseek = seq_lseek, - .release = seq_release, + .release = single_release, }; -static struct file_operations status_fops = { +static int wandev_mapdir_open(struct inode *inode, struct file *file) +{ + return single_open(file, wandev_mapdir_get_info, WP_PDE(inode)->data); +} + +static struct file_operations wandev_mapdir_fops = { .owner = THIS_MODULE, - .open = status_open, + .open = wandev_mapdir_open, .read = seq_read, .llseek = seq_lseek, - .release = seq_release, + .release = single_release, }; -static int wandev_show(struct seq_file *m, void *v) +static int wp_get_dev_config_open(struct inode *inode, struct file *file) { - struct wan_device *wandev = m->private; + return single_open(file, get_dev_config_info, WP_PDE(inode)->data); +} - if (wandev->magic != ROUTER_MAGIC) - return 0; +static struct file_operations wp_get_dev_config_fops = { + .owner = THIS_MODULE, + .open = wp_get_dev_config_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; - if (!wandev->state) { - seq_puts(m, "device is not configured!\n"); - return 0; - } +static int wp_get_dev_status_open(struct inode *inode, struct file *file) +{ + return single_open(file, get_dev_status_info, WP_PDE(inode)->data); +} - /* Update device statistics */ - if (wandev->update) { - int err = wandev->update(wandev); - if (err == -EAGAIN) { - seq_puts(m, "Device is busy!\n"); - return 0; - } - if (err) { - seq_puts(m, "Device is not configured!\n"); - return 0; - } - } +static struct file_operations wp_get_dev_status_fops = { + .owner = THIS_MODULE, + .open = wp_get_dev_status_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; - seq_printf(m, PROC_STATS_FORMAT, - "total packets received", wandev->stats.rx_packets); - seq_printf(m, PROC_STATS_FORMAT, - "total packets transmitted", wandev->stats.tx_packets); - seq_printf(m, PROC_STATS_FORMAT, - "total bytes received", wandev->stats.rx_bytes); - seq_printf(m, PROC_STATS_FORMAT, - "total bytes transmitted", wandev->stats.tx_bytes); - seq_printf(m, PROC_STATS_FORMAT, - "bad packets received", wandev->stats.rx_errors); - seq_printf(m, PROC_STATS_FORMAT, - "packet transmit problems", wandev->stats.tx_errors); - seq_printf(m, PROC_STATS_FORMAT, - "received frames dropped", wandev->stats.rx_dropped); - seq_printf(m, PROC_STATS_FORMAT, - "transmit frames dropped", wandev->stats.tx_dropped); - seq_printf(m, PROC_STATS_FORMAT, - "multicast packets received", wandev->stats.multicast); - seq_printf(m, PROC_STATS_FORMAT, - "transmit collisions", wandev->stats.collisions); - seq_printf(m, PROC_STATS_FORMAT, - "receive length errors", wandev->stats.rx_length_errors); - seq_printf(m, PROC_STATS_FORMAT, - "receiver overrun errors", wandev->stats.rx_over_errors); - seq_printf(m, PROC_STATS_FORMAT, - "CRC errors", wandev->stats.rx_crc_errors); - seq_printf(m, PROC_STATS_FORMAT, - "frame format errors (aborts)", wandev->stats.rx_frame_errors); - seq_printf(m, PROC_STATS_FORMAT, - "receiver fifo overrun", wandev->stats.rx_fifo_errors); - seq_printf(m, PROC_STATS_FORMAT, - "receiver missed packet", wandev->stats.rx_missed_errors); - seq_printf(m, PROC_STATS_FORMAT, - "aborted frames transmitted", wandev->stats.tx_aborted_errors); - return 0; -} -static int wandev_open(struct inode *inode, struct file *file) +#if 0 +static int wp_prot_dev_config_open(struct inode *inode, struct file *file) { - return single_open(file, wandev_show, PDE(inode)->data); + return 0; + //return single_open(file, get_dev_status_info, WP_PDE(inode)->data); } -static struct file_operations wandev_fops = { +static struct file_operations wp_prot_dev_config_fops = { .owner = THIS_MODULE, - .open = wandev_open, + .open = wp_prot_dev_config_open, .read = seq_read, .llseek = seq_lseek, .release = single_release, - .ioctl = wanrouter_ioctl, }; +#endif -/* - * Initialize router proc interface. - */ +#elif defined(LINUX_2_4) -int __init wanrouter_proc_init(void) +static struct file_operations router_fops = { - struct proc_dir_entry *p; - proc_router = proc_mkdir(ROUTER_NAME, proc_net); - if (!proc_router) - goto fail; + read: router_proc_read, + write: router_proc_write, +}; - p = create_proc_entry("config", S_IRUGO, proc_router); - if (!p) - goto fail_config; - p->proc_fops = &config_fops; - p = create_proc_entry("status", S_IRUGO, proc_router); - if (!p) - goto fail_stat; - p->proc_fops = &status_fops; - return 0; -fail_stat: - remove_proc_entry("config", proc_router); -fail_config: - remove_proc_entry(ROUTER_NAME, proc_net); -fail: - return -ENOMEM; -} +static struct inode_operations router_inode = +{ + permission: router_proc_perms, +}; /* - * Clean up router proc interface. + * /proc/net/wanrouter/ file operations */ -void wanrouter_proc_cleanup(void) +static struct file_operations wandev_fops = { - remove_proc_entry("config", proc_router); - remove_proc_entry("status", proc_router); - remove_proc_entry(ROUTER_NAME, proc_net); -} + read: router_proc_read, + ioctl: wanrouter_ioctl, +}; /* - * Add directory entry for WAN device. + * /proc/net/wanrouter */ -int wanrouter_proc_add(struct wan_device* wandev) + +#else + +static struct file_operations router_fops = { - if (wandev->magic != ROUTER_MAGIC) - return -EINVAL; + NULL, /* lseek */ + router_proc_read, /* read */ + router_proc_write, /* write */ + NULL, /* readdir */ + NULL, /* select */ + NULL, /* ioctl */ + NULL, /* mmap */ + NULL, /* no special open code */ + NULL, /* flush */ + NULL, /* no special release code */ + NULL /* can't fsync */ +}; + +static struct inode_operations router_inode = +{ + &router_fops, + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* follow link */ + NULL, /* readlink */ + NULL, /* readpage */ + NULL, /* writepage */ + NULL, /* bmap */ + NULL, /* truncate */ + router_proc_perms +}; + + +static struct file_operations wandev_fops = +{ + NULL, /* lseek */ + router_proc_read, /* read */ + NULL, /* write */ + NULL, /* readdir */ + NULL, /* select */ + wanrouter_ioctl, /* ioctl */ + NULL, /* mmap */ + NULL, /* no special open code */ + NULL, /* flush */ + NULL, /* no special release code */ + NULL /* can't fsync */ +}; + +static struct inode_operations wandev_inode = +{ + &wandev_fops, + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + NULL, /* readpage */ + NULL, /* writepage */ + NULL, /* bmap */ + NULL, /* truncate */ + router_proc_perms +}; + +#endif - wandev->dent = create_proc_entry(wandev->name, S_IRUGO, proc_router); - if (!wandev->dent) - return -ENOMEM; - wandev->dent->proc_fops = &wandev_fops; - wandev->dent->data = wandev; - return 0; -} /* - * Delete directory entry for WAN device. + * /proc/net/wanrouter/ */ -int wanrouter_proc_delete(struct wan_device* wandev) -{ - if (wandev->magic != ROUTER_MAGIC) - return -EINVAL; - remove_proc_entry(wandev->name, proc_router); - return 0; -} +wan_proc_entry_t proc_router_fr; +wan_proc_entry_t proc_router_chdlc; +wan_proc_entry_t proc_router_ppp; +wan_proc_entry_t proc_router_x25; +wan_proc_entry_t proc_router_mppp; -#else +#endif /* __LINUX__ */ /* - * No /proc - output stubs + * Interface functions */ -int __init wanrouter_proc_init(void) +/* + * Prepare data for reading 'Config' entry. + * Return length of data. + */ +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(LINUX_2_4) +STATIC int config_get_info(char* buf, char** start, off_t offs, int len) +#else +#if defined(LINUX_2_6) +static int config_get_info(struct seq_file *m, void *v) +#elif defined(LINUX_2_4) +static int config_get_info(char* buf, char** start, off_t offs, int len) +#else +static int config_get_info(char* buf, char** start, off_t offs, int len, int dummy) +#endif +#endif { - return 0; -} + wan_device_t* wandev = NULL; + PROC_ADD_DECL(m); + PROC_ADD_INIT(m, buf, offs, len); + + PROC_ADD_LINE(m, conf_hdr); + WAN_LIST_FOREACH(wandev, &wan_devlist, next){ + /*for (wandev = router_devlist; wandev; wandev = wandev->next){*/ + sdla_t* card = (sdla_t*)wandev->private; + u16 arg = 0; + + if (!wandev->state) continue; + + if (card && card->hw_iface.getcfg){ + card->hw_iface.getcfg(card->hw, + (wandev->card_type==WANOPT_S50X) ? + SDLA_IOPORT : SDLA_SLOT, + &arg); + } + if (wandev->state){ + PROC_ADD_LINE(m , + (wandev->card_type==WANOPT_S50X)?CONF_ISA_FRM:CONF_PCI_FRM, + wandev->name, + "N/A", /* FIXME */ + SDLA_DECODE_CARDTYPE(wandev->card_type), + wandev->irq, + arg, + wandev->ndev, + CLK_DECODE(wandev->clocking), + wandev->bps); + } + } -void wanrouter_proc_cleanup(void) -{ + PROC_ADD_RET(m); } -int wanrouter_proc_add(struct wan_device *wandev) -{ - return 0; -} -int wanrouter_proc_delete(struct wan_device *wandev) +/* + * Prepare data for reading 'Status' entry. + * Return length of data. + */ + +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(LINUX_2_4) +STATIC int status_get_info(char* buf, char** start, off_t offs, int len) +#else +#if defined(LINUX_2_6) +static int status_get_info(struct seq_file *m, void *v) +#elif defined(LINUX_2_4) +static int status_get_info(char* buf, char** start, off_t offs, int len) +#else +static int status_get_info(char* buf, char** start, off_t offs, int len, int dummy) +#endif +#endif { - return 0; -} + struct wan_dev_le *devle; + wan_device_t* wandev = NULL; + +#ifdef CONFIG_PRODUCT_WANPIPE_ANNEXG + netdevice_t *dev; + wp_stack_stats_t wp_stats; +#endif + PROC_ADD_DECL(m); + PROC_ADD_INIT(m, buf, offs, len); + + PROC_ADD_LINE(m, stat_hdr); + devle=NULL; + WAN_LIST_FOREACH(wandev, &wan_devlist, next){ + + if (!wandev->state) continue; + +#ifdef CONFIG_PRODUCT_WANPIPE_ANNEXG + memset(&wp_stats,0,sizeof(wp_stack_stats_t)); + + if (wandev->get_active_inactive){ + WAN_LIST_FOREACH(devle, &wandev->dev_head, dev_link){ + dev = WAN_DEVLE2DEV(devle); + if (!dev) continue; + wandev->get_active_inactive(wandev,dev,&wp_stats); + } + } + + PROC_ADD_LINE(m, + + STAT_FRM, + wandev->name, + PROT_DECODE(wandev->config_id,1), + wandev->config_id == WANCONFIG_FR ? + FR_STATION_DECODE(wandev->station) : + wandev->config_id == WANCONFIG_MFR ? + FR_STATION_DECODE(wandev->station) : + wandev->config_id == WANCONFIG_ADSL ? + ADSL_STATION_DECODE(wandev->station) : + wandev->config_id == WANCONFIG_X25 ? + X25_STATION_DECODE(wandev->station) : + wandev->config_id == WANCONFIG_AFT ? + "A1/2 TE1": + wandev->config_id == WANCONFIG_AFT_TE1 ? + "A104 TE1": + wandev->config_id == WANCONFIG_AFT_TE3 ? + "A300 TE3" : + wandev->config_id == WANCONFIG_AFT_ANALOG ? + "A200 RM" : + ("N/A"), + STATE_DECODE(wandev->state), + wp_stats.fr_active,wp_stats.fr_inactive, + wp_stats.lapb_active,wp_stats.lapb_inactive, + wp_stats.x25_link_active,wp_stats.x25_link_inactive, + wp_stats.x25_active,wp_stats.x25_inactive, + wp_stats.dsp_active,wp_stats.dsp_inactive); + +#else + PROC_ADD_LINE(m, + + STAT_FRM, + wandev->name, + PROT_DECODE(wandev->config_id,1), + wandev->config_id == WANCONFIG_FR ? + FR_STATION_DECODE(wandev->station) : + wandev->config_id == WANCONFIG_MFR ? + FR_STATION_DECODE(wandev->station) : + wandev->config_id == WANCONFIG_ADSL ? + ADSL_STATION_DECODE(wandev->station) : + wandev->config_id == WANCONFIG_X25 ? + X25_STATION_DECODE(wandev->station) : + ("N/A"), + STATE_DECODE(wandev->state)); #endif + } + PROC_ADD_RET(m); +} + /* - * End + * Prepare data for reading 'Interfaces' entry. + * Return length of data. */ +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(LINUX_2_4) +STATIC int interfaces_get_info(char* buf, char** start, off_t offs, int len) +#else +#if defined(LINUX_2_6) +static int interfaces_get_info(struct seq_file *m, void *v) +#elif defined(LINUX_2_4) +static int interfaces_get_info(char* buf, char** start, off_t offs, int len) +#else +static int interfaces_get_info(char* buf, char** start, off_t offs, int len, int dummy) +#endif +#endif +{ + struct wan_dev_le *devle; + wan_device_t* wandev = NULL; + netdevice_t* dev=NULL; + PROC_ADD_DECL(m); + PROC_ADD_INIT(m, buf, offs, len); + + PROC_ADD_LINE(m, interfaces_hdr); + + WAN_LIST_FOREACH(wandev, &wan_devlist, next){ + wanpipe_common_t *dev_priv; + if (!(m->count < (m->size - 80))) break; + if (!wandev->state) continue; + WAN_LIST_FOREACH(devle, &wandev->dev_head, dev_link){ + dev = WAN_DEVLE2DEV(devle); + + if (!dev){ + continue; + } + + dev_priv = wan_netif_priv(dev); + PROC_ADD_LINE(m, + INTERFACES_FRM, + wan_netif_name(dev), wandev->name, + dev_priv->lcn, + dev_priv?STATE_DECODE(dev_priv->state):"N/A"); + + if (dev_priv->usedby == STACK){ + wanpipe_lip_get_if_status(dev_priv,m); + } + } + } + PROC_ADD_RET(m); +} + +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(LINUX_2_4) +STATIC int probe_get_info(char* buf, char** start, off_t offs, int len) +#else +#if defined(LINUX_2_6) +static int probe_get_info(struct seq_file *m, void *v) +#elif defined(LINUX_2_4) +static int probe_get_info(char* buf, char** start, off_t offs, int len) +#else +static int probe_get_info(char* buf, char** start, off_t offs, int len, int dummy) +#endif +#endif +{ + int i=0; + sdla_hw_probe_t* hw_probe; + sdla_hw_type_cnt_t *hw_cnt; + PROC_ADD_DECL(m); + PROC_ADD_INIT(m, buf, offs, len); + + PROC_ADD_LINE(m, "-------------------------------\n"); + PROC_ADD_LINE(m, "| Wanpipe Hardware Probe Info |\n"); + PROC_ADD_LINE(m, "-------------------------------\n"); + + hw_probe = (sdla_hw_probe_t *)sdla_get_hw_probe(); + + for (; + hw_probe; + hw_probe = WAN_LIST_NEXT(hw_probe, next)) { + + i++; + PROC_ADD_LINE(m, + "%-2d. %s\n", i, hw_probe->hw_info); + } + + hw_cnt=(sdla_hw_type_cnt_t*)sdla_get_hw_adptr_cnt(); + + PROC_ADD_LINE(m, + "\nCard Cnt: S508=%-2d S514X=%-2d S518=%-2d A101-2=%-2d A104=%-2d A300=%-2d A200=%-2d A108=%-2d\n", + hw_cnt->s508_adapters, + hw_cnt->s514x_adapters, + hw_cnt->s518_adapters, + hw_cnt->aft101_adapters, + hw_cnt->aft104_adapters, + hw_cnt->aft300_adapters, + hw_cnt->aft200_adapters, + hw_cnt->aft108_adapters); +#ifdef WAN_DEBUG_MEM + PROC_ADD_LINE(m, + + "Total Memory = %d\n", atomic_read(&wan_debug_mem)); +#endif + + PROC_ADD_RET(m); +} + + +/* + * Prepare data for reading entry. + * Return length of data. + * + * On entry, the 'start' argument will contain a pointer to WAN device + * data space. + */ + +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(LINUX_2_4) +STATIC int wandev_get_info(char* buf, char** start, off_t offs, int len) +#else +#if defined(LINUX_2_6) +static int wandev_get_info(struct seq_file *m, void *v) +#elif defined(LINUX_2_4) +static int wandev_get_info(char* buf, char** start, off_t offs, int len) +#else +static int wandev_get_info(char* buf, char** start, off_t offs, int len, int dummy) +#endif +#endif +{ + wan_device_t* wandev = PROC_GET_DATA(); + int rslt = 0; + PROC_ADD_DECL(m); + + if ((wandev == NULL) || (wandev->magic != ROUTER_MAGIC)) + return 0; + + PROC_ADD_INIT(m, buf, offs, len); + if (!wandev->state){ + PROC_ADD_LINE(m, + "device is not configured!\n"); + goto wandev_get_info_end; + } + + /* Update device statistics */ + if (wandev->update && !m->from){ + + rslt = wandev->update(wandev); + if(rslt) { + switch (rslt) { + case -EAGAIN: + PROC_ADD_LINE(m, + + "Device is busy!\n"); + break; + + + default: + PROC_ADD_LINE(m, + + "Device is not configured!\n"); + break; + } + goto wandev_get_info_end; + } + } + + PROC_ADD_LINE(m, + + PROC_STATS_2_FORMAT, + "total rx packets", wandev->stats.rx_packets, + "total tx packets", wandev->stats.tx_packets); + PROC_ADD_LINE(m, + + PROC_STATS_2_FORMAT, + "total rx bytes", wandev->stats.rx_bytes, + "total tx bytes", wandev->stats.tx_bytes); + PROC_ADD_LINE(m, + + PROC_STATS_2_FORMAT, + "bad rx packets", wandev->stats.rx_errors, + "packet tx problems", wandev->stats.tx_errors); + PROC_ADD_LINE(m, + + PROC_STATS_2_FORMAT, + "rx frames dropped", wandev->stats.rx_dropped, + "tx frames dropped", wandev->stats.tx_dropped); + PROC_ADD_LINE(m, + + PROC_STATS_2_FORMAT, + "multicast rx packets", wandev->stats.multicast, + "tx collisions", wandev->stats.collisions); + PROC_ADD_LINE(m, + + PROC_STATS_2_FORMAT, + "rx length errors", wandev->stats.rx_length_errors, + "rx overrun errors", wandev->stats.rx_over_errors); + PROC_ADD_LINE(m, + + PROC_STATS_2_FORMAT, + "CRC errors", wandev->stats.rx_crc_errors, + "abort frames", wandev->stats.rx_frame_errors); + PROC_ADD_LINE(m, + + PROC_STATS_2_FORMAT, + "rx fifo overrun", wandev->stats.rx_fifo_errors, + "rx missed packet", wandev->stats.rx_missed_errors); + PROC_ADD_LINE(m, + + PROC_STATS_1_FORMAT, + "aborted tx frames", wandev->stats.tx_aborted_errors); + + /* Update Front-End information (alarms, performance monitor counters */ + if (wandev->get_info){ + m->count = wandev->get_info( + wandev->private, + m, + M_STOP_CNT(m)); + } + +wandev_get_info_end: + PROC_ADD_RET(m); +} + + + +#if defined(__LINUX__) + +/* + * Initialize router proc interface. + */ + +int wanrouter_proc_init (void) +{ + struct proc_dir_entry *p; + proc_router = proc_mkdir(ROUTER_NAME, proc_net); + if (!proc_router) + goto fail; + + p = create_proc_entry("config",S_IRUGO,proc_router); + if (!p) + goto fail_config; + +#if defined(LINUX_2_6) + p->proc_fops = &config_fops; +#elif defined(LINUX_2_4) + p->proc_fops = &router_fops; + p->proc_iops = &router_inode; + p->get_info = config_get_info; +#else + p->ops = &router_inode; + p->nlink = 1; + p->get_info = config_get_info; +#endif + + p = create_proc_entry("status",S_IRUGO,proc_router); + if (!p) + goto fail_stat; + +#if defined(LINUX_2_6) + p->proc_fops = &status_fops; +#elif defined(LINUX_2_4) + p->proc_fops = &router_fops; + p->proc_iops = &router_inode; + p->get_info = status_get_info; +#else + p->ops = &router_inode; + p->nlink = 1; + p->get_info = status_get_info; +#endif + + p = create_proc_entry("hwprobe",0,proc_router); + if (!p) + goto fail_probe; + +#if defined(LINUX_2_6) + p->proc_fops = &wp_hwprobe_fops; +#elif defined(LINUX_2_4) + p->proc_fops = &router_fops; + p->proc_iops = &router_inode; + p->get_info = probe_get_info; +#else + p->ops = &router_inode; + p->nlink = 1; + p->get_info = probe_get_info; +#endif + + p = create_proc_entry("map",0,proc_router); + if (!p) + goto fail_map; + +#if defined(LINUX_2_6) + p->proc_fops = &wp_map_fops; +#elif defined(LINUX_2_4) + p->proc_fops = &router_fops; + p->proc_iops = &router_inode; + p->get_info = map_get_info; +#else + p->ops = &router_inode; + p->nlink = 1; + p->get_info = map_get_info; +#endif + + p = create_proc_entry("interfaces",0,proc_router); + if (!p) + goto fail_interfaces; + +#if defined(LINUX_2_6) + p->proc_fops = &wp_iface_fops; +#elif defined(LINUX_2_4) + p->proc_fops = &router_fops; + p->proc_iops = &router_inode; + p->get_info = interfaces_get_info; +#else + p->ops = &router_inode; + p->nlink = 1; + p->get_info = interfaces_get_info; +#endif + + map_dir = proc_mkdir("dev_map", proc_router); + if (!map_dir) + goto fail_dev_map; + + /* Initialize protocol proc fs. */ + proc_router_chdlc.count = 0; + proc_router_chdlc.protocol_entry = NULL; + proc_router_fr.count = 0; + proc_router_fr.protocol_entry = NULL; + proc_router_ppp.count = 0; + proc_router_ppp.protocol_entry = NULL; + proc_router_x25.count = 0; + proc_router_x25.protocol_entry = NULL; + proc_router_mppp.count = 0; + proc_router_mppp.protocol_entry = NULL; + return 0; + +fail_dev_map: + remove_proc_entry("interfaces", proc_router); +fail_interfaces: + remove_proc_entry("map", proc_router); +fail_map: + remove_proc_entry("hwprobe", proc_router); +fail_probe: + remove_proc_entry("status", proc_router); +fail_stat: + remove_proc_entry("config", proc_router); +fail_config: + remove_proc_entry(ROUTER_NAME, proc_net); +fail: + return -ENOMEM; +} + +int wanrouter_proc_usage_check(void) +{ + if (proc_router){ + return atomic_read(&proc_router->count); + } + return 0; +} + +/* + * Clean up router proc interface. + */ +void wanrouter_proc_cleanup (void) +{ + remove_proc_entry("config", proc_router); + remove_proc_entry("status", proc_router); + remove_proc_entry("hwprobe", proc_router); + remove_proc_entry("map", proc_router); + remove_proc_entry("interfaces", proc_router); + remove_proc_entry("dev_map",proc_router); + remove_proc_entry(ROUTER_NAME,proc_net); +} + +/* + * Add directory entry for WAN device. + */ + +int wanrouter_proc_add (wan_device_t* wandev) +{ + int err=0; + struct proc_dir_entry *p; + + spin_lock_init(&wandev->get_map_lock); + + if (wandev->magic != ROUTER_MAGIC) + return -EINVAL; + + + wandev->dent = create_proc_entry(wandev->name, S_IRUGO, proc_router); + if (!wandev->dent) + return -ENOMEM; + +#if defined(LINUX_2_6) + wandev->dent->proc_fops = &wandev_fops; +#elif defined(LINUX_2_4) + wandev->dent->proc_fops = &wandev_fops; + wandev->dent->proc_iops = &router_inode; + wandev->dent->get_info = wandev_get_info; +#else + wandev->dent->ops = &wandev_inode; + wandev->dent->nlink = 1; + wandev->dent->get_info = wandev_get_info; +#endif + wandev->dent->data = wandev; + + p=create_proc_entry(wandev->name, 0, map_dir); + if (!p){ + remove_proc_entry(wandev->name, proc_router); + wandev->dent=NULL; + return -ENOMEM; + } + +#if defined(LINUX_2_6) + //FIXME: ADD THE FOPS HERE + p->proc_fops = &wandev_mapdir_fops; +#elif defined(LINUX_2_4) + p->proc_fops = &wandev_fops; + p->proc_iops = &router_inode; + p->get_info = wandev_mapdir_get_info; +#else + p->ops = &wandev_inode; + p->nlink = 1; + p->get_info = wandev_mapdir_get_info; +#endif + p->data = wandev; + + + return err; +} + +/* + * Delete directory entry for WAN device. + */ + +int wanrouter_proc_delete(wan_device_t* wandev) +{ + if (wandev->magic != ROUTER_MAGIC) + return -EINVAL; + + remove_proc_entry(wandev->name, proc_router); + remove_proc_entry(wandev->name, map_dir); + return 0; +} +/* + * Add directory entry for Protocol. + */ + +int wanrouter_proc_add_protocol(wan_device_t* wandev) +{ + struct proc_dir_entry* p = NULL; + //struct proc_dir_entry** proc_protocol; + wan_proc_entry_t* proc_protocol; + + if (wandev->magic != ROUTER_MAGIC) + return -EINVAL; + + switch(wandev->config_id){ + case WANCONFIG_FR: + case WANCONFIG_MFR: + proc_protocol = &proc_router_fr; + break; + + case WANCONFIG_CHDLC: + proc_protocol = &proc_router_chdlc; + break; + + case WANCONFIG_PPP: + proc_protocol = &proc_router_ppp; + break; + + case WANCONFIG_X25: + proc_protocol = &proc_router_x25; + break; + + case WANCONFIG_MPPP: + proc_protocol = &proc_router_mppp; + break; + + default: + proc_protocol = NULL; + return 0; + } + + if (proc_protocol->protocol_entry == NULL){ + + proc_protocol->count=0; + + /* Create /proc/net/wanrouter/ directory */ + proc_protocol->protocol_entry = + proc_mkdir(PROT_DECODE(wandev->config_id,0), proc_router); + + if (!proc_protocol->protocol_entry) + goto fail; + + /* Create /proc/net/wanrouter//config directory */ + p = create_proc_entry("config",0,proc_protocol->protocol_entry); + if (!p) + goto fail_config; + +#if defined(LINUX_2_6) + p->proc_fops = &wp_get_dev_config_fops; + +#elif defined(LINUX_2_4) + p->proc_fops = &router_fops; + p->proc_iops = &router_inode; + p->get_info = get_dev_config_info; +#else + + p->ops = &router_inode; + p->nlink = 1; + p->get_info = get_dev_config_info; +#endif + p->data = (void*)wandev->config_id; + + /* Create /proc/net/wanrouter//status directory */ + p = create_proc_entry("status",0,proc_protocol->protocol_entry); + if (!p) + goto fail_stat; + +#if defined(LINUX_2_6) + p->proc_fops = &wp_get_dev_status_fops; + +#elif defined(LINUX_2_4) + p->proc_fops = &router_fops; + p->proc_iops = &router_inode; + p->get_info = get_dev_status_info; +#else + p->ops = &router_inode; + p->nlink = 1; + p->get_info = get_dev_status_info; +#endif + p->data = (void*)wandev->config_id; + } + + /* Create /proc/net/wanrouter// directory */ + wandev->link = proc_mkdir(wandev->name, proc_protocol->protocol_entry); + if (!wandev->link) + goto fail_link; + + /* Create /proc/net/wanrouter//config directory */ + p = create_proc_entry("config",0,wandev->link); + if (!p) + goto fail_link_config; + +#if defined(LINUX_2_6) + p->proc_fops = NULL; //&wp_prot_dev_config_fops; +#elif defined(LINUX_2_4) + p->proc_fops = &router_fops; + p->proc_iops = &router_inode; + p->get_info = wandev->get_dev_config_info; + p->write_proc = wandev->set_dev_config; +#else + p->ops = &router_inode; + p->nlink = 1; + p->get_info = wandev->get_dev_config_info; + p->write_proc = wandev->set_dev_config; +#endif + p->data = wandev; + + proc_protocol->count ++; + return 0; + +fail_link_config: + remove_proc_entry(wandev->name, proc_protocol->protocol_entry); +fail_link: + if (proc_protocol->count){ + /* Do not remove /proc/net/wanrouter/... because + * another device is still using this entry. + */ + return -ENOMEM; + } + remove_proc_entry("status", proc_protocol->protocol_entry); + return -ENOMEM; + +fail_stat: + remove_proc_entry("config", proc_protocol->protocol_entry); +fail_config: + remove_proc_entry(PROT_DECODE(wandev->config_id,0), proc_router); + proc_protocol->protocol_entry = NULL; +fail: + return -ENOMEM; +} + +/* + * Delete directory entry for Protocol. + */ + +int wanrouter_proc_delete_protocol(wan_device_t* wandev) +{ + wan_proc_entry_t* proc_protocol = NULL; + + if (wandev->magic != ROUTER_MAGIC) + return -EINVAL; + + switch(wandev->config_id){ + case WANCONFIG_FR: + case WANCONFIG_MFR: + proc_protocol = &proc_router_fr; + break; + + case WANCONFIG_CHDLC: + proc_protocol = &proc_router_chdlc; + break; + + case WANCONFIG_PPP: + proc_protocol = &proc_router_ppp; + break; + + case WANCONFIG_X25: + proc_protocol = &proc_router_x25; + break; + + case WANCONFIG_MPPP: + proc_protocol = &proc_router_mppp; + break; + + default: + proc_protocol = NULL; + return 0; + break; + } + + remove_proc_entry("config", wandev->link); + remove_proc_entry(wandev->name, proc_protocol->protocol_entry); + proc_protocol->count --; + if (!proc_protocol->count){ + remove_proc_entry("config", proc_protocol->protocol_entry); + remove_proc_entry("status", proc_protocol->protocol_entry); + remove_proc_entry(PROT_DECODE(wandev->config_id,0), proc_router); + proc_protocol->protocol_entry = NULL; + } + return 0; +} + +/* + * Add directory entry for interface. + */ + +int wanrouter_proc_add_interface(wan_device_t* wandev, + struct proc_dir_entry** dent, + char* if_name, + void* priv) +{ + +#if 0 + if (wandev->magic != ROUTER_MAGIC) + return -EINVAL; + if (wandev->link == NULL || wandev->get_if_info == NULL) + return -ENODEV; + + *dent = create_proc_entry(if_name, 0, wandev->link); + if (!*dent) + return -ENOMEM; +#ifdef LINUX_2_4 + (*dent)->proc_fops = &router_fops; + (*dent)->proc_iops = &router_inode; +#else + (*dent)->ops = &router_inode; + (*dent)->nlink = 1; +#endif + (*dent)->get_info = wandev->get_if_info; + (*dent)->write_proc = wandev->set_if_info; + (*dent)->data = priv; +#endif + return 0; +} + +/* + * Delete directory entry for interface. + */ + +int wanrouter_proc_delete_interface(wan_device_t* wandev, char* if_name) +{ +#if 0 + if (wandev->magic != ROUTER_MAGIC) + return -EINVAL; + if (wandev->link == NULL) + return -ENODEV; + + remove_proc_entry(if_name, wandev->link); +#endif + return 0; +} + +/****** Proc filesystem entry points ****************************************/ + +/* + * Verify access rights. + */ + +#ifndef LINUX_2_6 +static int router_proc_perms (struct inode* inode, int op) +{ + return 0; +} + +/* + * Read router proc directory entry. + * This is universal routine for reading all entries in /proc/net/wanrouter + * directory. Each directory entry contains a pointer to the 'method' for + * preparing data for that entry. + * o verify arguments + * o allocate kernel buffer + * o call get_info() to prepare data + * o copy data to user space + * o release kernel buffer + * + * Return: number of bytes copied to user space (0, if no data) + * <0 error + */ + +static ssize_t router_proc_read(struct file* file, char* buf, size_t count, + loff_t *ppos) +{ + struct inode *inode = file->f_dentry->d_inode; + struct proc_dir_entry* dent; + char* page; + int len; + + if (count <= 0) + return 0; + + dent = inode->u.generic_ip; + if ((dent == NULL) || (dent->get_info == NULL)) + return 0; + + page = wan_malloc(count); + if (page == NULL) + return -ENOBUFS; +#ifdef LINUX_2_4 + len = dent->get_info(page, dent->data, file->f_pos, count); +#else + len = dent->get_info(page, dent->data, file->f_pos, count, 0); +#endif + if (len) { + if(copy_to_user(buf, page, len)){ + DEBUG_SUB_MEM(count); + wan_free(page); + return -EFAULT; + } + file->f_pos += len; + } + wan_free(page); + return len; +} + +/* + * Write router proc directory entry. + * This is universal routine for writing all entries in /proc/net/wanrouter + * directory. Each directory entry contains a pointer to the 'method' for + * preparing data for that entry. + * o verify arguments + * o allocate kernel buffer + * o copy data from user space + * o call write_info() + * o release kernel buffer + * + * Return: number of bytes copied to user space (0, if no data) + * <0 error + */ +static ssize_t router_proc_write (struct file *file, const char *buf, size_t count, + loff_t *ppos) +{ + struct inode* inode = file->f_dentry->d_inode; + struct proc_dir_entry* dent = NULL; + char* page = NULL; +#ifdef WAN_DEBUG_MEM + unsigned int ocount=count; +#endif + + if (count <= 0) + return 0; + + dent = inode->u.generic_ip; + if ((dent == NULL) || (dent->write_proc == NULL)) + return count; + + page = wan_malloc(count); + if (page == NULL) + return -ENOBUFS; + if (copy_from_user(page, buf, count)){ + DEBUG_SUB_MEM(count); + wan_free(page); + return -EINVAL; + } + page[count-1] = '\0'; + + /* Add supporting Write to proc fs */ + count = dent->write_proc(file, page, count, dent->data); + + DEBUG_SUB_MEM(ocount); + wan_free(page); + return count; +} + +#endif + + +/* + * Prepare data for reading 'MAP' entry. + * Return length of data. + */ + +#if defined(LINUX_2_6) +static int map_get_info(struct seq_file *m, void *v) +#elif defined(LINUX_2_4) +static int map_get_info(char* buf, char** start, off_t offs, int len) +#else +static int map_get_info(char* buf, char** start, off_t offs, int len, int dummy) +#endif +{ + wan_device_t* wandev = NULL; + struct wan_dev_le *devle; + netdevice_t* dev=NULL; + + PROC_ADD_DECL(m); + PROC_ADD_INIT(m, buf, offs, len); + + PROC_ADD_LINE(m, map_hdr); + WAN_LIST_FOREACH(wandev, &wan_devlist, next){ + + if (!wandev->state){ + continue; + } + if (!wandev->get_map){ + continue; + } + + spin_lock(&wandev->get_map_lock); + WAN_LIST_FOREACH(devle, &wandev->dev_head, dev_link){ + dev = WAN_DEVLE2DEV(devle); + if (!dev) continue; + if (!(dev->flags&IFF_UP)){ + continue; + } + m->count = wandev->get_map(wandev, dev, m, M_STOP_CNT(m)); + } + spin_unlock(&wandev->get_map_lock); + } + + PROC_ADD_RET(m); +} + + + +/* + * Prepare data for reading FR 'Config' entry. + * Return length of data. + */ +#if defined(LINUX_2_6) +static int get_dev_config_info(struct seq_file *m, void *v) +#elif defined(LINUX_2_4) +static int get_dev_config_info(char* buf, char** start, off_t offs, int len) +#else +static int get_dev_config_info(char* buf, char** start, off_t offs, int len,int dummy) +#endif +{ + wan_device_t* wandev = NULL; + netdevice_t* dev = NULL; + struct wan_dev_le *devle; + PROC_ADD_DECL(m); + PROC_ADD_INIT(m, buf, offs, len); + + WAN_LIST_FOREACH(wandev, &wan_devlist, next){ + if (!(m->count < (PROC_BUFSZ - 80))) break; + if (!wandev->get_config_info) + continue; + +#ifndef LINUX_2_6 + if ((wandev->config_id != (unsigned)start) || !wandev->state) + continue; +#else + if (!wandev->state) + continue; +#endif + + WAN_LIST_FOREACH(devle, &wandev->dev_head, dev_link){ + dev = WAN_DEVLE2DEV(devle); + if (!dev) continue; + m->count = wandev->get_config_info(dev->priv, + m, + M_STOP_CNT(m)); + } + } + + PROC_ADD_RET(m); +} + +/* + * Prepare data for reading FR 'Status' entry. + * Return length of data. + */ + +#if defined(LINUX_2_6) +static int get_dev_status_info(struct seq_file *m, void *v) +#elif defined(LINUX_2_4) +static int get_dev_status_info(char* buf, char** start, off_t offs, int len) +#else +static int get_dev_status_info(char* buf, char** start, off_t offs, int len, int dummy) +#endif +{ + wan_device_t* wandev = NULL; + struct wan_dev_le *devle; + netdevice_t* dev = NULL; + int cnt = 0; + PROC_ADD_DECL(m); + + PROC_ADD_INIT(m, buf, offs, len); + + WAN_LIST_FOREACH(wandev, &wan_devlist, next){ + if (!(cnt < (PROC_BUFSZ - 80))) break; + + if (!wandev->get_status_info) + continue; + +#ifndef LINUX_2_6 + if ((wandev->config_id != (unsigned)start) || !wandev->state) + continue; +#else + if (!wandev->state) + continue; +#endif + + WAN_LIST_FOREACH(devle, &wandev->dev_head, dev_link){ + dev = WAN_DEVLE2DEV(devle); + if (!dev) continue; + m->count = wandev->get_status_info(dev->priv, m, M_STOP_CNT(m)); + } + } + + PROC_ADD_RET(m); +} + + +#if defined(LINUX_2_6) +static int wandev_mapdir_get_info(struct seq_file *m, void *v) +#elif defined(LINUX_2_4) +static int wandev_mapdir_get_info(char* buf, char** start, off_t offs, int len) +#else +static int wandev_mapdir_get_info(char* buf, char** start, off_t offs, int len, int dummy) +#endif +{ + wan_device_t* wandev = PROC_GET_DATA(); + struct wan_dev_le *devle; + netdevice_t* dev = NULL; + PROC_ADD_DECL(m); + + if (!wandev){ + return -ENODEV; + } + + PROC_ADD_INIT(m, buf, offs, len); + + PROC_ADD_LINE(m, map_hdr); + + if (!wandev->state){ + goto wandev_mapdir_get_info_exit; + } + if (!wandev->get_map){ + goto wandev_mapdir_get_info_exit; + } + + spin_lock(&wandev->get_map_lock); + WAN_LIST_FOREACH(devle, &wandev->dev_head, dev_link){ + dev = WAN_DEVLE2DEV(devle); + if (!dev) continue; + + if (!wandev->get_map || !(dev->flags&IFF_UP)){ + continue; + } + m->count = wandev->get_map(wandev, dev, m, M_STOP_CNT(m)); + } + spin_unlock(&wandev->get_map_lock); + +wandev_mapdir_get_info_exit: + PROC_ADD_RET(m); +} + + + +#endif /* __LINUX__ */ + +#else + +/* + * No /proc - output stubs + */ + +int wanrouter_proc_init(void) +{ + return 0; +} + +void wanrouter_proc_cleanup(void) +{ + return; +} + +int wanrouter_proc_add(wan_device_t *wandev) +{ + return 0; +} + +int wanrouter_proc_delete(wan_device_t *wandev) +{ + return 0; +} + +int wanrouter_proc_add_protocol(wan_device_t *wandev) +{ + return 0; +} + +int wanrouter_proc_delete_protocol(wan_device_t *wandev) +{ + return 0; +} + +int wanrouter_proc_add_interface(wan_device_t* wandev, + struct proc_dir_entry** dent, + char* if_name, + void* priv) +{ + return 0; +} + +int wanrouter_proc_delete_interface(wan_device_t* wandev, char* if_name) +{ + return 0; +} + +#endif + +/*============================================================================ + * Write WAN device ???. + * o Find WAN device associated with this node + */ +#ifdef LINUX_2_0 +static int device_write( + struct inode* inode, struct file* file, const char* buf, int count) +{ + int err = verify_area(VERIFY_READ, buf, count); + struct proc_dir_entry* dent; + wan_device_t* wandev; + + if (err) return err; + + dent = inode->u.generic_ip; + if ((dent == NULL) || (dent->data == NULL)) + return -ENODATA; + + wandev = dent->data; + + DEBUG_TEST("%s: writing %d bytes to %s...\n", + name_root, count, dent->name); + + return 0; +} +#endif + + + #if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) +int proc_add_line(struct seq_file* m, char* frm, ...) +{ + char tmp[400]; + int ret = PROC_BUF_CONT; + int size = 0; + va_list arg; + + va_start(arg, frm); + if (m->count && m->stop_cnt){ + va_end(arg); + return PROC_BUF_EXIT; + } + size = vsprintf(tmp, frm, arg); + if (m->stop_cnt){ + if (m->stop_cnt < size){ + DEBUG_EVENT("!!! Error in writting in proc buffer !!!\n"); + m->stop_cnt = size; + } + m->stop_cnt -= size; + }else{ + if (size < m->size - m->count){ + /*vsprintf(&m->buf[m->count], frm, arg);*/ + memcpy(&m->buf[m->count], tmp, size); + m->count += size; + /* *cnt += vsprintf(&buf[*cnt], frm, arg); */ + }else{ + m->stop_cnt = m->from + m->count; + ret = PROC_BUF_EXIT; + } + } + va_end(arg); + return ret; +} +#endif + + +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) +#else +int proc_add_line(struct seq_file* m, char* frm, ...) +{ +#if defined(LINUX_2_6) + return 0; +#else + char tmp[400]; + int ret = PROC_BUF_CONT; + int size = 0; + va_list arg; + + va_start(arg, frm); + if (m->count && m->stop_cnt){ + va_end(arg); + return PROC_BUF_EXIT; + } + size = vsprintf(tmp, frm, arg); + if (m->stop_cnt){ + if (m->stop_cnt < size){ + DEBUG_EVENT("!!! Error in writting in proc buffer !!!\n"); + m->stop_cnt = size; + } + m->stop_cnt -= size; + }else{ + if (size < m->size - m->count){ + /*vsprintf(&m->buf[m->count], frm, arg);*/ + memcpy(&m->buf[m->count], tmp, size); + m->count += size; + /* *cnt += vsprintf(&buf[*cnt], frm, arg); */ + }else{ + m->stop_cnt = m->from + m->count; + ret = PROC_BUF_EXIT; + } + } + va_end(arg); + return ret; +#endif +} +#endif +/* + * End + */